Series Lifecycle

Documentation snapshot 18 October 2026. Deployment · Audit Status
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:

  1. Creation: terms and scheduled observations are recorded.
  2. Subscription: COUPON deposits USDG; SHIELD deposits stock and USDG prefund.
  3. Strike: the core fixes the strike price, matches notional and records refunds.
  4. Live: qualifying observations accrue coupons and may trigger autocall.
  5. Autocall or maturity: the core fixes the settlement entitlement.
  6. Claims and redemption: holders pull accrued coupons, refundable deposits and terminal payouts.

Status Machine

fact INoteCore.Status { None, Subscription, Live, Autocalled, Matured, Cancelled, Unwound }

Series status machine Subscription deposits open Live observing Autocalled principal + coupon Matured cash or physical Cancelled all refundable Settled claims collected finalizeStrike observe: P ≥ autocall observe: last index D = 0 or S = 0 redeem / refund
fact "Settled" is not an on-chain status. It describes completion of holder claims, redemptions and refunds; rounding residues can remain. Autocalled and Matured are terminal.

1. Creation

createSeries(SeriesParams p) is an onlyOwner call (pausable). _validateParams reverts InvalidParams(reason) unless:

  • underlying has 18 decimals and feed has 8 decimals; neither is the zero address.
  • 0 < barrierBps <= autocallBps (reason "barrier").
  • couponFloorBps <= couponCapBps <= maxCouponCapBps (400) and couponCapBps > 0 ("coupon bounds"); refBps > 0 ("refBps"). refBps is not required to lie inside the floor/cap band; discovery clamps it.
  • notionalCap > 0, minTicket > 0, minTicket <= notionalCap ("notional").
  • observations has 2 <= length <= maxObservations (64), is strictly ascending, and every timestamp passes MarketCalendar.isOfficialClose.
  • subscriptionEnd > block.timestamp and observations[0] > subscriptionEnd.

Fees in force at creation (couponFeeBps, notionalFeeBps) are snapshotted into the series and never change afterwards. Status becomes Subscription.

2. Subscription

fact 2. Subscription
CallWhoEffect
depositCoupon(seriesId, quoteAmount)Anyone, >= minTicket (BelowMinTicket)Transfers USDG into escrow, increments totalCouponDeposits (D)
depositShield(seriesId, stockAmount, prefundQuote)AnyoneTransfers 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 underlyingDesk 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).

  1. If D == 0 or S == 0 or the strike observation was cancelled by governance, or the computed match N == 0: status Cancelled (SeriesCancelled), everything refundable.
  2. Otherwise read s0 via OracleAdapter.observe(feed, observations[0]). If the oracle returns ok == false, emit StrikeDeferred and stop; anyone may retry.
  3. Compute S at s0. If the series carries a reserved deposit (a Desk fill with hurdle h), reduce D to max(others, min(D, refBps × S / h)), where others is 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. Then N = min(D, S, notionalCap, prefundCapacity) and couponBps (see Coupon discovery).
  4. Book matchedNotional, stockMatched, prefundRemaining, the notional fee into accruedFees, unmatched amounts as refundable. Status Live, nextObs = 1.
  5. Credit the keeper reward to the keeper (keeperOwed), pulled later with claimKeeperReward() 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, shieldUnusedPerUnit fixed from prefundRemaining.
  • Matured (last observation): if barrier holds, coupon accrued and breached = false; else breached = true. A maturity observation cancelled by governance settles at lastPrice.

6. Claims, Redemptions, Refunds

fact 6. Claims, Redemptions, Refunds Reference
CallAvailable whenPays
claim(seriesId)Live, Autocalled, MaturedAccrued net coupons on the caller's COUPON units
redeem(seriesId, units)Autocalled, Matured, or Unwound after strikeCOUPON: 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 strikeSHIELD: stock plus unused prefund, or one raw USDG unit per raw leg unit plus unused prefund if breached
refund(seriesId)Live, Autocalled, Matured, CancelledUnmatched COUPON USDG, unmatched Stock Tokens, unmatched prefund
sweepFees(seriesId)Any statussweepableFees(seriesId) (accruedFees less keeperReserve, the keeper rewards of the cranks still due) to feeSink; NoFees when zero
writeOffDust(seriesId, to)Cancelled, Autocalled, Matured, Unwound; ownerMoves 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.

A little more clarity?

Keep exploring, or revisit this topic from the navigation.