V10 event layouts
event Buy(address indexed buyer, address indexed recipient, uint256 grossEth, uint256 tokensOut, uint256 fee);
event Sell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 netEth, uint256 fee);
event PricePoint(uint256 priceWei);
event Graduated(bytes32 indexed poolId, uint256 ethAmount, uint256 tokenAmount, uint128 liquidity, uint160 sqrtPriceX96);Buy and Sell each have two indexed addresses and three uint256 data words. This is not the Pons V2 CurveBuy layout. Filter logs by the verified curve address and the correct event signature. Fee already includes applicable base fee and creator tax in the V10 buy/sell event. Native ETH amounts and JOHN-style token amounts use 18 decimals.
Transaction and event identity
Preserve chain ID, transaction hash, log index, block number and block hash. A useful unique event key is chainId:txHash:logIndex. Do not deduplicate only by transaction hash: one transaction can contain multiple trade events. Events can be emitted in both bonding and graduated trading. Avoid double-counting the same trade from curve events and pool Swap events.
Receipt checks
- Fetch the receipt and require successful status. Pending or unavailable receipts must remain pending.
- Match the logged contract address, topics and data against that receipt; check the block hash against the canonical block. Compare decoded amounts with the authorized input and minimum output before crediting a trade.
- For a direct user-to-curve call, match receipt sender/target and event buyer/seller/recipient to the expected transaction. The sample decodeDirectTrade helper covers this direct-call case only.
- For aggregator or smart-account routes, implement route-specific accounting and validate actual asset movements. Do not apply the direct-call helper blindly.
- Persist the event and checkpoint atomically. Deliver notifications through an idempotent outbox so a restart does not duplicate them.
Reorganizations and catch-up
Scan bounded ranges with a configurable confirmation lag. Save checkpoint block hashes and compare them on restart. If a hash changes, rewind to a verified common ancestor and invalidate/reprocess affected events. A fixed two-block delay is not a universal finality guarantee. Split rejected log ranges, retry with limits, and never advance the cursor past a failed range.
Graduation and display
The last bonding buy can share its receipt with Graduated. Determine phase using event order and the graduation event, not only the latest graduated() value. Show the actual ETH input/output from decoded events. If no trustworthy ETH/USD source is available, show ETH and omit the dollar estimate rather than display $0.00 as a measured value.