> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keystoneos.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# KeystoneRouter

> Per-chain LayerZero V2 coordinator for cross-chain settlements.

`KeystoneRouter` coordinates cross-chain settlements. One router is deployed per chain next to that chain's [KeystoneSettlement](/smart-contracts/keystone-settlement). The router holds **no funds, no recipients, and no copy of the settlement state machine**: on the coordinator chain it holds only the coordination record and a single irrevocable release-or-abort decision; on a participant chain it only reads its local settlement's status and drives the two router-only settlement entrypoints (`executeFromRouter` / `abortFromRouter`).

The coordinator role is **per settlement**, not per chain: any chain's router can act as the coordinator for a given settlement, with the other involved chains as participants. The coordinator's own leg is read live from its local settlement and is never messaged.

## Message types

The router is a LayerZero V2 OApp carrying three single-id messages:

| Type        | Value | Direction                  | Payload                                                                                   |
| ----------- | ----- | -------------------------- | ----------------------------------------------------------------------------------------- |
| `CONFIRMED` | 1     | participant -> coordinator | `settlementId`, plus the participant's `timeoutAt` and `abortDeadline` for cross-checking |
| `RELEASE`   | 2     | coordinator -> participant | `settlementId` only - no recipients, no amounts                                           |
| `ABORT`     | 3     | coordinator -> participant | `settlementId` only                                                                       |

Receive gas is pinned contract-side via governance-set enforced options per `(chain, message type)` pair, so a permissionless relayer never supplies raw options bytes.

<Note>
  **The relay pattern:** no LayerZero send ever runs inside a message receive or a settlement-state transaction. Receiving a message makes at most one settlement call and zero sends. Sends happen only through the permissionless, payable relay calls (`sendConfirm` / `relayDecision`) with the LayerZero fee supplied as `msg.value`.
</Note>

## Cross-chain settlement flow

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#1a3a35', 'actorBorder': '#2DD4A8', 'actorTextColor': '#e0f2ef', 'actorLineColor': '#2DD4A8', 'signalColor': '#2DD4A8', 'signalTextColor': '#e0f2ef', 'noteBkgColor': '#162e2a', 'noteTextColor': '#e0f2ef', 'noteBorderColor': '#1AAF8B', 'activationBkgColor': '#1a3a35', 'activationBorderColor': '#2DD4A8', 'labelBoxBkgColor': '#1a3a35', 'labelBoxBorderColor': '#2DD4A8', 'labelTextColor': '#e0f2ef', 'loopTextColor': '#2DD4A8'}}}%%
sequenceDiagram
    participant OP as Operator
    participant RC as Router (coordinator chain)
    participant SC as Settlement (coordinator chain)
    participant RP as Router (participant chain)
    participant SP as Settlement (participant chain)

    OP->>RC: registerCoordination(id, participantEids, timeoutAt, abortDeadline)
    Note over SC,SP: legs funded on each chain -> Prepared
    RP->>RC: sendConfirm (anyone pays LZ fee)<br/>CONFIRMED carries deadlines
    RC->>RC: verify participant + deadlines match,<br/>mark confirmed (idempotent)
    RC->>RC: all confirmed + local Prepared (read) +<br/>before releaseCutoff -> record Release
    RC->>RP: relayDecision (anyone pays LZ fee)<br/>RELEASE
    RP->>SP: executeFromRouter
    RC->>SC: applyLocalDecision -> executeFromRouter
