Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

token-stream

Linear vesting payment streams (Sablier-style).

A payer locks a deposit that vests linearly to a recipient over [start, end). The recipient can withdraw the vested-so-far amount at any time; either party can cancel, at which point the recipient keeps everything vested up to that moment and the payer is refunded the unvested remainder. Many independent streams of one token coexist, keyed by id — a minimal payroll / grant / subscription rail.

Mechanics

  • createStream(recipient, deposit, start, end)id — pulls deposit and opens the stream. Crediting is the actual amount received (fee-on-transfer safe).
  • vestedOf(id) — amount vested by now: 0 before start, deposit * (now - start) / (end - start) during, deposit after end (via Math.mulDiv, floored).
  • withdrawableOf(id)vested - withdrawn, what the recipient can pull right now.
  • withdraw(id, amount) — recipient pulls up to the withdrawable balance.
  • cancel(id) — payer or recipient cancels: recipient gets vested - withdrawn, payer gets deposited - vested. The stream settles to a zero remaining balance.

Safety

  • ReentrancyGuard on every token-moving entry point; SafeERC20; checks-effects-interactions (state is finalized before any transfer, including the two-leg cancel payout).
  • No stream can ever pay out more than was deposited; the vested curve is monotonic and clamps at the deposit.
  • Fully tested: unit tests for the vesting curve, partial withdrawals, the cancel split (before/during/after vesting), and every access guard, plus two stateful invariants (fail_on_revert = true):
    • conservation — the contract's balance always equals the sum over all streams of their remaining (deposited - withdrawn), which drops to zero on cancel;
    • no-overpay — for every stream, withdrawn <= deposited.

Test

forge test
FOUNDRY_INVARIANT_FAIL_ON_REVERT=true forge test --match-path "test/TokenStream.invariant.t.sol"

Deploy

TOKEN=0x... forge script script/Deploy.s.sol --rpc-url "$RPC_URL" --broadcast

Not audited. Reference implementation — review before any real deployment.

About

Sablier-style linear vesting payment streams: a payer locks a deposit that vests linearly to a recipient; the recipient withdraws vested funds anytime and either party can cancel to split the balance. Foundry, unit + stateful invariant tested.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages