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

Timelocks and Execution Delays: Developer Reference

This document provides a deep technical breakdown of the implementation, contract interactions, state machine, and programmatic execution of timelocks within the IPOR Fusion protocol. It is intended for smart contract engineers, audit teams, and automation developers. For high-level conceptual guidance, refer to the Curator Manual.

1. Smart Contract Architecture

The timelock framework in IPOR Fusion is built natively into IporFusionAccessManager, which extends and customizes OpenZeppelin's AccessManager contract.

Every restricted function across the IPOR Fusion ecosystem (including PlasmaVault, PlasmaVaultGovernance, and market connectors) is decorated with the onlyAuthorized modifier. This modifier queries the IporFusionAccessManager to verify if the caller is authorized and whether they must satisfy an execution delay.

2. The Transaction Lifecycle State Machine

A scheduled operation transitions through four distinct state phases inside IporFusionAccessManager:

          ┌──────────────┐
          │    Unset     │
          └──────┬───────┘
                 │ schedule() called

          ┌──────────────┐
          │   Pending    │ ◄─── block.timestamp < scheduledTime
          └──────┬───────┘
                 │ block.timestamp >= scheduledTime

          ┌──────────────┐
          │    Ready     │ ─── cancel() called ──► [ Unset ]
          └──────┬───────┘
                 │ execute() called

          ┌──────────────┐
          │   Executed   │ (Removed from state / closed)
          └──────────────┘

The execution lifecycle of a delayed operation is mathematically bounded by:

Tscheduled=Tproposal+DdelayT_{scheduled} = T_{proposal} + D_{delay}

Where:

  • TproposalT_{proposal} is the block timestamp when schedule() is transactionally processed.

  • DdelayD_{delay} is the configured executionDelay of the calling account-role pairing.

  • TscheduledT_{scheduled} is the earliest timestamp at which execute() can successfully resolve.

3. Operation Hashing & Identification

Every scheduled transaction is tracked using a unique bytes32 digest called the operationId. The operationId is computed by hashing the components of the execution target:

operationId=keccak256(abi.encode(caller,target,data))\text{operationId} = \text{keccak256}(\text{abi.encode}(caller, target, data))

Where:

  • caller: The address initiating the action.

  • target: The address of the destination contract being called.

  • data: The exact encoded execution calldata (function selector + parameters).

This hashing mechanism guarantees that an authorized account can only execute the exact payload that was originally audited and scheduled. Any alteration to the calldata parameters will result in a completely different operationId and fail verification.

4. Programmatic Administration: Set, Edit, and Remove

Developers can programmatically manage individual timelocks or set system floors through the access manager's admin interface. Because these actions are protected, they are subject to any execution delays assigned to the administrator address itself.

A. Setting or Editing an Individual Delay

To set or edit a delay on a specific account, call grantRole with the target executionDelay:

  • Behavior:

    • If the account does not yet possess roleId, the role is granted with the specified executionDelay.

    • If the account already possesses roleId, calling this updates their individual execution delay to the new value.

    • Emits: RoleGranted(roleId, account, executionDelay, newMember)

B. Removing an Individual Timelock

To remove a timelock entirely (enabling instant execution), grant the role with a delay of 0:

  • Result: operatorAddress can now directly call Atomist functions on target contracts without going through the schedule() workflow.

C. Restricting Bypasses via Minimal Role Delays

To establish a global safety floor that prevents any administrator from granting zero-delay configurations, set a minimal delay floor:

  • Validation: Once configured, any subsequent call to grantRole() that attempts to set an executionDelay lower than the registered floor will transactionally revert with the custom error TooShortExecutionDelayForRole(roleId, executionDelay).

  • Emits: MinimalExecutionDelaySet(roleId, delay) per updated role.

5. Technical API Reference

A. Scheduling an Operation

To propose a transaction when subject to a timelock, an account must invoke schedule:

  • Parameters:

    • target: The destination contract address.

    • data: The full encoded payload of the transaction to execute.

    • when: The intended execution timestamp. This value must be equal to or greater than block.timestamp+Ddelayblock.timestamp + D_{delay}.

  • Returns:

    • operationId: The unique cryptographic hash identifying the proposal.

    • delay: The exact delay (in seconds) that must elapse before execution.

B. Executing a Scheduled Operation

Once the delay period has passed, any account can trigger the execution of the scheduled operation by calling execute:

  • Execution Constraints:

    • Reverts with AccessManagerNotReady(operationId) if block.timestamp<Tscheduledblock.timestamp < T_{scheduled}.

    • Reverts with AccessManagerExpired(operationId) if the current time exceeds the expiration threshold (Tscheduled+PERIOD_OF_GRACET_{scheduled} + \text{PERIOD\_OF\_GRACE}, where the standard Grace Period is typically 5 days5\text{ days}).

    • Executes the payload using a low-level solidity call. If the target reverts, execute bubbles up the revert data.

C. Cancelling an Operation

Authorized role administrators or accounts holding the GUARDIAN_ROLE can wipe a pending operation from state:

  • Behavior: Clears the execution timestamp of the operationId from the storage mapping, reverting its status to Unset.

  • Security Guard: A cancelled operation can never be executed. To run the transaction again, it must be scheduled anew, restarting the entire delay countdown.

D. Enforcing Safety Floors

The access manager supports establishing minimum execution delays on a per-role basis to prevent administrative oversight or fast-path exploit pathing:

  • Constraints:

    • roleIds and delays arrays must match in length.

    • Once configured, calling grantRole() with an execution delay below the specified floor will revert.

6. Security Architecture Notes

Self-Referential Timelocks (Admin Constraint)

The administrative capabilities of the IporFusionAccessManager are completely governed by its own permission rules. If an administrative account (e.g., OWNER_ROLE) has an individual delay, it is strictly bound by that delay when performing administrative actions:

Reentrancy & Context Preservation

  • To prevent exploitation of state checks, execute() implements a reentrancy guard or execution lock during the execution of the call.

  • The access manager preserves the execution context using msg.sender routing. When a target contract receives a call, it verifies that msg.sender is the IporFusionAccessManager address, and reads the originating caller context.

7. Code Examples & Scripts

Scenario: Programmatic Scheduling and Execution of a Performance Fee Update

Below is a hardhat/ethers-style script demonstrating how an automation bot or multisig relayer interacts with the timelocked workflow to update performance fees on a PlasmaVault via PlasmaVaultGovernance.

Last updated

Was this helpful?