Hosts
Which tokens can be infected, the eight eligibility checks, host statuses, Pons pair approval and the depth limit.
§What a host is
A host is the token a virus trades against. In Pons terms, it is the virus's pairToken: the asset the virus's bonding curve accepts on buys, pays out on sells, and is paired with in the graduated Uniswap V4 pool. Every fee a virus generates is denominated in its host, and every burn VIRUS performs for that virus reduces the host's supply.
A host is fixed at launch. Pons records pairToken in the launch record, the feeder stores host in its immutable clone arguments, and VirusRegistry writes the virus's host once. Nothing can change it afterwards.
§Only Pons V2 launch tokens can be hosts
The purpose of a virus is to burn its host. VIRUS therefore needs a host whose burn(uint256) really destroys tokens and reduces totalSupply.
Pons V2 launch tokens (PonsV2LauncherToken) are ERC20 + ERC20Burnable from OpenZeppelin. Their burn calls _burn, which reduces totalSupply (VERIFIED_PONS, published source). That is the property VIRUS relies on, and it is asserted at run time: every feed() compares the host's totalSupply before and after the burn and reverts with BurnNotReflected unless it fell by exactly the burned amount.
Pons can also approve assets that are not launch tokens as pair tokens, such as tokenized stocks, stablecoins or cbBTC. VIRUS never accepts these as hosts, even when Pons has approved them (VIRUS_ADAPTATION A17). VIRUS has no guarantee that such a token exposes a burn that reduces supply, and a host that could not be burned would break the core promise.
§Eligibility checks A–H
The coordinator's hostCheck(address host) runs the on-chain checks. The app's host resolver (packages/chain/src/hosts.ts) runs the same checks, labels them A–H, and adds two that exist only in the app (C and D). When the VIRUS coordinator is deployed, the app calls hostCheck directly. Without it (LAB MODE), the app performs the same reads against Pons; check G then needs a registry to read.
| Check | Name | What is read | Passes when | Where enforced |
|---|---|---|---|---|
| A | Contract | host.code.length |
The address has code | hostCheck.isContract |
| B | Pons launch token and provenance | factory.getLaunchedToken(host), host.launchFactory(), host.curve() |
A Pons launch record exists with exists == true and token == host, and host.launchFactory() equals the Pons factory, and host.curve() equals the curve in the launch record |
hostCheck.ponsLaunchToken and hostCheck.provenance |
| C | Behaves as ERC-20 | decimals(), symbol() |
Both reads succeed | App only |
| D | Burnable | Derived | B passes (Pons launch tokens are ERC20Burnable) |
App only; burns are enforced at feed time by BurnNotReflected |
| E | Pons pair approval | factory.approvedPairTokens(host) |
true |
hostCheck.pairApproved; Pons re-checks it inside launchToken |
| F | Usable pair economics | factory.pairTokenEconomics(host) → (phantomQuote, graduationThreshold, decimals), and host.decimals() |
phantomQuote > 0, graduationThreshold > 0, decimals == 18, and the token's own decimals() == 18 |
hostCheck.economicsUsable |
| G | Not disabled | registry.hostDisabled(host) |
false |
hostCheck.notDisabled; registerVirus re-checks it |
| H | Depth | Walk of Pons pairToken links |
The virus would have depth ≤ 3, and the walk ends within its bound | hostCheck.depthOk; registerVirus re-checks depth ≤ 3 |
On chain, a host is viable only when every check passes:
viable = ponsLaunchToken && provenance && pairApproved
&& economicsUsable && notDisabled && depthOk;
hostCheck returns early with every flag false if the address has no code. inoculate reverts with HostNotViable(host) when viable is false.
The full return value is:
struct HostCheck {
bool isContract;
bool ponsLaunchToken;
bool provenance;
bool pairApproved;
bool economicsUsable;
bool notDisabled;
bool depthOk;
bool viable;
uint8 hostDepth;
uint8 childDepth;
uint8 decimals;
address ponsCurve;
address ponsPairToken;
uint256 phantomQuote;
uint256 graduationThreshold;
}
§Host statuses
The app turns the checks into one status per address. Statuses are evaluated in this order, and the first match wins:
| Order | Status | Condition | INOCULATE |
|---|---|---|---|
| 1 | NO SPECIMEN |
No contract at the address (A fails) | Disabled |
| 2 | DISABLED |
The VIRUS admin disabled the host for new launches (G fails) | Disabled |
| 3 | DETECTED |
A contract, but not a Pons V2 launch token with verified provenance, or not a working ERC-20 (B, C or D fails) | Disabled |
| 4 | PONS PAIR APPROVAL REQUIRED |
A valid Pons launch token that Pons has not approved as a pair token (E fails) | Disabled |
| 5 | APPROVED |
Pons-approved, but a VIRUS-side check fails: pair economics unusable (F) or the virus would be deeper than 3 (H) | Disabled |
| 6 | VIABLE |
Every check passes | Enabled, subject to the launch gate |
A VIABLE host can still be blocked by the launch gate: Pons canLaunch for you and for the coordinator, VIRUS launchesPaused, and an enabled Pons launch config. See Launching.
The app also shows the reason for each failing check, for example "NOT A PONS V2 LAUNCH TOKEN — VIRUS CANNOT BURN IT", "PAIRING NOT YET APPROVED BY PONS", "PONS PAIR ECONOMICS UNUSABLE FOR A HOST", "DISABLED FOR NEW INFECTIONS", or "CHILD WOULD BE DEPTH 4 (MAX 3)".
§Pons must approve every host
A Pons launch can only use a pair token the Pons owner has approved. Approval is two owner-only Pons calls (BLOCKED_BY_PONS B1, VERIFIED_PONS F3):
setPairTokenApproved(token, true), which setsapprovedPairTokens(token). Pons requires the token to have code, stored economics, and a matchingdecimals().setPairTokenEconomics(token, ...), which storespairTokenEconomics(token): the phantom quote reserve, the graduation threshold and the decimals, all in the pair token's own units.
VIRUS cannot approve anything and never submits an approval request on anyone's behalf. A valid Pons launch token that Pons has not approved is shown as SPECIMEN FOUND — PAIRING NOT YET APPROVED BY PONS, with INOCULATE disabled.
This is the largest external dependency of the protocol. If Pons approves no launch tokens as pair tokens, VIRUS has zero viable hosts. Whether Pons will do so is an open question recorded in the reference audit.
Pair economics matter beyond eligibility. For a launch paired with a custom token, Pons uses the pair token's phantomQuote and graduationThreshold from pairTokenEconomics, not the ETH-denominated figures in the launch config (VERIFIED_PONS F4). A virus's graduation threshold is therefore measured in host tokens and is set by Pons per host.
§Depth
Depth measures how many VIRUS layers sit between a token and its root market.
depth(token) = 0 if its Pons pairToken is ETH or a non-Pons asset
depth(token) = depth(pairToken) + 1 otherwise
child depth = host depth + 1 must be ≤ 3
| Depth | Example (illustrative tickers) | Can it host? |
|---|---|---|
| 0 | $DOG, a Pons launch paired with ETH | Yes, if Pons approves it. Its viruses have depth 1. |
| 1 | $FLU, a virus of $DOG | Yes, if Pons approves $FLU as a pair token. Its viruses have depth 2. |
| 2 | A virus of $FLU | Yes, if Pons approves it. Its viruses have depth 3. |
| 3 | A virus of a depth-2 virus | No. A child would have depth 4. |
The coordinator computes depth by walking getLaunchedToken(t).pairToken upward, at most MAX_DEPTH + 1 = 4 steps. If the chain is longer than that, the walk reports itself unbounded and depthOk is false. registerVirus independently rejects a depth of 0 (InvalidDepth) or above 3 (DepthExceeded).
A depth-0 host is not necessarily paired with ETH. A Pons launch paired with a non-Pons approved asset (a stablecoin, for example) also has depth 0, and its infection route begins with a leg outside Pons. See Infection routes.
§Viruses as hosts
Parasite allows parasites to host parasites, up to three deep (VERIFIED_PARASITE P7). VIRUS keeps the same maximum, enforced on chain. Recursion happens only where Pons has approved the virus itself as a pair token, because a virus is just another Pons launch token as far as Pons is concerned. Each virus that becomes a host goes through the same checks A–H.
§No warm-up phase
The VIRUS product brief describes a price-observation warm-up before a Parasite host becomes usable. That description is UNVERIFIED (brief only, not confirmed from Parasite's own pages). VIRUS deliberately does not reproduce it (VIRUS_ADAPTATION A6):
- Pons bonding curves and hooked pools price trades from their own reserves. Nothing in a VIRUS launch reads an external price, so there is nothing to observe.
- VIRUS does not fake an oracle or a waiting period that does not protect anything.
- The gate that does exist is Pons pair approval plus the VIRUS checks above. A host becomes usable the moment both hold.
§Disabled hosts
The VIRUS admin can call setHostDisabled(host, true) on VirusRegistry. A disabled host:
- shows as
DISABLEDand fails check G, soinoculatereverts, andregisterViruswould also revert withHostIsDisabled(host); - keeps every existing virus exactly as it was. Their feeders continue to feed, burn and pay the developer. Disabling affects new launches only.
The flag is reversible with setHostDisabled(host, false). Both calls emit HostDisabled(host, disabled).
§The host record
VirusRegistry registers a host automatically when its first virus is registered, and emits HostRegistered(host, depth, ponsCurve, ponsPairToken). The record never changes except through accumulating totals and the disabled flag:
| Field | Meaning |
|---|---|
registered, registeredAt |
Set on the first virus. |
depth |
Fixed at first registration. A later registration that implies a different depth reverts with HostMismatch. |
disabled |
Admin flag for new launches. |
children |
Number of registered viruses. |
ponsCurve, ponsPairToken |
The host's own Pons provenance. |
totalControlledFees |
Host tokens fed by all its viruses' feeders. |
totalBurned |
Host tokens burned. The host register ranks hosts by this figure. |
totalDevBooked, totalTreasury |
Developer and treasury shares, cumulative. |
totalInoculationFees |
2.5% first-buy fees paid in this host. |
Read it with registry.getHost(host). Candidate hosts are discovered from Pons PairTokenApprovalUpdated and TokenLaunched logs, and from VirusRegistry HostRegistered.