Skip to content
SECTION 05 / 15

Trading

How virus buys and sells work on the Pons curve and in the graduated pool, how quotes and price impact are computed, and what is still unverified.

§Two trading phases

Every virus trades in two phases, both run entirely by Pons:

Phase Pons phase Venue Fee rate Fee currency
Curve NotGraduated PonsV2BondingCurve of the virus curveFeeBps + creatorTaxBps Always the host
Pool PoolCreated Uniswap V4 pool of virus/host with the Pons meme hook hookFeeBps + creatorTaxBps The swap's unspecified currency

Between them sits migration: a sold-out curve waiting for graduate, then phase Swept waiting for createGraduatedPool. Nothing trades during migration. See Graduation.

VIRUS does not run a market. Trades go directly to the Pons curve or to the Uniswap Universal Router. VIRUS contracts are not in the trade path, and the only trade VIRUS contracts ever make is the atomic first buy inside inoculate.

§Buying on the curve

A buy spends host and receives virus. The fee legs are taken from the input, on the quote side (VERIFIED_PONS C2):

fee       = floor(spent × feeBps / 10,000)
tax       = floor(spent × creatorTaxBps / 10,000)
net       = spent − fee − tax
tokensOut = getAmountOut(net, quoteReserve, tokenReserve, 0)
          = net × tokenReserve / (quoteReserve + net)            (floored)
  • feeBps is the Pons base fee snapshotted on the curve (curve.feeBps()).
  • creatorTaxBps is the creator tax VIRUS set at launch (curve.creatorTaxBps()).
  • The fee and the tax are each floored separately.
  • getAmountOut is called with a zero fee because the fees were already taken.

The call is:

function buy(uint256 quoteIn, uint256 minTokensOut, address recipient)
    external payable returns (uint256);

For a virus, quoteIn is in host tokens and requires a prior host.approve(curve, quoteIn). The curve credits ERC-20 input by balance delta.

§Reserves

The curve prices against a virtual reserve that includes a phantom quote amount (VERIFIED_PONS C4):

quoteReserve     = phantomQuote + trackedQuote − quoteFeeBalance − creatorTaxBalance
realQuoteReserve =                trackedQuote − quoteFeeBalance − creatorTaxBalance

getReserves() returns (quoteReserve, tokenReserve). For a virus, phantomQuote and the graduation threshold come from Pons's pairTokenEconomics(host), in host units. Collected fees and tax sit on the curve (quoteFeeBalance, creatorTaxBalance) until swept, and are excluded from the pricing reserve.

§Partial fill at the graduation boundary

Only supply − reservedTokens tokens can ever be sold from the curve; the rest is reserved for the graduated pool. A buy that would take more than the remaining sellable amount is partially filled up to it, and the unspent host is refunded to msg.sender (VERIFIED_PONS C6). The app's quote reproduces this: it computes the net input needed for the remaining tokens with getAmountIn, grosses it up for the fee and tax, rounding up, and reports the spent amount, the refund and a clamped flag.

§Selling on the curve

A sell spends virus and receives host. The fee legs are taken from the gross output, again on the quote side (VERIFIED_PONS C3):

gross    = getAmountOut(tokensIn, tokenReserve, quoteReserve, 0)
fee      = floor(gross × feeBps / 10,000)
tax      = floor(gross × creatorTaxBps / 10,000)
quoteOut = gross − fee − tax
function sell(uint256 tokensIn, uint256 minQuoteOut, address recipient)
    external returns (uint256);

On the curve, every fee and every creator tax is paid in the host, on both buys and sells. That is why a virus's curve phase feeds its feeder purely in host.

§Sells close at readyToGraduate

Once the curve has sold its entire sellable allocation, readyToGraduate() becomes true (sellableTokens() == 0, VERIFIED_PONS C5). From then on sells are closed (VERIFIED_PONS C3) and there is nothing left to buy. The app disables trading on that leg and offers COMPLETE MIGRATION instead. Trading resumes in the pool once migration completes.

§Quotes

Curve quotes are computed locally by packages/chain/src/curveMath.ts, a port of PonsV2BondingCurveMath and the fee legs of PonsV2BondingCurve.buy and sell from the published Pons source, run over reserves read live from the curve. The two base formulas (VERIFIED_PONS M1, M2):

getAmountOut(in, rIn, rOut, fee) = in·(10,000 − fee)·rOut / (rIn·10,000 + in·(10,000 − fee))
getAmountIn(out, rIn, rOut, fee) = out·rIn·10,000 / ((rOut − out)·(10,000 − fee)) + 1

