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
| Network | Robinhood Chain (Arbitrum Orbit) |
| Chain ID | 4663 |
| RPC | https://rpc.mainnet.chain.robinhood.com |
| Explorer | https://robinhoodchain.blockscout.com |
Addresses
| Contract | Address |
|---|---|
| Pons factorylaunchToken, getLaunchedToken | 0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e |
| Pons routerlaunchAndBuy | 0xe33E9E479dF8802cb0866d5d05258bEc4cF62948 |
| Fee escrowcredits and claims | 0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e |
| Meme hookpost-graduation pool fees | 0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044 |
| Launch lockerholds graduated liquidity | 0x267444D099b10fB5Ed7c3Cc7B7c767AdcA574952 |
| USDGquote asset, 6 decimals | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
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 againstgetLaunchedToken.CreditedToken(account, token, from, amount)on the escrow. Becausefromis 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.