Every VIRUS contract function, event, error and struct with exact signatures and access, plus the Pons functions VIRUS calls.
§Conventions
- Solidity
0.8.30, EVM cancun, OpenZeppelin 5.x (SafeERC20, ReentrancyGuard, Ownable2Step, Clones).
- No upgradeability. The only proxies are the immutable EIP-1167 feeder clones.
- "Access" names who may call a function successfully. "Anyone" means no restriction.
- Errors inherited from OpenZeppelin (for example
OwnableUnauthorizedAccount(address), ReentrancyGuardReentrantCall(), SafeERC20FailedOperation(address)) can also surface and are not repeated per contract.
§VirusLaunchCoordinator
Launches a virus on Pons V2 in one transaction: host checks, live economics, a unique feeder, the Pons launch with that feeder as creator fee recipient, post-launch verification, binding, registration, and an optional first buy carrying the 2.5% inoculation fee. It has no admin, no receive function and no trade function, and holds no ETH or tokens between transactions.
§Functions
constructor(IPonsV2LaunchFactory ponsFactory_, IVirusRegistry registry_, VirusFeederFactory feederFactory_);
function inoculate(InoculateParams calldata p)
external payable returns (address virus, address curve, address feeder);
function hostCheck(address host) public view returns (HostCheck memory c);
function previewEconomics(uint256 launchConfigId) public view returns (EconomicsPreview memory e);
function previewInoculation(address caller, address host, uint256 launchConfigId, uint256 firstBuy)
external view returns (InoculationPreview memory pv);
function predictFeeder(address developer, bytes32 userSalt, address host) external view returns (address);
function ponsFactory() external view returns (IPonsV2LaunchFactory); // immutable
function registry() external view returns (IVirusRegistry); // immutable
function feederFactory() external view returns (VirusFeederFactory); // immutable
| Function |
Access |
Notes |
constructor |
Deployer |
Reverts WiringMismatch if feederFactory_.registry() != registry_ or the Pons factory has no code. |
inoculate |
Anyone who passes the Pons gate |
payable, nonReentrant. msg.value must equal ponsFactory.launchFee(). See Launching. |
hostCheck |
View |
Runs checks A, B, E, F, G, H. viable is true only if all pass. |
previewEconomics |
View |
Live config and live currentFeePolicy(), the computed creator tax, both phase fee rows, parity, launch fee. |
previewInoculation |
View |
Everything the confirmation screen shows for caller, in one call. |
predictFeeder |
View |
Feeder address for (developer, userSalt, host) under the current treasury. |
§Structs
struct Metadata {
string name;
string symbol;
string logo;
string description;
IPonsV2LaunchFactory.Socials socials; // twitter, telegram, discord, website, farcaster
}
struct InoculateParams {
address host;
uint256 launchConfigId;
bytes32 expectedPonsEconomics;
uint16 expectedCreatorTaxBps;
bytes32 salt;
uint256 firstBuy;
uint256 minVirusOut;
uint256 deadline;
Metadata meta;
}
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;
}
struct EconomicsPreview {
uint256 launchConfigId;
bool configEnabled;
uint256 supply;
uint256 curveFeeBps;
uint256 hookFeeBps;
uint256 protocolShareBps;
uint256 creatorTaxBps;
uint256 maxCreatorTaxBps;
bool taxWithinCap;
VirusEconomics.PhaseFees curvePhase;
VirusEconomics.PhaseFees poolPhase;
bool parityExact;
uint256 launchFeeWei;
}
struct InoculationPreview {
HostCheck host;
EconomicsPreview economics;
bytes32 ponsEconomicsDigest;
uint256 firstBuy;
uint256 inoculationFee;
uint256 totalHostRequired;
uint256 estimatedVirusOut;
bool callerCanLaunch;
bool coordinatorCanLaunch;
bool launchesPaused;
bool canInoculate;
}
§Events
| Event |
Fields |
Inoculated |
address indexed virus, address indexed host, address indexed developer, address feeder, address curve, uint16 creatorTaxBps, bytes32 ponsEconomics |
FirstInfection |
address indexed virus, address indexed developer, uint256 firstBuy, uint256 inoculationFee, uint256 virusOut, uint256 hostRefund |
In FirstInfection, firstBuy is the host actually spent after any partial fill, and hostRefund is the unspent host plus the unearned part of the fee.
§Errors
| Error |
Raised when |
Expired() |
block.timestamp > deadline |
LaunchesPaused() |
VIRUS launches are paused in the registry |
CallerCannotLaunch() |
ponsFactory.canLaunch(msg.sender) is false |
CoordinatorCannotLaunch() |
ponsFactory.canLaunch(coordinator) is false |
EconomicsNotPinned() |
expectedPonsEconomics is zero |
ZeroSlippageBound() |
firstBuy > 0 and minVirusOut == 0 |
WrongLaunchFee(uint256 sent, uint256 required) |
msg.value != launchFee() |
HostNotViable(address host) |
hostCheck(host).viable is false |
ConfigDisabled(uint256 launchConfigId) |
The Pons launch config is not enabled |
CreatorTaxUnreachable(uint256 required, uint256 cap) |
The tax exceeds maxCreatorTaxBps, does not fit uint16, or breaks a 2,000bps combined ceiling. Reports the tax and maxCreatorTaxBps in every case. |
CreatorTaxMismatch(uint256 expected, uint256 actual) |
The live tax differs from expectedCreatorTaxBps |
InvalidMetadata() |
Empty or oversized name or symbol, or oversized logo, description or social |
LaunchVerificationFailed() |
The Pons launch record or curve does not match what was requested |
InexactHostTransfer(uint256 expected, uint256 received) |
The first-buy pull did not deliver exactly firstBuy + fee |
WiringMismatch() |
Constructor wiring check failed |
§VirusFeeder
The Pons creator fee recipient of exactly one virus. Deployed as an EIP-1167 clone whose immutable arguments fix the host, developer, treasury and every Pons reference; the split is in the implementation bytecode. After a one-shot bind, nothing about a feeder can change. It has no owner.
§Functions
function config() public view returns (Config memory);
function host() external view returns (address);
function developer() external view returns (address);
function treasury() external view returns (address);
function bind(address virus_, address curve_) external;
function feed() external returns (uint256 gross);
function claimDev() external returns (uint256 amount);
function burnStrayVirus() external returns (uint256 amount);
function state() external view returns (State memory s);
// public storage
function virus() external view returns (address);
function curve() external view returns (address);
function poolId() external view returns (bytes32);
function severed() external view returns (bool);
function devOwed() external view returns (uint256);
function devClaimed() external view returns (uint256);
function totalFed() external view returns (uint256);
function totalBurned() external view returns (uint256);
function totalDevBooked() external view returns (uint256);
function totalTreasury() external view returns (uint256);
function lastSweep() external view returns (SweepOutcome);
| Function |
Access |
Notes |
config, host, developer, treasury |
View, clones only |
Decoded from the clone's immutable arguments. Revert NotClone on the implementation. |
bind |
The feeder factory only, once |
Verifies the Pons launch record (exists, token, curve, pairToken == host, creatorFeeRecipient == this, buyback off), stores virus, curve and the derived V4 poolId. |
feed |
Anyone |
nonReentrant, bound clones only. Sweep where Pons allows, claim host from escrow, split balance − devOwed 50/30/20, burn, pay treasury, record. Returns the gross distributed. See Feeding. |
claimDev |
Anyone; pays only the immutable developer |
nonReentrant, bound clones only. Pays all of devOwed. |
burnStrayVirus |
Anyone |
nonReentrant, bound clones only. Burns the feeder's entire balance of its own virus token. |
state |
View, bound clones only |
The lab readout below. |
§Structs and enums
struct Config {
address host;
address developer;
address treasury;
address registry;
address ponsFactory;
address feeEscrow;
address memeHook;
address feederFactory;
}
enum SweepOutcome {
None, // 0: nothing to sweep in this phase
Swept, // 1: Pons sweep executed
CurveSweepFailed, // 2: curve sweep reverted; fees remain on the curve
AwaitingPonsSweep, // 3: post-graduation fees need the Pons sweep operator first
NotRecipient // 4: Pons no longer routes this child's creator fees here
}
struct State {
address virus;
address host;
address developer;
address treasury;
PonsGraduationPhase phase;
bool isPonsRecipient;
uint256 escrowed; // host credited to this feeder in the Pons escrow
uint256 undistributed; // host held and not yet distributed (excludes devOwed)
uint256 devOwed;
uint256 devClaimed;
uint256 totalFed;
uint256 totalBurned;
uint256 totalTreasury;
}
§Events
| Event |
Fields |
Bound |
address indexed virus, address indexed curve, bytes32 poolId |
VirusFed |
address indexed virus, address indexed host, uint256 grossReceived, uint256 burned, uint256 devBooked, uint256 treasuryAmount, uint256 hostTotalSupplyAfter, SweepOutcome sweep |
DevClaimed |
address indexed developer, uint256 amount |
RecipientStatus |
bool active |
StrayVirusBurned |
uint256 amount |
§Errors
| Error |
Raised when |
NotClone() |
A clone-only function is called on the implementation |
NotFeederFactory() |
bind is called by anyone but the feeder factory |
AlreadyBound() |
bind is called a second time |
NotBound() |
feed, claimDev, burnStrayVirus or state before binding |
BindMismatch() |
The Pons launch record does not match the feeder |
NothingToClaim() |
claimDev with devOwed == 0, or burnStrayVirus with no virus balance |
BurnNotReflected(uint256 expected, uint256 actual) |
Host totalSupply did not fall by exactly the burned amount |
§What the feeder cannot do
It has no function that calls Pons transferCreatorFeeRecipient or setBuybackEnabled, makes an arbitrary call, accepts a caller-supplied target or calldata, or moves host anywhere except the burn, the treasury transfer and the developer payout. Every external call targets an immutable clone argument or the bound virus (security invariant 14).
§VirusFeederFactory
Deploys one deterministic feeder clone per virus and binds it exactly once. A feeder is never reused and a virus never gets a second feeder. Its feeder implementation is created in its constructor and is immutable.
§Functions
constructor(IVirusRegistry registry_);
function deployFeeder(bytes32 salt, VirusFeeder.Config calldata cfg) external returns (address feeder);
function bind(address feeder, address virus, address curve) external;
function predictFeeder(bytes32 salt, VirusFeeder.Config calldata cfg) external view returns (address);
function registry() external view returns (IVirusRegistry); // immutable
function implementation() external view returns (address); // immutable
function isFeeder(address feeder) external view returns (bool);
function virusOfFeeder(address feeder) external view returns (address);
function feederOf(address virus) external view returns (address);
| Function |
Access |
Notes |
deployFeeder |
registry.coordinator() only |
Clones.cloneDeterministicWithImmutableArgs(implementation, abi.encode(cfg), salt). Requires cfg.feederFactory == this and cfg.registry == registry. |
bind |
registry.coordinator() only |
One-shot on both sides; calls feeder.bind(virus, curve). |
predictFeeder |
View |
CREATE2 address for (salt, cfg). |
§Events
| Event |
Fields |
FeederDeployed |
address indexed feeder, address indexed host, address indexed developer, bytes32 salt |
FeederBound |
address indexed feeder, address indexed virus, address curve |
§Errors
| Error |
Raised when |
NotCoordinator() |
Caller is not the registry's current coordinator |
ConfigMismatch() |
cfg names a different factory or registry |
UnknownFeeder(address feeder) |
bind on an address this factory did not deploy |
FeederAlreadyBound(address feeder) |
The feeder is already bound |
VirusAlreadyHasFeeder(address virus) |
The virus already has a feeder |
§VirusRegistry
Canonical record of every host and every virus. Ownable2Step, owned by the VIRUS admin. Writers are narrow: the current coordinator registers viruses; each virus's own feeder records its feeds, developer claims and recipient status. Feeder writes are never pausable. Nothing edits an existing record.
§Functions
constructor(address initialOwner, address initialTreasury);
// admin (onlyOwner)
function setLaunchesPaused(bool paused) external;
function setHostDisabled(address host, bool disabled) external;
function proposeTreasury(address proposed) external;
function cancelTreasury() external;
function executeTreasury() external;
function setInitialCoordinator(address initial) external;
function proposeCoordinator(address proposed) external;
function cancelCoordinator() external;
function executeCoordinator() external;
function renounceOwnership() public pure; // always reverts
// coordinator
function registerVirus(Registration calldata r) external returns (uint32 strain);
// feeders
function recordFeed(uint256 gross, uint256 burned, uint256 devBooked, uint256 treasuryAmount, uint256 hostSupplyAfter) external;
function recordDevClaim(uint256 amount) external;
function recordRecipientStatus(bool active) external;
// views
function getHost(address host) external view returns (Host memory);
function getVirus(address token) external view returns (Virus memory);
function isVirus(address token) external view returns (bool);
function hostCount() external view returns (uint256);
function virusCount() external view returns (uint256);
function hostAt(uint256 index) external view returns (address);
function virusAt(uint256 index) external view returns (address);
function childrenOf(address host) external view returns (address[] memory);
function virusesOf(address developer) external view returns (address[] memory);
function hosts(uint256 offset, uint256 limit) external view returns (address[] memory);
function viruses(uint256 offset, uint256 limit) external view returns (address[] memory);
// public storage and constants
function coordinator() external view returns (address);
function treasury() external view returns (address);
function launchesPaused() external view returns (bool);
function pendingTreasury() external view returns (address);
function pendingTreasuryAt() external view returns (uint256);
function pendingCoordinator() external view returns (address);
function pendingCoordinatorAt() external view returns (uint256);
function hostDisabled(address host) external view returns (bool);
function virusOfFeeder(address feeder) external view returns (address);
function TREASURY_DELAY() external view returns (uint256); // 2 days
function COORDINATOR_DELAY() external view returns (uint256); // 2 days
// inherited from Ownable2Step
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function transferOwnership(address newOwner) external; // onlyOwner
function acceptOwnership() external; // pending owner only
| Function |
Access |
Notes |
setLaunchesPaused |
Owner |
Blocks inoculate and registerVirus only. |
setHostDisabled |
Owner |
New launches on that host only. Reversible. |
proposeTreasury / cancelTreasury / executeTreasury |
Owner |
Execute only after TREASURY_DELAY. Only feeders created afterwards use the new treasury. |
setInitialCoordinator |
Owner, once |
One-time wiring at deployment. |
proposeCoordinator / cancelCoordinator / executeCoordinator |
Owner |
Execute only after COORDINATOR_DELAY. |
renounceOwnership |
— |
Always reverts, so the registry can never be left ownerless and paused. |
registerVirus |
Current coordinator |
Blocked while paused. Assigns the next strain number. Registers the host on its first virus. |
recordFeed, recordDevClaim, recordRecipientStatus |
The registered feeder of a virus |
Never pausable. The feeder can only write its own virus's record. |
§Structs
struct Host {
bool registered;
bool disabled;
uint8 depth;
uint64 registeredAt;
uint32 children;
address ponsCurve;
address ponsPairToken;
uint256 totalControlledFees;
uint256 totalBurned;
uint256 totalDevBooked;
uint256 totalTreasury;
uint256 totalInoculationFees;
}
struct Virus {
address token;
address curve;
address host;
address feeder;
address developer;
address treasury;
uint8 depth;
bool active; // false while Pons routes creator fees somewhere other than the feeder
uint16 creatorTaxBps;
uint32 strain;
uint64 launchBlock;
uint256 launchConfigId;
uint256 graduationThreshold;
uint256 firstBuy;
uint256 inoculationFee;
uint256 totalFed;
uint256 totalBurned;
uint256 devBooked;
uint256 devClaimed;
uint256 treasuryPaid;
}
struct Registration {
address token;
address curve;
address host;
address feeder;
address developer;
address treasury;
uint8 depth;
uint16 creatorTaxBps;
uint256 launchConfigId;
uint256 graduationThreshold;
uint256 firstBuy;
uint256 inoculationFee;
address hostPonsCurve;
address hostPonsPairToken;
}
§Events
| Event |
Fields |
HostRegistered |
address indexed host, uint8 depth, address ponsCurve, address ponsPairToken |
HostDisabled |
address indexed host, bool disabled |
VirusInoculated |
address indexed virus, address indexed host, address indexed developer, address feeder, address curve, uint32 strain, uint8 depth, uint16 creatorTaxBps, uint256 launchConfigId |
InoculationRecorded |
address indexed virus, address treasury, uint256 graduationThreshold, uint256 firstBuy, uint256 inoculationFee |
VirusFed |
address indexed virus, address indexed host, uint256 grossReceived, uint256 burned, uint256 devBooked, uint256 treasuryAmount, uint256 hostTotalSupplyAfter |
HostBurned |
address indexed host, address indexed virus, uint256 amount, uint256 hostTotalSupplyAfter |
DevBooked |
address indexed virus, address indexed developer, uint256 amount |
DevClaimed |
address indexed virus, address indexed developer, uint256 amount |
TreasuryPaid |
address indexed virus, address indexed treasury, uint256 amount |
VirusRecipientStatus |
address indexed virus, bool active |
LaunchesPausedSet |
bool paused |
TreasuryUpdateProposed |
address indexed current, address indexed proposed, uint256 executableAt |
TreasuryUpdateCancelled |
address indexed proposed |
TreasuryUpdated |
address indexed previous, address indexed current |
CoordinatorUpdateProposed |
address indexed current, address indexed proposed, uint256 executableAt |
CoordinatorUpdateCancelled |
address indexed proposed |
CoordinatorUpdated |
address indexed previous, address indexed current |
Plus the OpenZeppelin OwnershipTransferStarted and OwnershipTransferred events.
§Errors
| Error |
Raised when |
ZeroAddress() |
A required address is zero |
NotCoordinator() |
registerVirus from anyone but the coordinator |
NotFeeder() |
A record call from an address that is not a registered feeder |
LaunchesPaused() |
registerVirus while paused |
HostIsDisabled(address host) |
registerVirus on a disabled host |
DepthExceeded(uint8 depth) |
Depth above 3 |
InvalidDepth() |
Depth 0 |
AlreadyRegistered(address token) |
The virus is already registered |
FeederAlreadyUsed(address feeder) |
The feeder already belongs to a virus |
HostMismatch(address host) |
The implied host depth differs from the recorded one |
CoordinatorAlreadySet() |
setInitialCoordinator a second time |
NothingPending() |
Cancel or execute with nothing proposed |
DelayNotElapsed(uint256 executableAt) |
Execute before the delay |
OwnershipCannotBeRenounced() |
renounceOwnership |
§VirusTreasury
Ownable2Step holder of the treasury's 20% of fed host tokens and of inoculation fees. It has no reference to feeders and no way to touch a developer's booked balance.
§Functions
constructor(address initialOwner);
function withdraw(IERC20 token, address to, uint256 amount) external; // onlyOwner
function withdrawETH(address payable to, uint256 amount) external; // onlyOwner
function renounceOwnership() public pure; // always reverts
receive() external payable;
// inherited from Ownable2Step
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function transferOwnership(address newOwner) external; // onlyOwner
function acceptOwnership() external; // pending owner only
§Events
| Event |
Fields |
Withdrawn |
address indexed token, address indexed to, uint256 amount |
EthWithdrawn |
address indexed to, uint256 amount |
§Errors
| Error |
Raised when |
ZeroAddress() |
to is zero |
EthTransferFailed() |
The ETH transfer failed |
OwnershipCannotBeRenounced() |
renounceOwnership |
§VirusEconomics (library)
Internal library compiled into the contracts that use it. Mirrored bit for bit by packages/chain/src/economics.ts.
function split(uint256 gross) internal pure returns (Split memory s);
function inoculationFee(uint256 firstBuy) internal pure returns (uint256);
function creatorBaseScaled(uint256 baseFeeBps, uint256 protocolShareBps) internal pure returns (uint256);
function requiredCreatorTax(uint256 baseFeeBps, uint256 protocolShareBps) internal pure returns (uint256);
function phaseFees(uint256 baseFeeBps, uint256 protocolShareBps, uint256 creatorTaxBps)
internal pure returns (PhaseFees memory f);
function isParity(PhaseFees memory f) internal pure returns (bool);
struct Split { uint256 burn; uint256 dev; uint256 treasury; }
struct PhaseFees { uint256 ponsScaled; uint256 feederScaled; uint256 totalScaled; }
Constants are listed in Parameters.
§Pons functions VIRUS calls
VIRUS declares only the Pons members it calls or reads, in contracts/src/interfaces/IPonsV2.sol, written from the published factory source. Each is exercised by the fork tests before deployment.
§Called by the coordinator
| Contract |
Function |
Purpose |
| Factory |
canLaunch(address) |
Gate for the caller and for the coordinator |
| Factory |
launchFee() |
Exact msg.value |
| Factory |
getLaunchConfig(uint256) |
Config terms and enabled |
| Factory |
maxCreatorTaxBps() |
Tax cap |
| Factory |
memeHook(), feeEscrow() |
Feeder config; fee policy source |
| Factory |
getLaunchedToken(address) |
Host provenance, depth walk, post-launch verification |
| Factory |
approvedPairTokens(address), pairTokenEconomics(address) |
Checks E and F |
| Factory |
previewLaunchEconomics(uint256, address) |
Digest for the confirmation screen |
| Factory |
launchToken(TokenParams, uint256, address) |
The launch, payable |
| Meme hook |
currentFeePolicy() |
Live protocol share and hook fee |
| Curve |
pairToken(), feeBps(), creatorTaxBps(), token() |
Post-launch verification |
| Curve |
buy(uint256, uint256, address) |
The first buy only |
| Host token |
launchFactory(), curve(), decimals() |
Provenance and decimals |
§Called by each feeder
| Contract |
Function |
Purpose |
| Factory |
getLaunchedToken(address) |
Bind check, phase, recipient status |
| Curve |
sweepFees(uint256) |
Pre-graduation sweep with a zero buyback minimum |
| Meme hook |
sweepPoolFees(bytes32, uint256, uint256) |
Post-graduation sweep, as creator, with zero minimums |
| Fee escrow |
balanceOfToken(address, address), claimToken(address) |
Claim host |
| Host token |
balanceOf, totalSupply, burn(uint256), transfer |
Measure, burn, pay |
| Virus token |
balanceOf, burn(uint256) |
burnStrayVirus only |
§Called by the app, not by VIRUS contracts
| Contract |
Function |
Purpose |
| Factory |
graduate(address), createGraduatedPool(address) |
COMPLETE MIGRATION (sent by the user) |
| Factory |
getLaunchFeePolicy(address) |
Frozen per-virus economics |
| Factory |
pendingCreatorFeeRecipient(address) |
Owner-override detection |
| Factory |
launchConfigCount(), launchEnabled(), snipeTaxStartBps(), snipeTaxSeconds(), poolManager(), positionManager(), locker() |
Health and parameters |
| Curve |
buy, sell, getReserves, realQuoteReserve, sellableTokens, reservedTokens, readyToGraduate, graduated, quoteFeeBalance, creatorTaxBalance, phantomQuote, graduationThreshold, protocolFeeShareBps, deployer |
Trading, quotes, progress |
| Meme hook |
pendingFees(bytes32, address), pendingCreatorTax(bytes32, address) |
Fee pipeline |
IPonsV2.sol also declares read-only members that no VIRUS contract calls: launchForwarder() (read by the fork tests), feeSweepOperator(), pendingBuyback(bytes32, address) and curve.factory(). It declares transferCreatorFeeRecipient(address, address) only so that tests can prove a developer cannot call it successfully. No VIRUS contract calls it.