Slippage protection
A buyback is a public transaction announcing an intent to buy. Two independent bounds limit what a searcher can extract.
Bound one: the keeper's floor
minTokensOut, computed off chain from live state and passed in. Zero is rejected:
if (minTokensOut == 0) revert ZeroMinTokensOut();This is the ordinary AMM protection, and it depends on the keeper behaving.
Bound two: the contract's own floor
The contract derives its own reference from pre-trade spot and enforces it regardless of what the keeper passed.
Pre-graduation, from the live curve reserves:
uint256 idealOut = Math.mulDiv(ethIn, tokenReserve, quoteReserve);uint256 impactFloor = Math.mulDiv(idealOut, BPS - maxPriceImpactBps, BPS);// ... after the buy:if (got < impactFloor) revert PriceImpactTooHigh(got, impactFloor);Post-graduation, from the pool's sqrtPriceX96 read directly out of PoolManager storage:
bytes32 stateSlot = keccak256(abi.encode(poolId(token), POOLS_SLOT));uint160 sqrtPriceX96 = uint160(uint256(poolManager.extsload(stateSlot))); uint256 idealOut = Math.mulDiv(Math.mulDiv(ethIn, sqrtPriceX96, Q96), sqrtPriceX96, Q96);uint256 impactFloor = Math.mulDiv(idealOut, BPS - maxPriceImpactBps, BPS);Size bounds
Limiting how much can be sandwiched at once:
| Bound | Default | Effect |
|---|---|---|
maxEthPerExecution | 0.25 ETH | Caps a single trade. |
maxBudgetShareBps | 2500 | Caps the fraction of budget per trade. |
minEthPerExecution | 0.001 ETH | Prevents dust-sized griefing. |
Splitting a large budget across several bounded executions is strictly better against a sandwicher than one large trade.
Deadline
if (block.timestamp > deadline) revert DeadlinePassed(deadline);The keeper sets 180 seconds by default. A transaction that sits in the mempool long enough for conditions to change expires rather than executing at a stale price.
Route validation
Sandwiching is not the only attack. Every execution re-validates the venue against the factory record — token, curve, factory, pair token and graduation state must all agree, or RouteMismatch.
Residual risk
Private transaction relays would help further, but none is documented for Robinhood Chain — and assuming one would be exactly the kind of invented dependency this protocol avoids.
Verifying
BuybackExecuted includes minTokensOut alongside tokensRetired. Comparing the two across executions shows realised slippage over time. See verify a retirement.