Skip to content

Whitepaper · 5

Protocol reference

Pons publishes no SDK, so this integration is direct contract calls and event indexing. Everything below was recovered from deployed bytecode and confirmed with live calls against mainnet — several of the assumptions the documentation implied turned out to be wrong in ways that matter.

Chain

NetworkRobinhood Chain (Arbitrum Orbit)
Chain ID4663
RPChttps://rpc.mainnet.chain.robinhood.com
Explorerhttps://robinhoodchain.blockscout.com

Addresses

ContractAddress
Pons factorylaunchToken, getLaunchedToken0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e
Pons routerlaunchAndBuy0xe33E9E479dF8802cb0866d5d05258bEc4cF62948
Fee escrowcredits and claims0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e
Meme hookpost-graduation pool fees0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044
Launch lockerholds graduated liquidity0x267444D099b10fB5Ed7c3Cc7B7c767AdcA574952
USDGquote asset, 6 decimals0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168

The CharityVault interface

// Both entrypoints are permissionless — msg.sender into Pons is the vault
// regardless of who calls them, so a keeper needs no privilege.
function sweep(address[] curves, uint256 minBuybackTokensOut) external;
function harvest(address[] assets) external;   // address(0) = native

function ein() external view returns (string);           // the charity, immutable
function creator() external view returns (address);      // 0x0 when 100% to charity
function creatorSplitBps() external view returns (uint16);

event Harvested(bytes32 indexed einHash, address indexed asset,
                uint256 toTreasury, uint256 toCreator);

Findings that changed the design

These are the places where the obvious reading of the protocol was wrong. Each was found by testing against mainnet rather than by reading documentation, and each would have shipped a real bug.

1. The fee sweep operator is the recipient, not the deployer

sweepFees reverts with NotFeeSweepOperator() for anyone but the coin’s creatorFeeRecipient. Tested against three live coins whose deployer and recipient differ, the deployer was rejected every time. This is what makes the whole design work: because the vault is the recipient, it is the only address that can sweep — and it will do so for anyone who asks.

2. quoteReserve includes a phantom reserve

It is phantomQuote + realQuoteReserve. On launch config 0 the phantom is 3,236,000,000 against a threshold of 8,090,000,000, so the naive progress calculation reports every untouched coin as 40% graduated. Progress must be realQuoteReserve / (graduationThreshold − phantomQuote).

3. The escrow’s balance view takes the account first

balanceOfToken(account, token), not (token, account). The signature database gives no argument order and the natural reading is the wrong one. A fork trace of a real sweep settled it — before that, money appeared to vanish.

4. Pair tokens are not all dollars

Alongside USDG (6 decimals), Robinhood Chain’s tokenised equities are approved as pair tokens — 0xd0601C… is “NVIDIA · Robinhood Token” at 18 decimals. Formatting one of those with USDG’s decimals overstates it by a factor of a trillion; a 0.27 NVDA balance rendered as $330,771,619 before this was caught.

5. A swallowed out-of-gas corrupts gas estimation

The vault batches sweeps and tolerates per-curve failures so one idle coin cannot block the rest. But a catch cannot distinguish an out-of-gas from a logical revert, so eth_estimateGas settles on the cheapest gas where the outer call succeeds — the path where every inner sweep runs out. The transaction mines green having moved nothing. The vault now refuses to start a sweep below a gas floor and reverts when a non-empty batch sweeps nothing.

Events worth indexing

  • TokenLaunched(token, curve, deployer, pairToken, launchConfigId, graduationThreshold) on the Pons factory — note it does not carry the fee recipient, so a launch has to be resolved against getLaunchedToken.
  • CreditedToken(account, token, from, amount) on the escrow. Because from is the curve, this gives exact per-coin attribution with no balance-delta guesswork.
  • Harvested(einHash, asset, toTreasury, toCreator) on each vault — the complete record of what has left it.

The full recon, including how each interface was recovered from bytecode, lives in contracts/RECON.md in the repository.

NextRoadmapWhat is built, what is missing, and what is blocking launch