```

1. **Register.** An operator calls `registerCoordination` on the coordinator chain's router with the remote participant EIDs and the settlement's deadlines. A coordination can never be re-registered; the participant set and deadlines are immutable. The structural floor `abortDeadline >= timeoutAt + minDecisionWindow` is enforced, and an empty participant set is rejected.
2. **Prepare.** Each chain's settlement is funded and flips to `Prepared` (see [remote mode](/smart-contracts/keystone-settlement#remote-mode-the-prepared-phase)).
3. **Confirm.** On each participant chain, anyone calls `sendConfirm(settlementId, coordinatorEid)` - it reverts unless the **local** settlement is actually `Prepared`, and the message carries the local `timeoutAt`/`abortDeadline` so the coordinator can cross-check them. A confirmation whose deadlines disagree with the coordination record records an **Abort** instead of counting.
4. **Decide.** When every remote participant has confirmed, the coordinator's own leg is `Prepared`, the time is strictly before `releaseCutoff`, and no decision exists yet, the router records the irrevocable **Release** decision. Evaluation runs inline on each confirmation and can be re-triggered permissionlessly with `pokeDecision`.
5. **Relay.** Anyone calls `relayDecision(settlementId, dstEid)` per participant chain to transmit the recorded decision (the relayer pays the LayerZero fee and cannot influence the decision), and `applyLocalDecision(settlementId)` for the coordinator chain's own leg. Receiving `RELEASE` calls `executeFromRouter`; `ABORT` calls `abortFromRouter`. Re-delivery is harmless - the settlement guards its own state.

## Abort paths

A recorded decision is **single-write**: once `Release` exists it can never flip to `Abort`, and vice versa.

* **Operator abort** - an operator can record `Abort` at any time before a Release exists (e.g. a participant chain will never fund, or compliance regressed after `Prepared`).
* **Permissionless abort** - once the release window has closed (`block.timestamp >= releaseCutoff`) and the confirmation set is still incomplete, anyone can record `Abort`. This keeps refunds live even if the KeyStone backend is down.
* **Deadline-mismatch abort** - a `CONFIRMED` message whose deadlines disagree with the coordination record records `Abort` automatically.

## Timing windows

| Parameter           | Meaning                                                                                                                                                             |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `timeoutAt`         | Deposit window end on each settlement (single-chain timeout semantics)                                                                                              |
| `abortDeadline`     | End of the cross-chain decision window; the Prepared-phase timeout claim (operator or any depositor, on the settlement) opens here                                  |
| `minDecisionWindow` | Immutable deploy constant: `abortDeadline` must be at least this far after `timeoutAt`                                                                              |
| `releaseCutoff`     | `abortDeadline - releaseMargin`: a Release must be recorded strictly before this, leaving time to relay and execute on every chain before any chain's timeout opens |

The release window (before `abortDeadline`, on the settlement) and the timeout window (at/after `abortDeadline`) are disjoint, so no instant has both release and refund live on any chain. Current testnet deployments use `minDecisionWindow = 3600` seconds and `releaseMargin = 900` seconds - see [testnet addresses](/smart-contracts/testnet-addresses).

## Functions

```solidity theme={null}
function registerCoordination(bytes32 settlementId, uint32[] calldata participantEids, uint64 timeoutAt, uint64 abortDeadline) external  // operator only
function sendConfirm(bytes32 settlementId, uint32 coordinatorEid) external payable   // permissionless
function relayDecision(bytes32 settlementId, uint32 dstEid) external payable         // permissionless
function applyLocalDecision(bytes32 settlementId) external                           // permissionless
function pokeDecision(bytes32 settlementId) external                                 // permissionless
function recordAbort(bytes32 settlementId) external      // operator any time pre-Release; anyone after releaseCutoff with an incomplete set
function setOperator(address account, bool allowed) external                         // owner only
```

Views: `getCoordination(settlementId)` (record incl. `confirmedCount`, `participantCount`, `decision`), `getParticipantEids(settlementId)`, `isConfirmed(settlementId, eid)`, `releaseCutoff(settlementId)`.

## Events

| Event                                                                              | When                                                      |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `CoordinationRegistered(settlementId, timeoutAt, abortDeadline, participantCount)` | Coordinator registration                                  |
| `Confirmed(settlementId, srcEid)`                                                  | A participant chain's confirmation is counted             |
| `DecisionRecorded(settlementId, decision)`                                         | The irrevocable Release/Abort decision is written         |
| `ConfirmSent(settlementId, dstEid)`                                                | A CONFIRMED message is relayed to the coordinator         |
| `DecisionRelayed(settlementId, dstEid, decision)`                                  | A RELEASE/ABORT message is relayed to a participant       |
| `LocalDecisionApplied(settlementId, decision)`                                     | The coordinator chain applies the decision to its own leg |

## Governance

The router owner (Ownable2Step; intended to be a multisig plus timelock in production) administers the operator set, the LayerZero peers, the delegate, and the enforced options. Operators register coordinations and can abort pre-Release. All relays are permissionless - a relayer pays the message fee but can only transmit what the contract already decided.
