upstream

Concepts

The vault

Where fees wait, how they are split, when they expire, and what is guaranteed to add up.

States

StateMeaning
escrowNo wallet bound. The streamer share accumulates as pending.
boundA wallet is bound. Fees go straight through.
rotatingA wallet is bound and a change to another one is waiting out its delay.

Receiving fees

Each fee event is split with whole-number arithmetic:

burn      = amount * burnBps     / 10000   (rounded down)
launcher  = amount * launcherBps / 10000   (rounded down)
streamer  = amount - burn - launcher       (the remainder)

The streamer share is the remainder on purpose: rounding can only ever favour the person the money is for, and the three parts always add up to the amount.

The one invariant

accrued  ==  pending + paidStreamer + paidLauncher + burned

True after every call, in every state. The test suite checks it after each of 400 random operations (fees, claims, rotations, expiries at random times) and after every call in the scenario tests.

Expiry

If no wallet is bound and the waiting fees have been waiting for the full expiry (default 180 days), they are swept once:

  • onExpiry: launcher (default): to the launcher wallet.
  • onExpiry: burn: burned.

The expiry window counts from when fees start waiting. After a sweep, fees that arrive later start a new window. A vault that was never claimed does not lock money forever, and a streamer who shows up late still gets everything that arrived in the current window.

Configuration limits

  • The three shares must add up to 10000 basis points exactly.
  • The streamer must keep at least 50 percent (5000 bps). A vault cannot be set up to mostly pay the launcher.
  • Between 1 and 5 trusted attesters, all distinct valid Solana public keys.
  • A threshold of at least 1 and at most the number of attesters. A threshold of 0 would let a claim through with no attestation at all, so it is refused.
  • A positive expiry and a non-negative rotation delay.

On chain

The program applies the same rules. Fees arrive as plain SOL transfers to the vault's address, and crank, which anyone can call, measures what arrived and splits it. Due rotations and expiries are applied at the next instruction rather than continuously. See On-chain program.

What anyone can read

snapshot() returns the state, the bound wallet, the epoch, any pending rotation, every balance and when waiting fees expire. Everything needed to audit a vault is there.

Try it

The escrow lab on the home page runs this engine for 300 days with sliders for the fee rate, the claim day and the expiry.