For the complete documentation index, see llms.txt. This page is also available as Markdown.

Timelock Contract

OpenZeppelin Timelock Controller (Stellar Contracts v0.7.2) for governance delay on critical protocol actions.

Source: contracts/timelock/

Overview

The Timelock enforces a minimum delay on governance operations. Critical protocol changes (fee updates, asset whitelisting, contract upgrades) must be scheduled, wait for the delay to pass, and then be executed. This gives protocol participants time to review and react.

Operation Lifecycle

Unset → Waiting → Ready → Done
State
Description

Unset

Operation doesn't exist yet

Waiting

Scheduled, waiting for the delay (in ledgers) to pass

Ready

Delay has passed, can be executed

Done

Successfully executed

Roles

Role
Description

Proposer

Can schedule new operations with a delay. Proposers are also automatically granted the Canceller role at construction.

Executor

Can execute operations once they are ready. If no executors are configured, anyone can execute ready operations.

Canceller

Can cancel pending operations before execution

Admin

Can manage roles and update the minimum delay. By default the contract is its own admin (self-administered).

Functions

Function
Role
Description

schedule_op(target, function, args, predecessor, salt, delay, proposer)

Proposer

Schedule an operation; returns the operation id (hash). delay is in ledgers and must be ≥ min_delay.

execute_op(target, function, args, predecessor, salt, executor)

Executor*

Execute a ready operation (external targets). *Anyone if no executors configured.

cancel_op(operation_id, canceller)

Canceller

Cancel a pending operation.

update_delay(new_delay)

Admin

Update the minimum delay (self-administered → goes through the timelock).

get_min_delay()

Current minimum delay (ledgers).

hash_operation(...)

Compute an operation's id.

get_operation_state(id)

Returns the OperationState.

operation_exists(id) / is_operation_pending(id) / is_operation_ready(id) / is_operation_done(id)

State predicates.

The Timelock also exposes the OZ AccessControl interface (grant_role, revoke_role, has_role, …).

Integration with Globals

The Timelock is set as the admin of the Globals contract during deployment (via the two-step transfer_admin_role / accept_admin_transfer). This means:

  • All admin-gated functions on Globals (whitelist_asset, set_factory, upgrade, etc.) require Timelock authorisation

  • To change such a parameter, a Proposer schedules the operation, waits for the delay (in ledgers), then an Executor executes it

  • This prevents instant, unilateral changes to critical protocol parameters

ops_adm-gated functions on Globals (fees, settings, pool-manager approval, delinquency) are not routed through the Timelock — they are gated by the operations-admin role directly.

Self-Administered

The Timelock is deployed self-administered (admin None → the contract is its own admin):

  • No single external address can bypass the time delay

  • The Timelock's own settings (minimum delay, roles) can only be changed through the Timelock itself, via the CustomAccountInterface self-admin path

  • This creates a fully decentralised governance loop

Deployment

  • min_delay — Minimum number of ledgers between scheduling and execution

  • proposers — Addresses that can schedule operations (also granted the canceller role)

  • executors — Addresses that can execute ready operations (empty ⇒ anyone can execute)

  • admin: None — Self-administered (no external admin)

Test Coverage

14 tests covering:

  • Operation lifecycle (schedule → ready → execute)

  • Cancellation before execution

  • Delay enforcement (in ledgers)

  • Role-based access control (incl. proposer-auto-canceller and open-execution-when-no-executors)

  • Integration with the Globals contract (scheduling admin-gated operations)

Last updated