Series Lifecycle
On this page
A series progresses from subscription through strike and observations to a terminal outcome. Redemption depends on the recorded state and asset-transfer availability, not merely on whether an entry point is paused.
fact The six stages are:
- Creation: terms and scheduled observations are recorded.
- Subscription: COUPON deposits USDG; SHIELD deposits stock and USDG prefund.
- Strike: the core fixes the strike price, matches notional and records refunds.
- Live: qualifying observations accrue coupons and may trigger autocall.
- Autocall or maturity: the core fixes the settlement entitlement.
- Claims and redemption: holders pull accrued coupons, refundable deposits and terminal payouts.
Status Machine
fact INoteCore.Status { None, Subscription, Live, Autocalled, Matured, Cancelled, Unwound }
1. Creation
createSeries(SeriesParams p) is an onlyOwner call (pausable). _validateParams reverts InvalidParams(reason) unless:
underlyinghas 18 decimals andfeedhas 8 decimals; neither is the zero address.0 < barrierBps <= autocallBps(reason"barrier").couponFloorBps <= couponCapBps <= maxCouponCapBps(400) andcouponCapBps > 0("coupon bounds");refBps > 0("refBps").refBpsis not required to lie inside the floor/cap band; discovery clamps it.notionalCap > 0,minTicket > 0,minTicket <= notionalCap("notional").observationshas2 <= length <= maxObservations(64), is strictly ascending, and every timestamp passesMarketCalendar.isOfficialClose.subscriptionEnd > block.timestampandobservations[0] > subscriptionEnd.
Fees in force at creation (couponFeeBps, notionalFeeBps) are snapshotted into the series and never change afterwards. Status becomes Subscription.
2. Subscription
| Call | Who | Effect |
|---|---|---|
depositCoupon(seriesId, quoteAmount) | Anyone, >= minTicket (BelowMinTicket) | Transfers USDG into escrow, increments totalCouponDeposits (D) |
depositShield(seriesId, stockAmount, prefundQuote) | Anyone | Transfers Stock Tokens and USDG prefund; the amount booked is the stock actually received by the core (ZeroAmount if nothing arrives) and prefundQuote >= requiredPrefund(seriesId, received) (valued at the provisional price, else InsufficientPrefund). The whole prefundQuote is escrowed to the position; ShieldDeposited reports the received amount |
DeskPolicy.fill(seriesId) | Anyone, inside the fill window (last fillLead of Subscription), only when S > D and the series is inside the published rule for its underlying | Desk subscribes to COUPON under its caps, sized to the rule's coupon hurdle and never past the SHIELD gap, as a reserved deposit (Desk.fillCoupon(seriesId, amount, minCouponBps) posting NoteCore.depositCouponReserved); caller receives the policy bounty |
Deposits are final until strike. There is no withdrawal during Subscription; unmatched amounts are refundable after strike. Deposits revert after subscriptionEnd, and also from the effective strike close onward when a calendar change has rolled the strike observation to a close earlier than subscriptionEnd (SubscriptionClosed in both cases). The effective deadline is min(subscriptionEnd, effectiveObservationTs(seriesId, 0)); getSeries keeps reporting the recorded subscriptionEnd.
3. Strike
finalizeStrike(seriesId) is permissionless once block.timestamp >= effectiveObservationTs(seriesId, 0) (the scheduled strike close, or the close it rolled to).
- If
D == 0orS == 0or the strike observation was cancelled by governance, or the computed matchN == 0: statusCancelled(SeriesCancelled), everything refundable. - Otherwise read
s0viaOracleAdapter.observe(feed, observations[0]). If the oracle returnsok == false, emitStrikeDeferredand stop; anyone may retry. - Compute
Sats0. If the series carries a reserved deposit (a Desk fill with hurdleh), reduceDtomax(others, min(D, refBps × S / h)), whereothersis the COUPON of every other account, by excluding part of the reserve account’s deposit only (ReserveExcluded(seriesId, excluded, included)); the excluded quote becomes that account’s refund. ThenN = min(D, S, notionalCap, prefundCapacity)andcouponBps(see Coupon discovery). - Book
matchedNotional,stockMatched,prefundRemaining, the notional fee intoaccruedFees, unmatched amounts as refundable. StatusLive,nextObs = 1. - Credit the keeper reward to the keeper (
keeperOwed), pulled later withclaimKeeperReward()so a rejecting keeper address can never block the observation.
Legs are minted lazily: settle(seriesId, account) (permissionless, callable for any account) computes the account’s pro-rata match, mints COUPON or SHIELD units to it and books its refund. claim, redeem and refund settle the caller first.
4. Live
observe(seriesId) processes observations[nextObs] once block.timestamp >= closeTs. Outcomes are described in Observation. Each successful observation increments nextObs and pays the keeper. A Deferred observation leaves nextObs unchanged.
5. Autocalled or Matured
- Autocalled (intermediate observation,
P >= autocall): coupon accrued,shieldUnusedPerUnitfixed fromprefundRemaining. - Matured (last observation): if barrier holds, coupon accrued and
breached = false; elsebreached = true. A maturity observation cancelled by governance settles atlastPrice.
6. Claims, Redemptions, Refunds
| Call | Available when | Pays |
|---|---|---|
claim(seriesId) | Live, Autocalled, Matured | Accrued net coupons on the caller's COUPON units |
redeem(seriesId, units) | Autocalled, Matured, or Unwound after strike | COUPON: one raw USDG unit per raw leg unit, or stock using the strike price and quote rate if breached |
redeemShield(seriesId, units) | Autocalled, Matured, or Unwound after strike | SHIELD: stock plus unused prefund, or one raw USDG unit per raw leg unit plus unused prefund if breached |
refund(seriesId) | Live, Autocalled, Matured, Cancelled | Unmatched COUPON USDG, unmatched Stock Tokens, unmatched prefund |
sweepFees(seriesId) | Any status | sweepableFees(seriesId) (accruedFees less keeperReserve, the keeper rewards of the cranks still due) to feeSink; NoFees when zero |
writeOffDust(seriesId, to) | Cancelled, Autocalled, Matured, Unwound; owner | Moves the remaining escrow of the series to to when it is at most dustLimitQuote() (0.01 USDG) and DUST_LIMIT_STOCK (1e-6 of a Stock Token); NotDust otherwise; emits DustWrittenOff |
All accounting is pull-based. There is no deadline for redemption; escrowed assets wait for their holder.
Pausing
Governance can pause new series, deposits, strikes and observations. Claims, refunds and redemption entry points are not pause-gated, but their state conditions still apply. A live series does not become redeemable merely because the core is paused.
fact Ordinary leg redemption requires Autocalled, Matured, or Unwound after strike. With six-decimal USDG, 1,000,000 raw leg units represent 1 USDG of notional. Token restrictions or failed transfers can still prevent receipt. See Governance and Issuer Risk.
Keep exploring, or revisit this topic from the navigation.