Skip to content

feat: timelock tiers, multisig custom account, zenith-common crate, vault escape hatch - #150

Merged
dami-005 merged 2 commits into
Zenith-options:mainfrom
knytcomics-ui:feature/76-77-78-81-governance-hardening
Sep 29, 2026
Merged

dami-005 merged 2 commits into
Zenith-options:mainfrom
knytcomics-ui:feature/76-77-78-81-governance-hardening

Conversation

@knytcomics-ui

Copy link
Copy Markdown

Summary

  • [High] Timelocked Execution Tiers per Action Class #76 Timelock tiers: multisig tracks threshold_reached_at (set when an approval crosses threshold, cleared on a revoke that drops below it or on reset; if an approval expires during the delay, the timer restarts). is_executable(action_id, class) enforces immutable per-class delays set at initialize (Emergency = 0, Standard, Critical). Every consumer _via_multisig fn declares its class (pause = Emergency; upgrade/transfer_admin/vault fund moves = Critical; everything else = Standard). The delay table is in the README.
  • [High] Multisig as a Soroban Custom Account (__check_auth) #77 Custom account: CustomAccountInterface::__check_auth on multisig. It requires M distinct ed25519 signer signatures, sorted strictly ascending (so duplicates, unsorted lists and non-signer keys are rejected), with an optional allowed_contracts policy. It works alongside approval mode; the README covers when to use which, plus a CLI signing walkthrough.
  • [High] Deduplicate the _via_multisig Pattern with a Shared zenith-common Crate #78 zenith-common: new rlib with require_admin_or_multisig(env, key, Auth, class, err), enum Auth { Admin, Multisig(..) }, and pause/admin helpers. It defines no #[contract] and exports no spec entries. All 21 twins are now x_inner(env, Auth, ..) called from both entrypoints. Multisig is called with invoke_contract, so the per-crate multisig_client.rs files and the multisig wasm build-order dependency are gone.
  • [High] Beneficiary Escape Hatch After Prolonged Vault Pause #81 Vault escape hatch: initialize(.., max_pause_duration) (immutable), PausedAt plus cumulative pause accounting (brief unpause/re-pause doesn't reset the clock; only a full unpaused window does), first depositor = tag owner, set_beneficiary (blocked while paused), emergency_withdraw(tag, beneficiary) and an emergency_withdrawn event.

Closes #76
Closes #77
Closes #78
Closes #81

ABI / wasm size (#78)

New CI job spec-diff (tools/spec-diff/check.sh) diffs each contract's spec against the base branch:

Validation

  • cargo fmt --check and cargo clippy --all-targets -D warnings pass on every crate.
  • cargo test passes: multisig 45, price_oracle 62, vault 48, options_market 110. The existing tests only needed the new initialize args.
  • New tests:
    • Per-class delay boundaries, revoke and expiry during the delay, and the emergency bypass.
    • __check_auth with real ed25519 keys: duplicate, unsorted and non-signer signatures, and the policy.
    • Integration: options_market with admin = multisig account performs initialize/set_fee_rate/pause/upgrade through signed auth entries, with no mock_all_auths.
    • Vault escape hatch: time travel across the threshold and the pause/unpause reset attack.

…ault escape hatch

- multisig: per-class timelock (Emergency/Standard/Critical) via
  is_executable(action_id, class) with threshold_reached_at tracking;
  CustomAccountInterface::__check_auth for M-of-N ed25519 auth with an
  optional allowed-contracts policy
- common: new zenith-common rlib with require_admin_or_multisig(Auth),
  pause and admin helpers; every admin fn is a single x_inner shared by
  both entrypoints; per-crate multisig contractimport clients removed
- vault: cumulative-pause escape hatch (emergency_withdraw after
  max_pause_duration), tag owners and beneficiaries
- CI: spec-diff ABI guard + wasm size report; README updated

Closes Zenith-options#76
Closes Zenith-options#77
Closes Zenith-options#78
Closes Zenith-options#81
@drips-wave

drips-wave Bot commented Sep 28, 2026

Copy link
Copy Markdown

@knytcomics-ui 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! 🚀

Learn more about application limits

…-governance-hardening

# Conflicts:
#	.github/workflows/ci.yml
#	README.md
#	multisig/src/error.rs
#	multisig/src/lib.rs
#	multisig/src/test.rs
#	multisig/src/types.rs
#	options_market/src/lib.rs
#	options_market/src/storage.rs
#	options_market/src/test.rs
#	price_oracle/src/lib.rs
#	vault/src/error.rs
#	vault/src/events.rs
#	vault/src/lib.rs
#	vault/src/test.rs
#	vault/src/types.rs
@dami-005
dami-005 merged commit f95d8d4 into Zenith-options:main Sep 29, 2026
dami-005 pushed a commit that referenced this pull request Sep 30, 2026
…ion (#151)

- multisig: restore source wiped in #150 (from #149, de-duplicated and
  made consistent on BytesN<32> action ids)
- multisig: per-signer weights, initialize_weighted, get_approval_weight;
  legacy initialize keeps equal weights (#70)
- multisig: propose/queue/veto/execute_signer_change with a higher
  rotation threshold, mandatory delay, single-signer veto, invariant
  re-validation and epoch-keyed approvals (#69)
- lp_token: SEP-41 share token, mint restricted to the pinned lp_pool (#65)
- lp_pool: epoch-queued deposits/withdrawals, keeper option writing
  within series and utilization caps, virtual-share inflation defence (#64)
- CI matrices, README and docs updated

Closes: #64
Closes: #65
Closes: #69
Closes: #70
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants