The complete fee journey
A single wei, followed end to end. Every step names the contract, the function and the state change.
1. A trade
Someone buys PLOUTO on the Pons curve. The curve takes curveFeeBps (100 bps in the live config) and accumulates it internally.
State: inside the Pons curve. Not readable by Plouto as a per-recipient balance. Plouto shows: an em dash. See fee accrual.
2. Pons sweeps
At a time Plouto does not control, Pons sweeps accrued fees, splits protocol and creator shares, and credits the creator share to the recipient in the Fee Escrow.
State: feeEscrow.balanceOf(revenueRouter) is now non-zero.
Plouto shows: Credited in the Pons fee escrow.
3. Anyone calls claimPonsFees()
uint256 balanceBefore = address(this).balance;uint256 reported = feeEscrow.claim();received = address(this).balance - balanceBefore;The escrow sends ETH; receive() falls through because msg.sender is the escrow. The measured delta is credited.
State: totalRevenueClaimed += received, unallocatedRevenue += received.
Event: PonsFeesClaimed(reported, measuredDelta, unallocatedRevenue).
4. Anyone calls routeUnallocatedRevenue()
Our wei is part of amount. It is assigned to one of three shares — for this trace, say it lands in the 60%.
State: unallocatedRevenue = 0; the three cumulative totals increase; a RouteRecord is appended.
Event: RevenueRouted(amount, toBuybacks, toStakers, toReserve, totalRevenueRouted, routeIndex).
5. fundBuyback() on the executor
buybackBudget += msg.value;totalBudgetReceived += msg.value;State: the wei is now spendable budget.
Plouto shows: Buyback budget available, distinct from Spent on buybacks.
Event: BudgetFunded(from, amount, newBudget).
6. The keeper plans
Reads the phase, the reserves or the pool price, computes an expected output, applies a slippage tolerance, and simulates. If the simulation reverts, nothing is submitted.
7. executeBuyback(ethIn, minTokensOut, deadline)
Chain, deadline, floor, initialization and spend bounds are checked. The factory record is re-validated. Then:
buybackBudget -= ethIn;totalEthSpent += ethIn;Our wei leaves the protocol and enters the curve or the v4 pool.
8. PLOUTO arrives
Measured by balance delta, checked against minTokensOut, then checked against the on-chain price-impact floor derived from pre-trade spot.
9. Retirement
uint256 supplyBefore = _totalSupply(token);(bool ok,) = token.call(abi.encodeWithSignature("burn(uint256)", amount));if (ok && _totalSupply(token) + amount == supplyBefore) { totalPloutoBurned += amount; return true; }IERC20(token).safeTransfer(DEAD_ADDRESS, amount);totalPloutoSentToDead += amount;For PLOUTO this should take the burn path, since Pons tokens are ERC20Burnable.
State: totalPloutoRetiredByProtocol += acquired; an Execution is recorded.
Event: BuybackExecuted(ethSpent, tokensRetired, phase, realBurn, minTokensOut, newBudget, executionIndex).
The other two paths
Had the wei landed in the 30%, step 5 would instead be notifyRewardETH(), folding it into accRewardPerWeight and becoming claimable by every open position in proportion to Gravity. See staker reward mathematics.
Had it landed in the 10%, it would be depositRevenue() on the reserve, recorded as protocol revenue and locked behind the 2-day timelock. See PloutoReserve.
Reconciling the whole thing
At every point in the journey:
totalRevenueClaimed - totalRevenueRouted == unallocatedRevenuetotalSentToBuybacks - totalEthSpent == buybackBudgettotalPloutoBurned + totalPloutoSentToDead == totalPloutoRetiredByProtocoltotalRewardsReceived - totalRewardsClaimed <= address(staking).balanceAll four are asserted as invariants across randomised call sequences.