Routing
OIP messages travel across heterogeneous chains and off-chain systems through routing decisions made not by senders but by the message content itself. The routing layer determines three things for every message: which recipients receive it, how their actions are coordinated, and which validation pipeline applies. This page specifies the routing rules that an OIP-compliant implementation MUST follow.
The routing layer sits between the message protocol layer (which defines what messages look like) and the state management layer (which defines how state transitions are validated). Routing answers a different question: given a well-formed message, where does it go and how is its multi-domain delivery coordinated.
Audience: implementers building an OIP-compliant routing component, integrators reasoning about how their messages will be dispatched, and reviewers validating that an implementation honors the routing contract. The MUST/SHOULD/MAY classification of every requirement on this page is consolidated in Conformance; the items deferred to v0.6 and beyond are catalogued in Open Issues.
Content-Based Routing
OIP adopts Content-Based Routing. Routing decisions are derived from the message itself, specifically messageType, priority, targetScope, and atomicity on the RoutingMetadata object, rather than from the sender’s identity or a fixed routing table lookup.
Three properties of regulated cross-domain state synchronization make content-based routing necessary. Regulatory action scope is not always known at issuance time: an AML pattern detected during processing may pull additional chains into scope after the message has already started flowing. The same message may take different paths depending on validation results: a STATE_SYNC can escalate into a REGULATORY_ACTION mid-flight when a compliance trigger fires. Routing logic must remain consistent across nodes without central coordination: every node deriving the same decision from the same message content is the only way to keep multi-node operation deterministic.
The routing decision is expressed as a function over message fields and the routing node’s local context. The fields routing reads are bundled in RoutingMetadata, defined in Data Model and reproduced here for reference.
interface RoutingMetadata {
priority: Priority;
targetScope: TargetScope;
atomicity: AtomicityStrategy;
ttlSeconds: number;
correlationId?: string;
routingSlip?: RoutingSlipEntry[];
}
interface RoutingContext {
chainRegistry: ChainRegistry; // CAIP-2 chainId, ERC-3770 shortName, RPC, status
assetLocationMap: AssetLocationMap; // assetId → chains where the asset exists
authorityRegistry: AuthorityRegistry; // authorityId, authorityType, jurisdiction, keys
nodeRegistry: NodeRegistry; // nodeId, public key, supported types, atomicity levels
}
function route(m: OIPMessage, context: RoutingContext): RoutingDecision {
return {
recipients: deriveRecipients(m, context),
coordination: determineCoordination(m.routing.atomicity, m.routing.priority),
pipeline: selectPipeline(m.header.messageType)
};
}
interface RoutingDecision {
recipients: string[]; // ERC-3770 shortName list
coordination: CoordinationStrategy;
pipeline: ProcessingPipeline;
}
The four RoutingContext components — ChainRegistry, AssetLocationMap, AuthorityRegistry, NodeRegistry — are populated and updated through the explicit governance procedure specified in the Dynamic Routing Table Updates section below. The dispatch of m.header.messageType to a concrete validation pipeline is the responsibility of Validation; this page covers only the dispatch decision, not the pipeline contents themselves.
Recipient Derivation
Recipients are derived as the union of three sources. First, every ERC-3770 shortName explicitly listed in targetScope.targetChains. Second, every chain that hosts any asset listed in targetScope.targetAssets, resolved through the routing node’s local assetLocationMap. Third, when the message carries regulatory authority, every chain within the issuing authority’s permitted scope as recorded in authorityRegistry. The exact resolution rules for authority scope, including the four-level Authority Hierarchy that governs which scopes a given authority may target, are specified in Validation.
The union is then filtered against the routing node’s chainRegistry: chains marked inactive or unreachable are excluded from the recipient list and the failure is recorded as a routing-slip entry. scopeOverride from coordination strategy (see below) is applied last and may expand recipients to all chains in chainRegistry regardless of the original targetScope.
TTL Check Precedes Routing
Before invoking the routing decision function, the routing node MUST verify that header.timestamp + routing.ttlSeconds >= now. Expired messages are rejected with MESSAGE_TTL_EXPIRED and not routed. The decision deliberately sits at the routing boundary rather than inside validation, so that expired messages neither consume validation resources nor accumulate routing-slip entries. The boundary placement of this check is registered as a MUST requirement in Conformance. TTL setting policy and the asset-class minimum TTL floor are specified in Data Model.
Atomicity-Driven Coordination
The atomicity field on RoutingMetadata is independent from targetScope. Atomicity decides how multi-domain delivery is coordinated; targetScope decides where the message lands. Treating them as separate dimensions is what allows the same scope (for example, three chains) to be delivered with three different guarantees (best-effort, guaranteed, or atomic).
OIP defines three Atomicity-Driven Coordination strategies. Each strategy fixes the execution mode, the confirmation requirement, and the failure handling behavior.
Figure 1: Atomicity Strategy Matrix
Each message type carries a default atomicity that reflects what the message semantically requires. Senders MAY override the default by explicitly setting atomicity on RoutingMetadata, subject to the priority-based escalation rules in the next section.
| Message Type | Default Atomicity | Rationale |
|---|---|---|
STATE_SYNC | GUARANTEED | State consistency required, partial progress acceptable |
REGULATORY_ACTION | ALL_OR_NOTHING | Regulatory enforcement requires full consistency |
LOCK_MANAGEMENT | GUARANTEED | Lock consistency required across domains |
QUERY | BEST_EFFORT | Read-only, partial responses acceptable |
ACK | BEST_EFFORT | Response message, simple delivery |
HEARTBEAT | BEST_EFFORT | Liveness signal, loss tolerated |
GOVERNANCE | ALL_OR_NOTHING | Governance decisions require network-wide consistency |
The determineCoordination function is normative. An OIP-compliant implementation MUST apply the priority escalation rules in the next section before invoking this function, and MUST route a CRITICAL message with ALL_OR_NOTHING atomicity and ALL_CHAINS scope regardless of the declared values. The function below MUST produce the same output for the same inputs across nodes; any deviation breaks cross-node determinism. The determinism requirement is registered in Conformance.
interface CoordinationStrategy {
atomicity: AtomicityStrategy;
execution: "PARALLEL" | "STAGED";
confirmationRequired: "NONE" | "ALL_TARGETS" | "ALL";
scopeOverride: "ALL_CHAINS" | null;
}
function determineCoordination(
atomicity: AtomicityStrategy,
priority: Priority
): CoordinationStrategy {
// CRITICAL forces ALL_OR_NOTHING regardless of declared atomicity
if (priority === Priority.CRITICAL) {
return {
atomicity: AtomicityStrategy.ALL_OR_NOTHING,
execution: "STAGED",
confirmationRequired: "ALL",
scopeOverride: "ALL_CHAINS"
};
}
switch (atomicity) {
case AtomicityStrategy.BEST_EFFORT:
return {
atomicity,
execution: "PARALLEL",
confirmationRequired: "NONE",
scopeOverride: null
};
case AtomicityStrategy.GUARANTEED:
return {
atomicity,
execution: "STAGED",
confirmationRequired: "ALL_TARGETS",
scopeOverride: null
};
case AtomicityStrategy.ALL_OR_NOTHING:
return {
atomicity,
execution: "STAGED",
confirmationRequired: "ALL",
scopeOverride: "ALL_CHAINS"
};
}
}
Priority-Based Atomicity Escalation
Some priorities carry safety implications strong enough that the declared atomicity is insufficient. Priority-Based Atomicity Escalation is the rule that CRITICAL and REGULATORY priorities force a minimum atomicity floor regardless of what the sender declared.
The escalation matrix below is normative. Implementations MUST apply these promotions before invoking determineCoordination.
| Original Priority | Original Atomicity | Final Atomicity | Final Scope |
|---|---|---|---|
CRITICAL | (any) | ALL_OR_NOTHING | ALL_CHAINS (override) |
REGULATORY | BEST_EFFORT | GUARANTEED (minimum) | targetScope retained |
REGULATORY | GUARANTEED | GUARANTEED | targetScope retained |
REGULATORY | ALL_OR_NOTHING | ALL_OR_NOTHING | ALL_CHAINS |
HIGH / NORMAL / LOW | (declared) | (declared) | targetScope retained |
The reasoning behind these promotions is structural. CRITICAL messages address situations where race conditions and cross-chain partial states are themselves the threat: a freeze that lands on three chains but not the fourth creates exactly the regulatory evasion vector the action was meant to close. ALL_OR_NOTHING with ALL_CHAINS scope is the only delivery profile that closes this gap. REGULATORY messages have a softer floor of GUARANTEED, because not every regulatory message is system-critical, but partial delivery still erodes enforcement integrity. The minimum floor prevents senders from accidentally weakening regulatory delivery semantics by declaring BEST_EFFORT.
Figure 2: Priority-Based Atomicity Escalation Flow
The authority required to mark a message CRITICAL is governed by the four-level Authority Hierarchy and scope restriction system specified in Validation. The concrete authority registration procedure and verification key management are pending downstream formalization, recorded as an explicit open issue in Open Issues. Authority assignment itself flows through the governance procedure described in Dynamic Routing Table Updates.
Routing Slip
A message that escalates mid-flight needs to leave a trail. The Routing Slip is an append-only log attached to RoutingMetadata.routingSlip that records every routing decision and mutation made along the message’s path. Each entry captures which node made the decision, when, what was decided, and what fields were mutated as a result. OIP-compliant implementations SHOULD accumulate and preserve the routing slip as the message traverses the network, since the slip is the primary audit substrate for cross-node behavior reconstruction. The append-only invariant is registered as a MUST requirement in Conformance; the accumulation responsibility itself is a SHOULD.
The routing slip serves three operational purposes. Audit traceability: regulators and operators can reconstruct why a given message reached a given destination. Debugging across nodes: when behavior diverges from expectation, the slip shows the exact stage and node at which the divergence occurred. Escalation tracking: when a STATE_SYNC escalates into a REGULATORY_ACTION or when scope expands due to AML pattern detection, the slip records the original intent alongside the mutation.
The slip is append-only: existing entries MUST NOT be rewritten or removed. New stages add new entries. Mutations are recorded as deltas in the mutations field of the new entry, never by editing prior entries.
The example below shows a STATE_SYNC message that an EU node escalated to REGULATORY_ACTION after detecting a structuring pattern, then handed to a regulatory node for authority verification.
const routingSlip: RoutingSlipEntry[] = [
{
stage: "INITIAL_RECEIPT",
nodeId: "node-eu-1",
timestamp: "2026-04-25T14:30:00Z",
decision: { acceptedAs: "STATE_SYNC", priority: "NORMAL" }
},
{
stage: "REGULATORY_COMPLIANCE_CHECK",
nodeId: "node-eu-1",
timestamp: "2026-04-25T14:30:01Z",
decision: {
amlPatternDetected: true,
patternType: "STRUCTURING",
escalationRequired: true
},
mutations: {
typeChanged: OIPMessageType.REGULATORY_ACTION,
priorityChanged: Priority.REGULATORY,
atomicityChanged: AtomicityStrategy.ALL_OR_NOTHING,
scopeExpanded: ["arb1", "oeth", "matic"]
}
},
{
stage: "AUTHORITY_VERIFICATION",
nodeId: "node-regulatory-eu",
timestamp: "2026-04-25T14:30:02Z",
decision: { authorityVerified: true, action: "FREEZE" }
}
];
Figure 3: Routing Slip Accumulation Across Three Stages
Dynamic Routing Table Updates
Routing depends on a local context that maps chains, assets, authorities, and nodes. In v0.5, updates to this context are governed by explicit GOVERNANCE messages rather than by automatic discovery or gossip-based propagation. This produces a deterministic, auditable update path at the cost of slower propagation, which is the right trade-off while the network is small and routing-table changes are infrequent. Automatic mechanisms are deferred to v0.6 and beyond; the deferral and its rationale are recorded in Open Issues.
Routing Table Components
The routing context held by each node consists of four components.
| Component | Contents |
|---|---|
ChainRegistry | Supported chains: CAIP-2 chainId, ERC-3770 shortName, RPC endpoint, active status |
AssetLocationMap | Asset ID → list of chains where the asset exists |
AuthorityRegistry | Authority issuers: authorityId, authorityType, jurisdiction, verification keys |
NodeRegistry | OIP nodes: nodeId, public key, supported message types, supported atomicity levels |
Update Mechanism
All four components are mutated through GOVERNANCE messages with a ROUTING_TABLE_UPDATE subtype. The payload structure below is normative.
interface RoutingTableUpdatePayload {
governanceType: "ROUTING_TABLE_UPDATE";
proposalId: string;
updateType: "CHAIN_ADD" | "CHAIN_REMOVE" | "CHAIN_UPDATE"
| "ASSET_LOCATION_UPDATE"
| "AUTHORITY_ADD" | "AUTHORITY_REMOVE" | "AUTHORITY_UPDATE"
| "NODE_ADD" | "NODE_REMOVE" | "NODE_UPDATE";
updatePayload: object; // shape varies by updateType
effectiveAt: string; // ISO 8601 (UTC)
rollbackDeadline?: string; // optional emergency rollback window
}
The update procedure follows a four-step cycle. A PROPOSAL message is issued first. A governance voting period (votingPeriodSeconds) follows. On approval, an EXECUTE message is broadcast. At effectiveAt, every node applies the update simultaneously. Messages whose State Root timestamp falls before effectiveAt are processed under the previous routing table; messages from the boundary forward are processed under the new one.
Deterministic Cutover
The cutover at effectiveAt uses the timestamp recorded in the OSS State Root, not each node’s local NTP-synchronized clock. This eliminates the divergence that would otherwise occur from clock skew between nodes processing the same message at the boundary.
- Decision basis is deterministic: when a node processes a message, it compares
effectiveAtagainst the timestamp on the OSS State Root currently being processed, not against its wall clock. - Boundary case: if the State Root timestamp is earlier than
effectiveAt, the previous routing table applies; if equal or later, the new one applies. - Cross-node consistency: every node processing the same State Root reaches the same routing decision. Clock skew cannot cause divergent routing.
- NTP skew tolerance: node operators are expected to keep wall clocks within 5-second NTP skew for operational reasons, but routing table cutover does not depend on wall clocks.
Deferred to v0.6+
Three mechanisms are explicitly deferred to OIP v0.6 and beyond: automatic node discovery (mDNS, Kademlia DHT), gossip-based routing table propagation, and automatic isolation of failed nodes. These become meaningful only when node count grows past roughly 100 in Phase 6, and the explicit governance path is the safer foundation until then. The complete catalogue of deferred routing items, including the CRITICAL priority authority registration procedure and the v0.6 wire-format dependencies, is maintained in Open Issues.
Related Pages
- Data Model defines the enums and interfaces that routing fields refer to (
Priority,AtomicityStrategy,TargetScope,RoutingMetadata,RoutingSlipEntry) and the TTL setting policy. - Message Protocol specifies the message types and payloads that the routing layer dispatches.
- State Management covers the state transitions that occur after routing has placed a message at its destination.
- Validation defines the processing pipelines selected by routing, the authority scope resolution invoked during recipient derivation, and the four-level Authority Hierarchy that governs CRITICAL priority.
- Cross-chain Protocol details the PREPARE → COMMIT → FINALIZE staged execution invoked by
GUARANTEEDandALL_OR_NOTHINGcoordination. - Conformance aggregates the MUST/SHOULD/MAY requirements that routing implementations must satisfy.
- Open Issues records routing items deferred to v0.6+, including dynamic discovery, gossip propagation, and the CRITICAL authority registration procedure.
