Lifecycle States
Creation
The seller calls
Funds: Asset collateral moves from seller wallet → venue escrow.
createOffer, specifying the asset, quote token, price per unit, size, expiry, unlock time (for deferred offers), and optionally a designated buyer (for private offers). At the same moment, the full collateral — the entire asset amount being offered — is transferred into escrow. The offer does not appear as fillable until the collateral transfer succeeds. There is no two-step “list then fund” flow; collateral and listing are atomic.Who can act: The seller only.Funds: Asset collateral moves from seller wallet → venue escrow.
Open
The offer is live and visible on the market. For public offers, any address may fill. For private offers, only the designated buyer address can execute a fill. The collateral sits in escrow and earns no yield; it is simply secured pending a fill, expiry, or cancellation.Who can act: Any address (public) or the designated buyer (private).
Funds: Collateral remains in escrow. No funds move until a fill is submitted.
Funds: Collateral remains in escrow. No funds move until a fill is submitted.
Partial Fill
A buyer fills a portion of the offer. The protocol calculates the quote amount owed for the filled size using cumulative precision arithmetic, transfers the quote from the buyer to the seller directly (plus fee to the fee recipient), and releases the proportional collateral to the buyer (spot) or issues claim tokens (deferred). The remaining unfilled collateral stays locked in escrow. Canopy tracks fills cumulatively — each new fill is recorded against the running total, which prevents any arithmetic inconsistency regardless of how many partial fills occur or in what order.Who can act: Any eligible buyer.
Funds: Quote moves buyer → seller; fee moves buyer → fee recipient; filled collateral moves escrow → buyer (spot) or claim tokens issued (deferred).
Funds: Quote moves buyer → seller; fee moves buyer → fee recipient; filled collateral moves escrow → buyer (spot) or claim tokens issued (deferred).
Partial fills are tracked cumulatively using
assetFilled and quotePaid. Pricing is mathematically consistent regardless of fill order — a fill of 100 units followed by a fill of 400 units produces exactly the same economic outcome as a single fill of 500 units.Full Fill
The cumulative filled amount reaches the total escrowed size (
Funds: All collateral has been disbursed or is fully backing outstanding claim tokens.
assetRemaining reaches 0). The offer is marked inactive. All collateral has been consumed — either delivered to spot buyers or backing issued claim tokens. The offer can no longer receive fills or be cancelled (there is nothing left to cancel).Who can act: No further actions available on this offer.Funds: All collateral has been disbursed or is fully backing outstanding claim tokens.
Expiry
If the offer’s expiry timestamp is reached before it is fully filled, the offer can no longer accept new fills (the
Funds: Unfilled collateral remains in escrow until the seller cancels.
fill function will revert with OfferExpired()). However, the offer remains active for cancellation purposes — the seller can still call cancel to recover the unfilled collateral. Any fills that already executed are settled and irreversible.Who can act: The seller (cancel only).Funds: Unfilled collateral remains in escrow until the seller cancels.
Expiry does not automatically return collateral. The seller must explicitly call
cancel to recover unfilled assets after expiry.Cancellation
At any point while the offer is active (whether before or after expiry), the seller may cancel. The protocol returns the remaining unfilled collateral to the seller’s wallet. Portions that have already been filled are settled and irreversible — cancellation affects only the open (unfilled) portion.Who can act: The seller only.
Funds: Unfilled collateral moves from escrow → seller wallet.
Funds: Unfilled collateral moves from escrow → seller wallet.
Cancellation applies only to the unfilled portion of an offer. Any fills that already executed are final and cannot be reversed, regardless of subsequent cancellation.
Unlock (Deferred Offers Only)
For deferred (forward) offers, an unlock time is set at creation. When the current block timestamp reaches or exceeds that value, the series enters the redeemable phase. No onchain transaction is required to trigger this transition — the contract evaluates the timestamp at redemption time. Claim tokens issued for this series are now eligible for redemption.Who can act: No action needed; the transition is automatic.
Funds: Collateral remains in escrow until claim holders initiate redemption.
Funds: Collateral remains in escrow until claim holders initiate redemption.
For spot offers, the unlock and redemption steps do not apply. Settlement is immediate and final at fill time — there is no waiting period and no claim tokens are issued.
Redemption (Deferred Offers Only)
Any address holding claim tokens for the unlocked series can redeem. The holder submits a redemption transaction, the protocol burns the specified claim tokens, and releases the underlying collateral directly to the caller on a 1:1 basis. Redemption is fully permissionless — no admin approval, no whitelist, no broker involvement. Multiple holders can redeem independently; each redemption reduces the outstanding claim supply and the series’
Funds: Claim tokens burned; escrowed collateral released 1:1 → claim holder wallet.
backing counter in lockstep.Who can act: Any current claim token holder.Funds: Claim tokens burned; escrowed collateral released 1:1 → claim holder wallet.
State Transition Summary
What triggers each state change?
What triggers each state change?
| Transition | Trigger |
|---|---|
| Created → Open | createOffer succeeds with collateral deposited |
| Open → Partially Filled | Buyer submits a fill for less than the remaining amount |
| Partially Filled → Fully Filled | Buyer submits a fill that consumes all remaining collateral |
| Open / Partially Filled → Expired | block.timestamp >= expiry (fills revert, cancel still available) |
| Open / Partially Filled → Cancelled | Seller calls cancel |
| Filled → Unlocked | block.timestamp >= unlockTime (deferred only) |
| Unlocked → Redeemed | Claim holder calls redeem (deferred only) |
Can a cancelled offer be reinstated?
Can a cancelled offer be reinstated?
No. Cancellation is final for the cancelled portion. If a seller wants to re-offer the returned collateral, they must create a new offer with a new transaction.
Can the unlock time be changed after creation?
Can the unlock time be changed after creation?
No. The unlock time is immutable once the offer is created. This is a deliberate design choice — buyers and claim token holders rely on a fixed settlement horizon when pricing and transferring positions.
What happens when an offer expires?
What happens when an offer expires?
The offer stops accepting fills, but the seller’s collateral remains in escrow. The seller must call
cancel to recover the unfilled portion. Expiry does not trigger automatic collateral return.