Reference
Contracts
Two small contracts: a factory that creates one vault per token, and the vault itself. Neither is upgradeable, and Feeroute holds no role in either.
Addresses
Robinhood Chain mainnet, chain id 4663. Explorer: Blockscout.
| Contract | Address |
|---|---|
| Feeroute factory | 0x4cAa25fdd5a05e0c630761D2D1f20fbC0787b01B |
| Feeroute vaults | One per token, created by the factory. Browse them on Explore. |
| Pons v2 launch factory | 0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e |
| Pons fee escrow | 0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e |
| Multicall3 | 0xcA11bde05977b3631167028862bE2a173976CA11 |
FeerouteFactory
Creates vaults. Only the token's current Pons fee recipient may create its vault, and becomes its owner. The factory doesn't route fees itself; that is a separate call on the Pons factory.
| Function | Who | What it does |
|---|---|---|
createVault(token, splits, creatorCapBps, timelock) | The token's fee recipient | Deploys a vault owned by the caller with the first split live. ETH-quoted curves only. |
vaultOf(token) | View | Latest vault created for a token |
vaults(i) · vaultCount() | View | Every vault ever created |
FeerouteVault
Split entry
FeerouteVault.Split
struct Split {
address account; // who gets paid
uint16 bps; // share in basis points, all entries add up to 10_000
uint32 vestSeconds; // 0 = paid at once, up to 365 days
bytes32 label; // on-chain name shown on the report
}Write functions
| Function | Who | What it does |
|---|---|---|
sweep() | Anyone | Claim from the Pons escrow, then split everything not owed yet by the active shares |
proposeSplits(splits) | Owner | Queue a new split and start the timelock |
executeSplits() | Anyone, after the timelock | Sweep with the old split, then activate the new one |
cancelSplits() | Owner | Drop the queued split |
proposeRoute(recipient) | Owner | Queue moving the Pons fee route away from the vault |
executeRoute() | Anyone, after the timelock | Sweep, then call transferCreatorFeeRecipient on Pons |
cancelRoute() | Owner | Drop the queued route change |
release(account) | Anyone | Pay account everything it can take now; funds only go to account |
releaseTo(to) | Recipient | Take your own unlocked share to another address |
claimFromPons() | Anyone | Fallback claim from the escrow with all available gas |
claimTokenFromPons(token) | Anyone | Claim ERC-20 credit from the escrow; not split, the owner rescues it |
rescueToken(token) | Owner | Send the vault's balance of an ERC-20 to the owner |
transferOwnership(to) · acceptOwnership() | Owner, then new owner | Two-step ownership handover |
Views
| Function | Returns |
|---|---|
splits() | The active split |
pendingSplits() | The queued split and when it can execute (0 if none) |
pendingRoute() · pendingRouteEta() | The queued route target and when it can execute |
sweepable() | ETH in the vault the next sweep would split |
pendingInPons() | ETH credited to the vault in the Pons escrow, claimed by the next sweep |
releasable(account) | What the account could release right now |
vesting(account) | ETH still locked for the account, and when it fully unlocks |
claimable(account) | Deferred payments and unlocked vesting already set aside |
totalSwept() · totalOwed() | Lifetime ETH split, and ETH held for recipients |
splitsVersion() · creatorCapBps() · timelock() | Current split version and the fixed settings |
token() · curve() · ponsFactory() · owner() | What the vault is bound to |
Constants
| Constant | Value | Meaning |
|---|---|---|
MAX_RECIPIENTS | 10 | Entries per split |
TOTAL_BPS | 10,000 | Shares must add up to this |
MAX_VEST | 365 days | Longest vesting period |
MAX_TIMELOCK | 30 days | Longest timelock |
PAYOUT_GAS | 50,000 | Gas forwarded to each recipient during a sweep |
CLAIM_GAS | 500,000 | Gas given to the escrow claim inside a sweep |
Events
The public report and the Activity page are built from these, so everything they show can be checked on-chain.
FeerouteVault events
Swept(uint64 indexed splitsVersion, uint256 amount, address indexed caller)
Paid(address indexed account, uint256 amount)
PaymentDeferred(address indexed account, uint256 amount)
Vested(address indexed account, uint256 amount, uint64 end)
Released(address indexed account, address indexed to, uint256 amount)
ClaimedFromPons(address indexed escrow, uint256 amount)
ClaimedTokenFromPons(address indexed escrow, address indexed token, uint256 amount)
SplitsProposed(uint64 indexed version, Split[] splits, uint64 eta)
SplitsExecuted(uint64 indexed version, Split[] splits)
SplitsCancelled(uint64 indexed version)
RouteProposed(address indexed newRecipient, uint64 eta)
RouteChanged(address indexed newRecipient)
RouteCancelled(address indexed newRecipient)
TokenRescued(address indexed token, address indexed to, uint256 amount)
FeerouteFactory:
VaultCreated(address indexed token, address indexed vault, address indexed owner,
address curve, uint16 creatorCapBps, uint32 timelock)Errors
| Error | Raised when |
|---|---|
InvalidRecipientCount | A split has no entries or more than 10 |
InvalidAccount | A recipient or route target is the zero address or the vault |
DuplicateAccount | The same wallet appears twice |
ZeroShare | An entry has 0 bps |
InvalidTotal | Shares don't add up to 10,000 bps |
InvalidVest · InvalidTimelock · InvalidCap | A setting is above its maximum |
CreatorCapExceeded | The owner's address would hold more than the cap |
ProposalPending | A proposal of the same kind is already queued |
NoProposal · TimelockActive | Nothing to execute or cancel, or it's too early |
NothingToRelease | The account has nothing unlocked |
InsufficientGas | The transaction can't cover a full escrow claim or payout |
TransferFailed | A release couldn't be delivered |
UnknownToken · NotFeeRecipient · UnsupportedQuote | Factory: not a Pons v2 token, caller isn't its fee recipient, or the curve isn't quoted in ETH |
From the command line
You don't need this site to use a vault. With Foundry's cast and the public RPC:
terminal
RPC=https://rpc.mainnet.chain.robinhood.com VAULT=0x… # from Explore or the report # the active split cast call $VAULT "splits()((address,uint16,uint32,bytes32)[])" --rpc-url $RPC # fees ready now, and fees waiting in Pons cast call $VAULT "sweepable()(uint256)" --rpc-url $RPC cast call $VAULT "pendingInPons()(uint256)" --rpc-url $RPC # split them (anyone can) cast send $VAULT "sweep()" --rpc-url $RPC --account <your keystore> # take what has unlocked for a recipient cast send $VAULT "release(address)" <recipient> --rpc-url $RPC --account <your keystore>