Skip to content

Reconstruct the timelock Crate: Proposer/Executor/Canceller Roles and Predecessor Dependencies #166

Closed

Description

@dami-005

Description:
timelock/ is empty end to end apart from a migrations shim, despite README.md describing a full delayed-execution admin with proposer/executor/canceller roles and predecessor dependencies. Rebuild the crate to match that documented design.

Problem Statement & Context:
The timelock is the mechanism meant to hold the admin role on the other contracts so users always get an exit window before a destructive admin action lands. Without it, every other contract in the protocol has a single immediately-acting admin: Address as its sole point of control — a foundational safety gap, not a nice-to-have.

Scope & Acceptance Criteria:

  • initialize establishing the three roles (and compatibility with common's admin/multisig pattern where applicable).
  • schedule/propose, execute, and cancel entrypoints with a configurable delay, role-gated per the README's table.
  • Predecessor dependency support: an operation with an unexecuted predecessor cannot execute.
  • Contract errors and lifecycle events for scheduled, executed, and cancelled operations, plus a readable operation id scheme.
  • The existing migrations shim is preserved and still functions.
  • Out of scope: assigning the timelock as admin on options_market/price_oracle/vault (separate integration issue).

Implementation Guidelines:

  1. Key Files/Modules: timelock/src/lib.rs and its supporting types/events/error/test modules, plus the existing migrations shim.
  2. Design/Architecture: store scheduled operations in persistent storage keyed by an operation id derived from the target, payload, and nonce; enforce roles on every entrypoint; make the delay a settable parameter with a documented minimum.
  3. Edge Cases/Constraints: executing before the delay elapses must fail; double-execution must fail; cancelling an already-executed or nonexistent operation must fail; cancelling a predecessor should not leave a dependent operation executable; ensure the delay boundary condition (exactly at eta) is decided and tested.
  4. Testing: unit tests for each role's authorization failures, the delay boundary (just before and exactly at eta), cancel-before-execute, execute-after-cancel, predecessor ordering (dependent blocked until predecessor executes), and re-execution rejection.

Definition of "Done":

  • Code written, tested, and documented.
  • All acceptance criteria met.
  • PR submitted with a clear description, passing CI, relevant screenshots/test output.
  • Code reviewed and approved.

Resources:

  • README.md (timelock/ crate section) for the documented role table and delay semantics.

Complexity: High (200 points)

Activity

  1. tesleem-28 commented on Oct 18, 2026

    @tesleem-28
    Contributor

    @tesleem-28 has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    Hello Maintainer, I carefully examined the issue and understand what the final behavior should look like. I'll work on a maintainable implementation and cover the relevant scenarios.

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @tesleem-28 to this issue.

  2. josephamly36-commits commented on Oct 18, 2026

    @josephamly36-commits
    Contributor

    @josephamly36-commits has applied to work on this issue as part of the Stellar Wave Program's 10th wave.

    hello mainatiner ,I would like to contribute to this issue. My experience includes application architecture, performance optimization, testing, and deployment workflows. I focus on writing maintainable and scalable code.

    ℹ️ Repo Maintainers: To accept this application, review their application or assign @josephamly36-commits to this issue.

  3. drips-wave commented on Oct 18, 2026

    @drips-wave

    Congratulations, @tesleem-28! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.

    🧑‍💻 @tesleem-28: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.

    Warning

    When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.

    🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.

    🌊 Happy Wave 🌊

  4. AminMG044 commented on Oct 19, 2026

    @AminMG044

    PR

    #294 — rebuilds
    timelock/ to match the design README.md documents, and wires the
    existing migrations shim back in.

    What it does

    • initialize(min_delay, proposers, executors, cancellers) — one-time setup,
      no admin afterwards. An empty executors list means anyone may execute a
      ready operation.
    • schedule(proposer, calls, predecessor, salt, delay) -> id — proposer-only.
      The id is sha256(xdr((calls, predecessor, salt))), so it commits to the
      whole payload and hash_operation derives it off-chain, before anything is
      scheduled.
    • execute(executor, calls, predecessor, salt) — executor-only (unless open).
      The operation is identified by the content the executor repeats, which
      hashes to the id that was scheduled. Every call runs in order; a revert in
      any of them reverts the whole batch.
    • cancel(canceller, id) — canceller-only.
    • Self-administration through delayed operations: update_delay(u64),
      grant_role(Role, Address), revoke_role(Role, Address),
      set_open_executor(bool), and migrate(u32, u32) for the shim.
    • The views, events and error codes the README names, with the same numbers
      (1–9, plus the migration codes 100–104 every Zenith contract carries).

    Two decisions the issue asked to be pinned down

    • The delay boundary is inclusive. An operation may be executed at
      exactly its ready-at, and not before. Both sides of the boundary are
      tested.
    • A cancelled predecessor can never run, so neither can its dependent.
      Cancelling a predecessor therefore never leaves a dependent executable —
      it has to be cancelled as well, which is the one thing a canceller has to
      notice.

    The migrations shim

    The step registry, require_current and self_migrate are untouched. The
    crate now declares mod migrations;, carries the migration error variants,
    writes the schema version in initialize, and dispatches the migrate
    self-call — the four things the shim's own note asked for.

    One thing this PR also has to carry

    The workspace had no root Cargo.lock, so cargo resolved
    ed25519-dalek to 3.0.0 for soroban-env-host (whose >=2.0.0
    requirement admits it) and the build failed with a ChaCha20Rng: CryptoRng
    error before a single test could run. The lockfile pins it to the 2.x line
    the workspace already asks for, which is what lets the timelock's own CI
    jobs (clippy, wasm, test) build at all.

    Verification

    cargo test -p zenith-timelock          ✅ 23 passed | 0 failed
    cargo fmt --check (timelock/)          ✅ clean
    cargo clippy -p zenith-timelock --all-targets -- -D warnings   ✅ no warnings
    cargo build -p zenith-timelock --target wasm32-unknown-unknown --release   ✅
    

    Out of scope, as the issue says

    Assigning the timelock as admin on options_market / price_oracle /
    vault, and the handover scripts in scripts/governance/, which still speak
    the old timelock interface (schedule(op_id, targets, fns, args, delay),
    get_proposer, get_guardian). Those scripts were already broken — the
    crate was empty — and re-pointing them belongs with the integration issue.

    Maintainer note: the whole-workspace fmt / clippy / wasm CI jobs
    are red on main before this change, for reasons owned by other issues:
    price_oracle, vault and options_market are still stubs (#147, #148,
    #149) and streams / staking / test_adversaries do not compile. The
    timelock's own gates are green.

  5. added a commit that references this issue on Oct 19, 2026
    82f0033
  6. added a commit that references this issue on Oct 19, 2026
    c900d1d
  7. added a commit that references this issue on Oct 19, 2026
    408294a
  8. drips-wave commented on Oct 24, 2026

    @drips-wave

    This issue has been completed by @tesleem-28 as part of the Stellar Wave Program's 10th Wave 🥳

    😎 @tesleem-28: You earned 200 Points for completing this issue! Once the Wave's rewards are finalized, you'll be eligible for a percentage of the Wave's reward pool based on the percentage of total points you've earned. Learn more here. You can also Leave a review to share your experience working on this issue.

    🧑‍💻 Repo maintainers: How'd the contributor do? Leave a review to share your experience working with them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Stellar WaveIssues in the Stellar wave program

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions