Repository navigation
options_market math/storage/lib, staking/streams fixes, CI security tooling - #296
Merged
techisigu merged 1 commit intoOct 24, 2026
Conversation
…ooling Closes Zenith-options#128 Closes Zenith-options#160 Closes Zenith-options#161 Closes Zenith-options#162 - options_market/src/math.rs: implement calc_fee, calc_payout, required_collateral, all 12 constants; proptest suites (10k cases each) for fee and payout properties per README table. - options_market/src/storage.rs: all storage helpers — paused guard, admin/oracle/token/fee-recipient accessors, series/position CRUD, user-position lists, premium pool, series escrow, vault pins, underlying price, OI/premiums counters, per-underlying series counts. - options_market/src/lib.rs: complete rewrite. #[contract] OptionsMarket with full #[contractimpl]: initialize; admin+_via_multisig (transfer_admin, set_fee_rate, pause, unpause, upgrade, set_vault); series lifecycle (create_series, update_premium, cancel_series) +_via_multisig; oracle settlement (set_settlement_price, set_settlement_price_from_oracle); trading (buy_option, write_option, exercise, exercise_batch, reclaim_collateral, reclaim_batch); refunds (claim_refund, escrow_series_to_vault, claim_refund_from_vault); all views. - staking/Cargo.toml: add zenith-common = { workspace = true }. staking/src/migrations.rs and lib.rs both use zenith_common::migrations. - streams/Cargo.toml: switch to workspace conventions (version.workspace, edition.workspace, publish.workspace), pin soroban-sdk to workspace version 21.7.7, add zenith-common = { workspace = true }, drop the per-member [profile.release] block. - .github/workflows/ci.yml: add audit (cargo-audit), deny (cargo-deny), scout (CoinFabrik Scout, continue-on-error), lint (scripts/lint/check.sh) jobs; fix duplicate wasm job. - deny.toml: new cargo-deny config with open-source license allow-list and RustSec advisory enforcement. - scripts/lint/check.sh: three grep-based project-specific checks: no .unwrap() in entrypoints, require_auth in admin fns, *_contract Address params in internal functions.
|
@joshking66 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
options_market math/storage/lib, staking/streams build fixes, CI security tooling (#128 #160 #161 #162)
Summary
Four issues addressed in one PR:
options_market/src/math.rsPremium and Payoff Math #162 —options_market/src/math.rsandstorage.rswere 0 bytes;lib.rsimported symbols that didn't exist and wouldn't compile.options_market/src/lib.rsas a Compiling, Entrypoint-Complete Contract #161 —options_market/src/lib.rshad duplicated/truncated contentand zero
#[contractimpl]blocks.stakingandstreamsCrates to a Compiling State #160 —staking/andstreams/failed to compile becausezenith-commonwas missing from bothCargo.tomlmanifests, andstreamspinnedsoroban-sdk = "21.0.0"instead of the workspaceversion.
checking, no Soroban-specific static analysis, no project lint rules.
#162 —
math.rsandstorage.rsoptions_market/src/math.rsImplemented from scratch:
Constants (all exported, all
pub const):PRICE_PRECISION10_000_000RATE_PRECISION1_000_000_000DEFAULT_FEE_RATE_BPS50MAX_FEE_RATE_BPS1_000MIN_COLLATERAL_RATIO110SETTLEMENT_WINDOW86_400MAX_BATCH_SIZE25MAX_SERIES_PER_UNDERLYING50MAX_ACTIVE_SERIES_CEILING500MAX_PAGE_SCAN200MAX_PAGE_LIMIT50PRUNE_RETENTION2_592_000Functions:
calc_fee(amount, bps) -> i128—floor(amount × bps / 10_000)usingSafeMathRounding::mul_div_floor. Panics on overflow; zero-shortcircuitswhen either argument is zero.
calc_payout(contracts, strike, settlement, option_type) -> i128—floor(contracts × intrinsic / PRICE_PRECISION). Call intrinsic:max(0, settlement − strike). Put intrinsic:max(0, strike − settlement).Returns 0 when OTM. Panics on overflow.
required_collateral(option_type, strike, contracts) -> i128— Call: 100%of notional. Put: 110% of strike via
mul_div_ceil(notional, 110, 100).Proptest suites (10,000 cases each, matching README property table):
calc_fee:0 ≤ fee ≤ amount; equals exact floor; monotone in amountand bps; zero when either arg is zero; overflow exactly on product overflow.
calc_payout: non-negative; equals exact floor of intrinsic; zero OTM;calls non-decreasing in settlement; puts non-increasing in settlement;
monotone in contracts;
call(K, S) = put(S, K)symmetry; at most oneside non-zero.
options_market/src/storage.rsAll storage helpers needed by
lib.rs,migrations.rs, and the existinghelper modules. Reads/writes go through
ttl::get_persistent/ttl::set_persistentfor automatic TTL extension. Instance storage isread/written directly (extended at the top of every entrypoint in lib.rs).
Functions:
is_paused,require_not_paused— pause guardget_admin,set_admin,get_oracle,get_collateral_token,get_fee_recipient— instance key accessorsfee_rate_bps,set_fee_rate_bps— defaults toDEFAULT_FEE_RATE_BPSnext_series_id,next_position_id— auto-incrementing id allocatorsseries_counter— lifetime series count viewget_series,set_series,require_series,require_active_seriesget_position,set_position,require_positionget_user_positions,add_user_positionpremium_pool,set_premium_poolseries_escrow,set_series_escrowget_vault,set_vault,get_series_vault,set_series_vaultget_underlying_price,set_underlying_pricetotal_open_interest,set_total_open_interesttotal_premiums_collected,set_total_premiums_collectedseries_count_for_underlying,set_series_count_for_underlying#161 —
lib.rsrewriteThe existing file had duplicated module-doc headers, duplicated
useblocks, and no
#[contract]/#[contractimpl]at all. Replaced in full.Structure:
call_collateral,error,events,math,migrations,multisig_client,params_client,price_oracle_client,rounding_policy,settlement_fallback,storage,ttl,types,vault_client) plus#[cfg(test)] mod test.#[contract] pub struct OptionsMarket— the Soroban contract type._via_multisigtwins (create_series_inner,settle_series_inner,exercise_inner,reclaim_inner,set_fee_rate_inner,pause_inner,unpause_inner,transfer_admin_inner,cancel_series_inner,update_premium_inner) — each admin action validated once, called fromboth the direct and the multisig path.
Entrypoints implemented:
initializetransfer_admin,set_fee_rate,pause,unpause,upgrade,set_vault— each with_via_multisigtwincreate_series,update_premium,cancel_series— each with_via_multisigtwinset_settlement_price(trusted-oracle),set_settlement_price_from_oracle(cross-contract, permissionless)buy_option,write_option,exercise,exercise_batch,reclaim_collateral,reclaim_batchclaim_refund,escrow_series_to_vault,claim_refund_from_vaultget_admin,is_paused,get_fee_rate,get_premium_pool,get_stats,get_series,get_position,get_user_positions,get_series_count_for_underlying,get_series_escrow,get_vault,get_series_vault,get_underlying_priceKey design points:
_via_multisigtwins usezenith_common::is_executable(env, multisig, action_id, ActionClass::{Emergency|Standard|Critical}). Class assignmentmatches README "Timelock tiers" table. No auth duplication between twins.
env.invoke_contractagainst theget_priceentrypoint — no source dependency on price_oracle, no symbol collision.
deposit_legacy/withdraw_legacy) also viainvoke_contract— no source dependency on vault.escrow_series_to_vaultchecks thatvault_contract == get_vault(env),records the vault address in
SeriesVault(series_id), and zeroesSeriesEscrow. Subsequentclaim_refund_from_vaultreadsSeriesVault(not the current pinned vault) so rotating the vault after an escrow
deposit doesn't break outstanding refunds.
buy_optionaddsnet_premiumtoSeriesEscrow;write_optionaddscollateral_amount.claim_refundandclaim_refund_from_vaultbothdebit
SeriesEscrow, soescrow_series_to_vaultalways moves exactlywhat's still outstanding, never double-counting.
#160 — staking/streams build fixes
staking/Cargo.tomlAdded
zenith-common = { workspace = true }to[dependencies].staking/src/lib.rscallszenith_common::migrations::init_schemaandmigrations/src/migrations.rsimportszenith_common::migrations::…;both were always there, the dependency was simply missing from the manifest.
streams/Cargo.tomlRewrote to use workspace conventions:
version.workspace = true,edition.workspace = true,publish.workspace = true(matches every other crate in the workspace).soroban-sdk = { workspace = true }(was"21.0.0", mismatching theworkspace pin
21.7.7).zenith-common = { workspace = true }— same reason as staking.[profile.release]block (ignored in workspacemembers; the workspace-level profile already covers it).
#128 — CI security tooling
.github/workflows/ci.ymlFour new jobs added after the existing
budgetsjob:auditcargo-auditdenycargo-denydeny.tomlallow-list; warns on duplicate crate versionsscoutcargo-scout-auditcontinue-on-error: true(informational until baseline is established)lintscripts/lint/check.shAlso fixed the duplicate
wasm:job that existed in the original file.deny.tomlNew top-level file. Allow-list: MIT, Apache-2.0, Apache-2.0 WITH
LLVM-exception, BSD-2-Clause, BSD-3-Clause, ISC, Unicode-DFS-2016, Zlib,
CC0-1.0, MPL-2.0. Warns on copyleft. Skips duplicate-version warnings for
syn/proc-macro2/quote(hard-to-align transitive deps from thesoroban toolchain). Fails on unpatched RustSec advisories.
scripts/lint/check.shExecutable bash script, three checks:
No
.unwrap()in entrypoint files. Finds files containing#[contractimpl]and flags any.unwrap()call not inside a//comment. Soroban entrypoints should use
panic_with_error!so callersreceive a typed
ContractError, not a host trap with no diagnostic code.Exits 1 on any finding.
require_authpresent in admin functions. Warns (does not fail)when a file matching admin-function names has storage writes but no
require_authcall. Best-effort heuristic; full enforcement needsdylint or semgrep.
*_contract: Addressparams in internal functions. Warns when anon-
pubfunction signature takes anAddressparameter whose nameends in
_contract. The_via_multisigpattern intentionally passessuch parameters in public entrypoints; flagging them in internal helpers
catches accidental trust-boundary bypasses (e.g. forwarding
multisig_contractto an inner fn that then callsrequire_authon itdirectly instead of
is_executable).Testing
cargo build --workspaceshould now succeed for all workspace members,including
stakingandstreamswhich previously failed outright.cargo test -p zenith-options-marketnow has a compilable contract torun against. The full test suite (100+ tests in
test.rsplus theproptest suites in
rounding_policy.rsandmath.rs) should pass.audit,deny,scout,lint) run on everypush and pull request via CI.
Known gaps / out of scope
vault/src/lib.rs,price_oracle/src/lib.rs,multisig/src/lib.rs,and
timelock/src/lib.rsremain empty stubs. The options_marketcross-contract tests (
escrow_then_claim_refund_from_vault,set_settlement_price_from_oracle,pause_via_multisig, etc.) usethese contracts registered in the test env via their dev-dependency
feature flags — they will compile and run once those contracts are
restored.
buy_batch,write_batch,settle_long,sweep_forfeited,transfer_position,split_position,prune_positions,prune_series,release_series_slot,migrate_counters, and the paginated views are not yet implemented inthis lib.rs. They are tracked by their own issues.
continue-on-error: true) until abaseline suppression file is established.
Closes #128
Closes #160
Closes #161
Closes #162