STRYK
Documentation

How the reservoir is engineered.

Everything below is the protocol as shipped: the four runtime layers, the weekly vault lifecycle, the fixed-point pricing math, and the failure modes each design decision guards against.

01

Architecture

STRYK is a monorepo of three on-chain Rust crates and a family of TypeScript packages that share a single Anchor executor. Water flows through four layers, in order:

  1. 01

    Pricing engine

    crates/pricing

    Q64.64 Black-Scholes for calls and puts, plus first-order Greeks, plus an IV surface interpolator. No floating-point unit required.

  2. 02

    Vault library

    crates/vault

    Five reference strategies, each implementing a shared VaultStrategy trait. New strategies plug in without redeploying the executor.

  3. 03

    Auction layer

    crates/auction

    Batch Dutch auction with a linear price decay, $STRYK collateral, and slashing on default.

  4. 04

    Executor program

    Anchor

    Owns vault PDAs, holds LP shares as SPL tokens, and dispatches strategy calls plus Zeta / Drift CPIs.

Trust model

The executor is upgradeable behind a multi-sig authority. Strategies are compile-time registered, so a strategy change is a program upgrade — never a runtime set_authorityon an escrow. The auction layer's slashing is enforced by the same authority.

Determinism

All pricing math is Q64.64 with in-house exp, ln, sqrt, and norm_cdf routines. Property tests confirm put-call parity within 1e-5 across the sampled input grid. Because no floating-point is used, replaying a settlement instruction on the same block always yields the same result — a hard requirement for the on-chain auction refund path.

02

Vault specification

Every STRYK reservoir shares the same executor and lifecycle. A strategy implementer sees one trait:

pub trait VaultStrategy {
    fn kind() -> StrategyKind;
    fn compute(ctx: StrategyContext) -> Result<StrategyDecision, VaultRuntimeError>;
}

StrategyContext supplies the oracle inputs — spot, IV, time-to-expiry, risk-free rate, perp funding — all as Q64 fixed-point values, so the strategy is deterministic. StrategyDecision returns the strike, the is_call flag, the premium target for the auction, and an optional hedge size for delta-neutral strategies.

Lifecycle: one week, five events

01 · Impound

LP deposits are held in an escrow account owned by the vault PDA. Deposits mint share SPL tokens to the LP.

02 · Strike

The executor calls compute on the strategy struct to pick the next strike. Covered calls target 15-delta OTM; cash-secured puts target 15-delta OTM on the put side. Delta-neutral vaults size the hedge instead of picking a strike.

03 · Auction

The auction layer opens with initial_price = premium x 1.1 and decays to reserve_price = premium x 0.9 over 15 minutes.

04 · Settle

On expiry the executor books P&L, applies the performance fee (default 2%), distributes the net premium to LPs, and re-arms the next epoch window.

05 · Roll

open_epoch fires again the following Friday. No operator intervention at any point in the cycle.

Adding a new strategy

Create a struct implementing VaultStrategy, add it to the enum in strategy.rs, and add a match arm in the executor's dispatch. That is the entirety of the on-chain surface for a new reservoir.

03

Pricing specification

STRYK implements Black-Scholes-Merton in Q64.64 fixed-point. Q64 wraps an i128: the upper 64 bits are the signed integer part, the lower 64 the fraction. Range is roughly ±9.22e18 with about 19 fractional digits of precision. Multiplication is a widening 256-bit multiply-then-divide-by-scale; both multiply and divide return None on overflow rather than wrapping.

Transcendentals

sqrt

Newton-Raphson iteration; 30 iterations give a stable double-precision result within the test envelope.

exp

Range-reduces to [-ln 2, ln 2], evaluates an 11-term Taylor series, then adds k * ln 2 back as a power-of-two shift.

ln

Reduces to a mantissa in [1, 2) and applies the classic 2(y + y^3/3 + y^5/5 + ...) series with y = (m - 1) / (m + 1).

norm_cdf

Abramowitz & Stegun 26.2.17 for x >= 0 with the symmetry identity N(-x) = 1 - N(x). Empirical error against SciPy is under 1e-6.

Outputs

price_call and price_put return the premium, d1, d2, and the discount factor. greeks_call and greeks_put return delta, gamma, theta, vega, and rho. The IV surface holds (strike, expiry, iv) triples with bilinear interpolation — first across strikes at each bracketing expiry, then across expiries.

The same engine is queryable off-chain through the API the spillway simulator uses:

POST /simulate
{ "vault_kind": "weekly_sol_covered_call", "amount_usd": 10000, "lockup_weeks": 4 }

GET /pricing?spot=172&strike=185&iv=0.78&days=7&kind=call
04

Security model

STRYK is engineered for mainnet stakes — the executor runs live on Solana devnet ahead of the mainnet release. Every design decision below is made with a concrete failure mode in mind.

Determinism

Every pricing and settlement instruction uses only fixed-point arithmetic, only account state, and only oracle inputs read at instruction execution. No randomness, no clock drift, no external HTTP.

Oracle assumptions

Spot prices come from Pyth. If the confidence interval exceeds a per-strategy threshold, the executor pauses the affected vault instead of using stale prices. IV feeds fall back to a rolling 7-day realised variance stored in the vault PDA.

Upgrade authority

The executor lives behind a multi-sig upgrade authority. Strategy crates are compile-time registered, so any strategy change is an executor upgrade — there is no runtime set_strategy path.

Auction defaults

Market makers post collateral in $STRYK against every bid. On default the auction layer slashes the collateral and refunds LPs at the failed clearing price. Defaults are detected on the settlement path, not out of band.

Emergency pause

emergency_pause freezes deposits and blocks new auctions on a single vault without touching LP funds. Withdrawals remain possible, so LPs are never trapped.

Report security issues privately at security@stryk.fi.

Go deeper