Pool quotes are obtained by simulating V4Quoter.quoteExactInputSingle against the live pool, which includes the Pons hook fee and creator tax.

§Spot price and price impact

  • Spot price of one virus in host: quoteReserve / tokenReserve, including the phantom reserve.
  • Buy price impact compares the tokens received with the tokens the full input would buy at spot: (spotTokens − tokensOut) / spotTokens, where spotTokens = spent × tokenReserve / quoteReserve. Because spent includes the fee and tax, the buy impact figure includes them.
  • Sell price impact compares the gross output, before fees, with the spot value of the tokens sold: (spotValue − gross) / spotValue, where spotValue = tokensIn × quoteReserve / tokenReserve.

Every curve trade shows its fee lines (PONS BASE FEE, CREATOR TAX), expected output and MINIMUM RECEIVED before signing. A pool swap shows the V4 quoter's expected output, which already has the hook fee and creator tax deducted, and its minimum.

§The launch-window snipe tax

The published Pons factory snapshots two values into every launch: snipeTaxStartBps (published-source default 9,900) and snipeTaxSeconds (published-source default 15, maximum 60). It auto-exempts the launch's originalDeployer and creatorFeeRecipient, and calls exemptFromSnipeTax on the curve (VERIFIED_PONS F15, factory side).

The published PonsV2BondingCurve has no snipe-tax logic and no exemptFromSnipeTax function (UNVERIFIED X1). The deployed curve must therefore differ from the published one, and VIRUS does not know:

  • whether the tax is keyed on msg.sender or on recipient;
  • its exact rate over the window. A secondary source describes it as decaying to zero over 5 seconds, while the published factory default window is 15 seconds (UNVERIFIED X5).

What VIRUS does about it:

  • The app reads snipeTaxStartBps() and snipeTaxSeconds() live and never displays a constant.
  • Quotes that fall inside a launch's snipe window are flagged, never silently assumed untaxed. The local quote port does not include the unpublished tax.
  • The coordinator's first buy is exempt under either keying (see Launching).

§After graduation: the pool

Once Pons has created the graduated pool, the virus trades in a Uniswap V4 pool whose currencies are the virus and its host, whose LP fee is zero (poolFee must be 0), and whose hook is the Pons meme hook (VERIFIED_PONS F19, H7). All fees in this phase are hook fees.

The hook takes hookFeeBps + creatorTaxBps of the swap's unspecified currency (VERIFIED_PONS H2). For the exact-input swaps VIRUS builds:

Swap Specified (input) Unspecified (output) Fee is taken in
Buy virus with host Host Virus Virus
Sell virus for host Virus Host Host

This has a direct effect on feeding. Post-graduation buys accrue fees in the virus token, and Pons lets only its fee sweep operator convert those. Until it does, the feeder reports AWAITING_PONS_SWEEP. See Feeding.

The pool's Pons protocol cut is hookFeeBps × protocolFeeShareBps, and the feeder's share is hookFeeBps × (1 − protocolFeeShareBps) + creatorTaxBps. Because hookFeeBps and curveFeeBps are separate Pons parameters, the pool-phase total can differ from the curve-phase total. The app shows the two phases as separate rows.

§Executing pool swaps

Pool swaps go through the Uniswap Universal Router with Permit2 (see Infection routes). A swap takes three signed steps:

  1. an exact approval of the input token to Permit2;
  2. a Permit2 allowance for the router;
  3. the swap itself, with a minimum output from the V4Quoter's quote.

The encoding matches the source of Universal Router 2.1.2, the version deployed on Robinhood Chain. In the local lab it has been executed against pinned builds of that router and its Uniswap V4 contracts. The deployed contracts on Robinhood Chain are still UNVERIFIED, so graduated-pool trading stays disabled in the production app until the fork test test_fork_UniversalRouterSwap passes. Until then VIRUS does not submit pool swaps.

§Slippage and minimums

Every trade uses one of three slippage settings, 0.5%, 1% (default) or 3%, and a minimum output of floor(quote × (10,000 − slippageBps) / 10,000). A zero minimum is never submitted. See Infection routes.

§Where the fees go

Part of the fee Recipient
Pons protocol share of the base or hook fee Pons
Remainder of the base or hook fee, plus the full creator tax The virus's VirusFeeder, credited in host through the Pons fee escrow
Of what the feeder receives 50% burned from host supply, 30% booked to the developer, 20% to the VIRUS treasury

The exact numbers are in Fees and burns.