Skip to content
Protocol contracts not yet configured for this build
Enter app

Architecture

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()

solidity
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

solidity
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:

solidity
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

solidity
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:

text
totalRevenueClaimed  - totalRevenueRouted == unallocatedRevenuetotalSentToBuybacks  - totalEthSpent      == buybackBudgettotalPloutoBurned + totalPloutoSentToDead == totalPloutoRetiredByProtocoltotalRewardsReceived - totalRewardsClaimed <= address(staking).balance

All four are asserted as invariants across randomised call sequences.