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.
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:
- 01
Pricing engine
crates/pricingQ64.64 Black-Scholes for calls and puts, plus first-order Greeks, plus an IV surface interpolator. No floating-point unit required.
- 02
Vault library
crates/vaultFive reference strategies, each implementing a shared VaultStrategy trait. New strategies plug in without redeploying the executor.
- 03
Auction layer
crates/auctionBatch Dutch auction with a linear price decay, $STRYK collateral, and slashing on default.
- 04
Executor program
AnchorOwns 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.
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
LP deposits are held in an escrow account owned by the vault PDA. Deposits mint share SPL tokens to the LP.
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.
The auction layer opens with initial_price = premium x 1.1 and decays to reserve_price = premium x 0.9 over 15 minutes.
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.
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.
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
Newton-Raphson iteration; 30 iterations give a stable double-precision result within the test envelope.
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.
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).
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=callSecurity 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.