QUIVER

Start here

Getting started

Creating a stream is two transactions: approve the token, then create. This page walks the whole path, from what you need beforehand to the recipient's first withdrawal.

Before you start

A wallet
Anything that speaks EVM. It must be on Robinhood Chain, id 4663.
The tokens
The full amount you want to stream, held by the address that will create the stream. QUIVER escrows the whole grant up front, it does not pull it later.
A little ETH
For gas, plus the creation fee. The fee is read live from the contract and shown in the form before you sign. See Fees.
The recipient address
A wallet, or a contract that implements onERC721Received. See the warning below.

Create a stream from the app

  1. Open the form and pick a shape

    Go to /create and connect. The presets are starting points, not rails: every field stays editable after you pick one.

    Team vesting
    4 years, 1 year cliff, cancelable.
    Investor unlock
    1 year, no cliff, irrevocable.
    Payroll
    30 days, no cliff, cancelable.
    Custom
    You set duration, cliff and cancelability yourself.
  2. Choose the token

    The dropdown lists ERC-20s that actually trade on the chain. Any other ERC-20 works too: pick Custom address and paste it. The list is a shortcut, not a permission.

  3. Set the recipient

    This address receives the NFT, and with it the right to every token the stream pays out. It does not have to be a third party. Streaming to yourself is the whole point of the team vesting pattern.

    Contract recipients

    The contract mints with _safeMint. If the recipient has code and does not implement onERC721Received, creation reverts. That is deliberate: such an address could never withdraw or transfer, and the tokens would be stranded forever. The form checks this before you sign, so you find out from a warning rather than a failed gas estimate.
  4. Set the amount and the schedule

    Duration and cliff are entered in days, counted from now. A cliff of 0 means no cliff. The summary panel shows the exact timestamps you are about to sign, and if you set a cliff, it tells you how much unlocks in one lump when the cliff lands.

  5. Decide if you can cancel

    Cancelable means you keep the right to stop the stream and take back the unvested remainder. Irrevocable means nobody can stop it, not you, not us. You can always give the right up later with renounceCancel, but you can never take it back. See Cancel and renounce.

  6. Approve, then create

    The first transaction approves QUIVER to move the amount. The second calls createStream and carries the fee as msg.value. Once it confirms, the NFT is minted and the app sends you to your streams.

    A real createStream on Robinhood Chain used 325,148 gas. It is heavier than a transfer because the contract indexes the stream on both sides, which is what lets this site work with no backend at all.

The same thing from a terminal

Nothing about QUIVER needs this website. The two calls below do exactly what the form does. Replace the amounts and timestamps with your own, and note that cliff and end are absolute Unix timestamps, not durations. Passing cliff == start means no cliff.

bash · approve then create
RPC=https://rpc.mainnet.chain.robinhood.com
QUIVER=0x2866D49f364a70383591a958354A89F6BDf050f2
TOKEN=0x020bfC650A365f8BB26819deAAbF3E21291018b4
RECIPIENT=0xYourRecipient

# 1. let QUIVER pull the grant (1,000 tokens, 18 decimals)
AMOUNT=$(cast to-wei 1000)
cast send $TOKEN "approve(address,uint256)" $QUIVER $AMOUNT \
  --rpc-url $RPC --private-key $KEY

# 2. a 1-year stream, no cliff, irrevocable
START=$(cast block latest --field timestamp --rpc-url $RPC)
END=$((START + 31536000))
FEE=$(cast call $QUIVER "creationFee()(uint256)" --rpc-url $RPC)

cast send $QUIVER \
  "createStream(address,address,uint128,uint40,uint40,uint40,bool)(uint256)" \
  $TOKEN $RECIPIENT $AMOUNT $START $START $END false \
  --value $FEE --rpc-url $RPC --private-key $KEY

Read the fee from the contract rather than hardcoding it. It is owner-settable under a cap, and any msg.value above the current fee is refunded to you in the same transaction.

Withdrawing

Only the current NFT holder, or an address they approved, can withdraw. They choose where the tokens land, which does not have to be the holder address. From the app, open the stream and hit withdraw. From a terminal:

bash · withdraw everything available
# what can be taken right now
cast call $QUIVER "withdrawableOf(uint256)(uint128)" 1 --rpc-url $RPC

# take it, sending the tokens anywhere you like
cast send $QUIVER "withdrawMax(uint256,address)(uint128)" 1 $DESTINATION \
  --rpc-url $RPC --private-key $KEY

withdrawMax reverts when nothing is due

withdrawMax withdraws the full withdrawable amount, and withdrawing zero is rejected. So during a cliff, or right after a withdrawal, it reverts with ZeroAmount. That is not a failure to diagnose, it just means there is nothing to take yet.

What happens next

The stream now runs on its own. The recipient can withdraw at any point, sell the NFT, or do nothing for four years and collect it all at the end. Nothing expires, and no withdrawal is ever required to keep the stream alive.