FeeProcessor
contracts/src/index/FeeProcessor.sol — the permissionless engine that turns accrued in-token fees into the protocol/RFV/holder split. It replaces the trusted keeper of earlier designs: anyone may call it, and it holds no funds between calls.
convert
function convert(
address index,
uint256 minReserveOut, // min USDG from selling the fee tokens (> 0)
uint256[] calldata stockMinOuts, // per-stock min out (> 0 each, length == basket)
uint256 deadline
) external nonReentrant;
Execution:
- Pull.
index.releaseFees()transfers the accrued fee tokens to the processor (untaxed — the processor is fee-exempt). RevertsNothingToProcessif zero. - Swap. Fee tokens → reserve asset (USDG) via the registered v2-style router, bounded by
minReserveOut. - Split.
protocolCut = 10%(fixed) → protocol treasury;rfvCut = rfvShareBps→ the index's RFV treasury;distCut = remainder. - Buy & distribute.
distCutis spent evenly across the basket buying each stock, each transferred to the IndexToken followed bydistribute(stock)— dividends are live in the same transaction.
Emits Converted(index, feeTokens, reserveIn, protocolCut, rfvCut, distSpent).
Robustness (audit-hardened)
- One bad stock can't brick the basket (finding V2): each stock buy runs under
try/catch; a delisted / liquidity-less / reverting leg is skipped and its budget stays in USDG, while the others distribute normally. - The skip path can't be gamed: the effective min-out per stock is capped at the router's own
getAmountsOutquote, so a griefer can't pass absurd min-outs to force skips and reroute value. - No silent no-ops: if nothing was distributed and nothing went to RFV (
distSpent == 0on a distributing index), the call reverts instead of consuming fees for nothing; zero-quote legs are skipped. - Pure-RFV indexes (
rfvShareBps = 9000) skip the stock loop entirely — conversion is just swap + split.
Slippage: caller-supplied, oracle-floored on mainnet
All min-outs must be > 0 — zero-bound conversions revert. The bounds are caller-supplied, which is safe on the testnet's 1:1 mock router; on mainnet callers should derive floors from the per-asset Chainlink feeds that exist for every Robinhood Chain tokenized equity (or a TWAP) to close the sandwich vector on thin pools. The optional keeper/ script does exactly this computation.
Robinhood Chain tokenized stocks trade via RFQ/0x at launch, not necessarily v2 AMM pools. The v2-router path is the testnet-mock wiring; mainnet deployment will route stock buys accordingly (see Security → mainnet gates).