UNPKG

@hyperlane-xyz/core

Version:

Core solidity contracts for Hyperlane

226 lines (165 loc) 7.18 kB
# TimelockRouter TimelockRouter is a timelock mechanism that delays message processing by a fixed time window. It provides time for off-chain observation and watcher intervention, but does not inherently provide fraud proofs or pausing capabilities. ## 1. Timelock Architecture TimelockRouter serves **three roles** in the message lifecycle: ```mermaid %%{ init: { "theme": "neutral", "themeVariables": { "mainBkg": "#025AA1", "textColor": "white", "clusterBkg": "white" }, "themeCSS": ".edgeLabel { color: black }" }}%% graph LR subgraph "Origin Chain" OR1[TimelockRouter] style OR1 fill:orange end subgraph "Destination Chain" OR2[TimelockRouter] style OR2 fill:orange end OR1 -. "1. Hook Role<br/>postDispatch()" .-> OR1 OR1 -. "2. Router Role<br/>sends messageId" .-> OR2 OR2 -. "3. ISM Role<br/>verify()" .-> OR2 ``` **How it works:** 1. **Hook Role (Origin)**: When a message is dispatched, TimelockRouter sends a preverification message containing only the messageId to the destination chain 2. **Router Role (Destination)**: Receives the preverification message via `handle()` and stores `readyAt[messageId] = block.timestamp + timelockWindow` 3. **ISM Role (Destination)**: When the actual message arrives, `verify()` checks that `readyAt[messageId] <= block.timestamp` before allowing processing **Two messages per transfer:** - **Message 1 (Preverification)**: Sends messageId to destination, starts timelock timer - **Message 2 (Actual Message)**: Delivers after timelock expires, verified by ISM **Storage:** ```solidity mapping(bytes32 => uint48) public readyAt; uint48 public immutable timelockWindow; ``` ## 2. WarpRoute with Timelock Configure WarpRoute to use TimelockRouter as both hook and ISM: ```solidity warpRoute.setHook(address(timelockRouter)); warpRoute.setInterchainSecurityModule(address(timelockRouter)); ``` **Test flow** (from `test_warpRouteFlow`): ```mermaid %%{ init: { "theme": "neutral", "themeVariables": { "mainBkg": "#025AA1", "textColor": "white", "clusterBkg": "white" }, "themeCSS": ".edgeLabel { color: black }" }}%% graph TB User((User)) style User fill:black subgraph "Origin Chain" WarpRoute_O[WarpRoute] style WarpRoute_O fill:green TLRouter_O[TimelockRouter<br/>Hook] style TLRouter_O fill:orange Mailbox_O[(Mailbox)] end subgraph "Destination Chain" TLRouter_D[TimelockRouter<br/>ISM + Router] style TLRouter_D fill:orange WarpRoute_D[WarpRoute] style WarpRoute_D fill:green Mailbox_D[(Mailbox)] end Fail1[❌ Step 2: Try process msg 1<br/>REVERTS: not preverified] style Fail1 fill:red,color:white Fail2[❌ Step 4: Try process msg 1<br/>REVERTS: not ready] style Fail2 fill:red,color:white Success[✓ Step 6: Process msg 1<br/>SUCCESS: tokens delivered] style Success fill:green,color:white %% Step 1: Transfer User == "Step 1: transferRemote(amount)<br/>→ dispatches 2 messages" ==> WarpRoute_O WarpRoute_O -- "dispatch(transfer msg)" --> Mailbox_O Mailbox_O -- "postDispatch()<br/>[Hook]" --> TLRouter_O TLRouter_O -- "dispatch(preverify msg)" --> Mailbox_O %% Messages in mailbox Mailbox_O -. "msg 0: preverify<br/>msg 1: transfer" .-> Mailbox_O %% Step 2: Try to process transfer before preverification Mailbox_D -. "Step 2" .-> Fail1 %% Step 3: Process preverification Mailbox_O == "Step 3: process msg 0" ==> Mailbox_D Mailbox_D -- "handle(messageId)<br/>[Router]" --> TLRouter_D TLRouter_D -- "readyAt[id] =<br/>now + 1 hour" --> TLRouter_D %% Step 4: Try to process transfer before timelock TLRouter_D -. "Step 4" .-> Fail2 %% Step 5: Wait TLRouter_D -. "Step 5: warp time<br/>+1 hour ⏰" .-> TLRouter_D %% Step 6: Process transfer successfully Mailbox_O == "Step 6: process msg 1" ==> Mailbox_D Mailbox_D -- "verify()<br/>[ISM]" --> TLRouter_D TLRouter_D -- "readyAt <= now?<br/>✓ pass" --> Mailbox_D Mailbox_D -- "handle(transfer)" --> WarpRoute_D WarpRoute_D -- "mint(amount)" --> User User -. "Step 6" .-> Success TLRouter_O -. "enrolled<br/>routers" .- TLRouter_D ``` ## 3. Optimistic Security with Aggregation TimelockRouter alone provides time delay. To create **optimistic security with fraud proofs and watcher control**, aggregate it with PausableISM and a finality proof system using **threshold-based aggregation**. **Architecture**: 1-of-2 aggregation of [2-of-2 aggregation of (pausable + timelock), finality proof] This provides **two independent paths** to message finality: - **Fast optimistic path** (Path 1): Requires BOTH pausable AND timelock (2-of-2 aggregation) - **Slow finality path** (Path 2): Requires only cryptographic proof, bypasses optimistic layer ```mermaid %%{ init: { "theme": "neutral", "themeVariables": { "mainBkg": "#025AA1", "textColor": "white", "clusterBkg": "white" }, "themeCSS": ".edgeLabel { color: black }" }}%% graph TB MB[Mailbox] OuterAgg[Outer AggregationISM<br/>1-of-2: EITHER path] style OuterAgg fill:purple InnerAgg[Inner AggregationISM<br/>2-of-2: BOTH required] style InnerAgg fill:purple PISM[PausableISM<br/>Watcher Control] style PISM fill:red TL[TimelockRouter<br/>Time Delay] style TL fill:orange ZK[ZkProofISM<br/>Rollup Finality] style ZK fill:blue Watcher([Watcher]) style Watcher fill:black MB -- "verify()" --> OuterAgg OuterAgg -- "Path 1:<br/>Fast Optimistic" --> InnerAgg OuterAgg -- "Path 2:<br/>Slow Finality" --> ZK InnerAgg -- "verify()" --> PISM InnerAgg -- "verify()" --> TL PISM -- "!paused?" --> InnerAgg TL -- "readyAt <= now?" --> InnerAgg InnerAgg -- "BOTH passed<br/>✓ fast path" --> OuterAgg ZK -- "valid proof?<br/>✓ slow path" --> OuterAgg OuterAgg -- "EITHER passed<br/>✓ process" --> MB Watcher -. "pause()" .-> PISM ``` **Verification flow:** **Path 1 (Fast Optimistic)**: Inner 2-of-2 aggregation requires BOTH: - `PausableISM.verify()` passes (not paused by watcher) - `TimelockRouter.verify()` passes (timelock expired) - **Result**: Message delivered after timelock window, unless paused **Path 2 (Slow Finality)**: Bypass optimistic layer entirely: - `ZkProofISM.verify()` passes (valid ZK proof or cryptographic finality) - **Result**: Message delivered immediately with cryptographic proof **Outer 1-of-2 aggregation**: Message succeeds if EITHER path passes **Benefits:** - **Normal case**: Fast optimistic path (low cost, ~1 hour latency) - **Emergency case**: Slow finality path bypasses paused optimistic layer - **Redundancy**: Two independent security mechanisms **Watcher workflow:** 1. **Monitor**: Watch for `MessageQueued` events from TimelockRouter 2. **Validate**: Check if message is valid (verify proofs, check state consistency) 3. **Pause if fraud detected**: Call `pausableIsm.pause()` to halt message processing 4. **Investigate & resolve**: Fix issues, then call `pausableIsm.unpause()`