Indexing revenue
The contracts store bounded arrays and expose them by index, so a full history can be read without an indexer. For a UI you will usually want one anyway.
On-chain arrays
// PloutoRevenueRouterfunction routesLength() external view returns (uint256);function getRoute(uint256 index) external view returns (RouteRecord); struct RouteRecord { uint64 timestamp; uint256 amount; uint256 toBuybacks; uint256 toStakers; uint256 toReserve;}Reading the most recent 50, newest first:
const count = Number(await client.readContract({ address: router, abi: ploutoRevenueRouterAbi, functionName: 'routesLength',})); const indices = Array.from({length: Math.min(count, 50)}, (_, i) => BigInt(count - 1 - i)); const routes = await client.multicall({ contracts: indices.map((i) => ({ address: router, abi: ploutoRevenueRouterAbi, functionName: 'getRoute', args: [i], })),});This is exactly what the Core page does. No backend is involved.
From logs
For a full historical index, or to attach transaction hashes, use the events instead:
const logs = await client.getLogs({ address: router, event: parseAbiItem( 'event RevenueRouted(uint256 amount, uint256 toBuybacks, uint256 toStakers, uint256 toReserve, uint256 totalRevenueRouted, uint256 routeIndex)' ), fromBlock: deploymentBlock, toBlock: 'latest',});routeIndex in the log corresponds exactly to the array index, so the two sources reconcile.
Reconstructing the pipeline
To rebuild the full fee picture you need three event streams:
| Event | Gives you |
|---|---|
PonsFeesClaimed | When fees were claimed, the measured amount, and what the escrow reported. |
RevenueRouted | Each split, with all three destinations. |
DonationReceived | ETH that is explicitly not revenue. |
Keep donations out of any "fees earned" figure. The contract does; an indexer that sums raw ETH inflows would not.
Invariants worth asserting in an indexer
If your reconstruction ever violates one of these, the bug is in the indexer:
Σ RevenueRouted.amount == totalRevenueRoutedΣ PonsFeesClaimed.measuredDelta == totalRevenueClaimedtotalRevenueClaimed - totalRevenueRouted == unallocatedRevenuetoBuybacks + toStakers + toReserve == amount (per event)Suggested schema
CREATE TABLE revenue_epoch ( route_index BIGINT PRIMARY KEY, block_number BIGINT NOT NULL, tx_hash BYTEA NOT NULL, ts TIMESTAMPTZ NOT NULL, amount_wei NUMERIC(78,0) NOT NULL, to_buybacks_wei NUMERIC(78,0) NOT NULL, to_stakers_wei NUMERIC(78,0) NOT NULL, to_reserve_wei NUMERIC(78,0) NOT NULL);Store wei as exact integers. Never store ETH as a float — the values exceed float precision and rounding will silently break the reconciliation above.