Use cases
Cancel and renounce
Cancelling is the most misread function in the contract. It is not a clawback, it is a stop. And renouncing the right to it is the only promise QUIVER lets you make that nothing can undo.
Cancelling is not a clawback
The instinct is that cancelling undoes the stream and returns the deposit. It does not, and it never could without stealing from the recipient.
When the sender calls cancel, the contract splits the escrow at the current instant. The vested part stays owed to the NFT holder in full, and they can withdraw it afterwards, at their leisure, with no deadline. Only the unvested remainder is transferred back to the sender, immediately, in the same transaction.
- The vested part
- Stays in the contract, still owed to the NFT holder. Cancelling does not touch it, and does not put a clock on claiming it.
- The unvested part
- Goes back to the sender in the cancel transaction. This is the only value that moves.
- The stream
- Stops accruing at that instant, and never resumes. It stays readable and still owns its NFT.
What it does to the state
There is no special cancelled branch in the vesting maths. The contract freezes the stream by rewriting its schedule so the ordinary formula keeps giving the right answer forever:
deposited = vested at this instant # the stream now promises exactly what it owes
end = now # so vestedOf() returns deposited from here on
cliff = min(cliff, now) # keeps start <= cliff <= end true after the rewrite
start = min(start, now)
canceled = true
cancelable = falseTwo consequences worth knowing. deposited after a cancellation is not what was originally deposited, it is what stayed owed, so do not read it as the historical grant. And refundableOf returns 0 for a cancelled stream, because there is nothing left to refund.
A cancelled stream can still pay out
Who can cancel, and when it reverts
Only the sender, the address that funded the stream, and only if the stream is still cancelable. The NFT holder cannot cancel. The protocol owner cannot cancel. There is no admin path.
NoStream- The id was never minted.
NotSender- You are not the address that funded it. Holding the NFT does not help.
NotCancelable- The stream was created irrevocable, or the right was renounced, or it is already cancelled.
A detail that surprises people
Cancelling a second time reverts with NotCancelable, not AlreadyCanceled, because cancel clears the cancelable flag on its way out, and that check runs first. AlreadyCanceled is declared in the ABI but no call path currently reaches it. Worth knowing if you are decoding revert data and matching selectors.
Renouncing: the one way door
renounceCancel(id)permanently gives up the sender's right to cancel. It flips cancelable to false and emits CancelRenounced. From that block on, cancel on that stream reverts forever.
There is no undo. No admin function restores it, no upgrade path exists, and no argument you can make to us changes it. That is not an oversight to route around, it is the entire feature. A promise you can revoke is not a promise, and a reader can only trust cancelable == false precisely because nothing can flip it back.
Check the schedule before you close the door
RPC=https://rpc.mainnet.chain.robinhood.com
QUIVER=0x2866D49f364a70383591a958354A89F6BDf050f2
# read every field back before you commit
cast call $QUIVER \
"getStream(uint256)((address,uint40,uint40,bool,bool,address,uint40,uint128,uint128))" \
$ID --rpc-url $RPC
# permanent, from the next block on
cast send $QUIVER "renounceCancel(uint256)" $ID \
--rpc-url $RPC --private-key $KEYChoosing, at creation
The choice is really about what you are trying to prove, and to whom.
- Cancelable fits a contributor who is still proving themselves. If they leave in month three, the unvested part comes back and the vested part is theirs, which is what you agreed to anyway.
- Irrevocable fits anything you are asking a stranger to trust: a team allocation you want the market to believe, an investor unlock, a stream anyone might buy. It is the strongest statement the contract can make.
- Cancelable now, renounced later is the middle path, and usually the right one. Keep the right while it is useful, give it up the moment it stops being useful, and let the chain record when you did.
One thing to keep in mind if a stream might be sold: a cancelable stream is near-worthless to a buyer, because the sender can gut it in the same block as the sale. See the trap on Tradable streams.