Vault mechanics
vault.clar is the protocol hub: it holds collateral, mints/burns shares,
runs the weekly round lifecycle, and settles against the oracle. All sBTC
amounts are in sats (1e8 = 1 sBTC); USDC in micro-USDC (1e6 = 1 USDC);
prices / IV / rates in 1e8 fixed point.
Depositing
(deposit (amount uint) (sbtc <sip010>))
A depositor sends sBTC and receives bcSHARE pro-rata (1:1 on the first deposit). The vault:
- checks it is not paused and that the token argument is the configured sBTC,
- requires
amount ≥ min-deposit(defaultu100000= 0.001 sBTC), - computes
shares = amount · supply / total-collateral(or= amountif supply is 0), - harvests any accrued premium for the user (premium-per-share index),
- pulls the sBTC (
contract-call? sbtc transfer …) into the vault, - mints bcSHARE via
bcshare-token.mint, - re-checkpoints the user's premium index and emits a
depositprint event.
The web app attaches a fungible-token post-condition (willSendEq(amount)) so
the wallet guarantees exactly amount sBTC leaves the user.
Withdrawing
(withdraw (shares uint) (sbtc <sip010>))
(request-withdraw (shares uint))
(cancel-withdraw-request (shares uint))
Burning shares returns shares · collateral / supply sBTC — but only the idle
(not call-backed) portion can leave. Collateral locked behind written
contracts in the active round cannot be withdrawn (ERR-LOCKED u115).
request-withdraw queues shares so the matching collateral is excluded from new
call-writing and frees up at the next settlement.
Premium accounting
Premium accrues to depositors through a cumulative premium-per-share index
(acc-premium-per-share, scaled by 1e12). On every balance-changing action the
vault harvests (moves newly accrued premium into the user's pending bucket)
and checkpoints (re-anchors their debt to the current balance). Premium is
claimed in USDC:
(claim-premium (usdc <sip010>))
Round lifecycle
(start-round (otm-bps uint) (iv uint)) ;; keeper only
(buy-call (contracts uint) (usdc <sip010>)) ;; permissionless
(settle-round) ;; keeper from expiry; anyone after the grace window
(exercise (round-id uint) (sbtc <sip010>)) ;; buyer pulls ITM payout
- start-round — the keeper opens a round at
strike = spot · (1 + otm-bps/10000), reading spot from the oracle. Bounds:otm-bps ∈ [otm-min, otm-max],iv ∈ [iv-min, iv-max]. The previous round must be settled. - buy-call — anyone buys
contracts1-sBTC calls. The premium is priced live bybs-math.bs-call-pricefrom current spot, the round's strike/IV, the remaining tenor, and the risk-free rate, then converted to micro-USDC. The buyer's USDC is pulled in; premium accrues to depositors immediately. You can never buy more thancontracts-available(whole idle sBTC, minus queued-withdrawal collateral). - settle-round — after expiry, settles against the oracle. The settlement
price must postdate expiry (
ERR-STALE-SETTLEMENT u122). Computespayout-per-contract = (S_exp − K)/S_exp(0 ifS_exp ≤ K), reserves the total payout out of collateral. - exercise — each ITM buyer pulls their
payout-per-contract · contractssBTC. Always less than 1 sBTC per contract, so the pool stays solvent.
Always fully collateralized
Because a contract's maximum payout is (S_exp − K)/S_exp < 1 sBTC and the pool
writes at most one contract per whole idle sBTC it holds, settlement is always
covered by collateral already in the vault. No external liquidity, no liquidation
engine, premium only flows in.
Admin & RBAC
set-keeper, set-owner, pause / unpause, set-config, and set-tokens
are owner-gated (keeper-gated for start-round). pause blocks
deposits / buys / round-starts, but leaves withdrawals, claims, settlement and
exercise open — pausing can never trap user funds. set-tokens only works
before any shares exist.
Read-only views
get-vault-state, get-round, get-position, get-user, preview-deposit,
preview-withdraw, preview-quote, preview-quote-current, contracts-available,
get-config. The web app's chain-direct mode reads these directly.
Error codes
u100 paused · u101 min deposit · u102 round active · u103 round not
active · u104 expired · u105 not expired · u106 insufficient coverage ·
u107 not keeper · u108 not owner · u109 stale price · u110 bad price ·
u111 transfer failed · u112 wrong token · u113 zero amount · u114
insufficient shares · u115 locked by round · u116 no position · u117
already claimed · u118 not settled · u119 bad params · u120 nothing to
claim · u121 settle in grace (keeper-only window) · u122 settlement price
predates expiry · u401 bcSHARE not authorized · u1001 BS domain.