Files
proxmox/docs/04-configuration/ISO20022_INTAKE_GATEWAY_CONTRACT_MULTI_NETWORK.md
defiQUG b3a8fe4496
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
chore: sync all changes to Gitea
- Config, docs, scripts, and backup manifests
- Submodule refs unchanged (m = modified content in submodules)

Made-with: Cursor
2026-03-02 11:37:34 -08:00

11 KiB
Raw Blame History

ISO-20022 Intake / Gateway Contract on Different Blockchain Networks

Version: 1.0
Last Updated: 2026-02-23
Status: Active
Companion to: SMART_CONTRACTS_ISO20022_FIN_METHODOLOGY.md


1. Purpose

This document describes how the intake or gateway contract that receives ISO-20022 (and Fin) messages works across different blockchain networks: same logical contract, same address where possible, two delivery paths (relayer-submitted vs cross-chain), and per-chain configuration without breaking deterministic deployment.


2. Role of the Intake / Gateway Contract

The ISO intake contract is the single on-chain entry point that:

  1. Accepts a canonical ISO message (see SMART_CONTRACTS_ISO20022_FIN_METHODOLOGY.md) from either:
    • an off-chain relayer (gateway that parsed MX/MT and submits the canonical payload), or
    • a cross-chain message (e.g. CCIP) that carries the canonical payload from another chain.
  2. Enforces idempotency (by instructionId / msgId), authorisation (relayer role or CCIP router), and optional policy (ComplianceGuard, allowlists).
  3. Executes the intended action: mint, transfer, or unlock for bridge, and emits events with canonical metadata for audit and ISO-20022 reporting.

The contract does not parse raw MX/MT; it only ever sees the canonical struct. Parsing and mapping happen off-chain or on the source chain before submission.


3. Same Address on Every Network

To keep integration simple and avoid per-chain address maps, the intake contract is deployed at the same address on every supported chain, following the same pattern as UniversalCCIPBridge and MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT.

3.1 Deterministic Deployment (CREATE2)

  • Formula: address = keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))[12:].
  • Identical bytecode on every chain (same compiler, no chain-specific branches in bytecode).
  • Identical constructor / initializer args for the core contract; any chain-specific config (e.g. CCIP router, relayer list) is set after deployment via initialize() or setters.

3.2 Suggested Salt and Initialization

Item Value
Contract name ISO20022IntakeGateway (or equivalent)
Salt keccak256("ISO20022IntakeGateway") (fixed, documented)
Constructor Minimal (e.g. none) or same admin everywhere
initialize(args) admin, optional ccipRouter, optional relayer; same admin on all chains; ccipRouter can be set to 0 and configured per chain later

This yields one canonical intake contract address across all networks (e.g. 138, 1, 56, 10, 137, 42161, 8453, 43114, and 651940 if supported). Integrators and off-chain gateways can use that single address regardless of chain.


4. Two Ways Messages Reach the Intake Contract

Messages reach the intake contract in two ways: direct submission by a relayer (same chain) or delivery via a cross-chain protocol (e.g. CCIP) from another chain.

4.1 Path A: Relayer-Submitted (Same Chain)

Flow:

  1. Off-chain gateway receives ISO-20022 MX or SWIFT Fin MT.
  2. Gateway parses, validates, and maps to the canonical struct (see methodology doc).
  3. Gateway (as a relayer) calls the intake contract on the target chain:
    • submitInbound(CanonicalMessage calldata m) for credits (mint / release), or
    • submitOutbound(CanonicalMessage calldata m) for debits (burn / lock),
      with the relayers EOA or contract holding RELAYER_ROLE (or INTAKE_RELAYER_ROLE).

On-chain:

  • msg.sender must have the relayer role.
  • Contract checks processedInstructions[m.instructionId] (or processedMessages[m.msgId]); reverts if already processed.
  • Contract optionally checks ComplianceGuard / PolicyManager using m.debtorId, m.creditorId, m.purpose.
  • Contract performs the action (mint, transfer, bridge unlock) and sets processedInstructions[m.instructionId] = true.
  • Contract emits an event with canonical fields for audit and pacs.002/camt.054 mapping.

Per-chain: Only the relayer address(es) need to be configured per chain (e.g. different gateway EOA or multisig per network). The intake contract bytecode and address stay the same.

4.2 Path B: Cross-Chain Delivery (e.g. CCIP)

Flow:

  1. On the source chain, an authorised sender (e.g. the same intake contract at the same address, or a dedicated “sender” contract) encodes the canonical struct into bytes data and sends a CCIP (or other cross-chain) message to the destination chain, with receiver = intake contract address (same canonical address).
  2. On the destination chain, the CCIP router calls the intake contracts receive entry point (e.g. ccipReceive(Any2EVMMessage calldata message)).
  3. The intake contract:
    • Verifies the call is from the CCIP router (or a designated receiver adapter) via msg.sender == ccipRouter or a ROUTER_ROLE check.
    • Decodes message.data to obtain the CanonicalMessage.
    • Applies replay protection using message.messageId and/or the decoded instructionId (must not already be in processedMessages / processedInstructions).
    • Optionally validates source chain and sender from message.sourceChainSelector and message.sender (allowlist or “same intake contract on source chain”).
    • Executes the same logic as Path A (mint / transfer / unlock) and emits the same canonical events.

Per-chain: The CCIP router address is chain-specific. It is set in initialize() or via setCCIPRouter(address) after deployment so that the same bytecode is used everywhere. On chains without CCIP (e.g. 651940), the router can be set to address(0) and Path B disabled; only Path A (relayer) is used.


5. Contract Interface (Summary)

The intake contract exposes at least:

Entry point Caller Purpose
submitInbound(CanonicalMessage) Relayer (Path A) Process an inbound credit (mint / release from bridge).
submitOutbound(CanonicalMessage) Relayer (Path A) Process an outbound debit (burn / lock for bridge).
ccipReceive(Any2EVMMessage) CCIP router only (Path B) Decode payload to CanonicalMessage and process as inbound (or outbound if encoded so).

Optional:

  • setCCIPRouter(address) Admin; for deterministic deploy, init with router=0 then set per chain.
  • addRelayer(address) / removeRelayer(address) Admin; manage who can call submitInbound/submitOutbound.

Idempotency key: instructionId (and optionally msgId). Storage: mapping(bytes32 => bool) public processedInstructions; and, for CCIP, mapping(bytes32 => bool) public processedMessages; keyed by CCIP messageId to avoid replay from the transport layer.


6. How It Works on Different Networks (By Chain Type)

6.1 Chains With CCIP (e.g. 138, 1, 56, 10, 137, 42161, 8453, 43114)

  • Deploy the intake contract via CREATE2 with the same salt and init args (e.g. admin; router=0).
  • Post-deploy: Call setCCIPRouter(ccipRouterAddress) with that chains CCIP router.
  • Relayer: Grant RELAYER_ROLE to the gateway(s) that will submit canonical messages on this chain.
  • Behaviour: Both Path A (relayer) and Path B (CCIP) are active. Messages can arrive from off-chain (Path A) or from another chain (Path B) with the same canonical format.

6.2 Chains Without CCIP (e.g. ALL Mainnet 651940)

  • Deploy the same contract at the same address via CREATE2 (same salt, same init; no CCIP router).
  • Leave CCIP router as address(0) (or never set it). Path B is unused.
  • Relayer: Only Path A is used; the off-chain gateway submits canonical messages via submitInbound / submitOutbound from an address with RELAYER_ROLE.
  • Optionally, a custom cross-chain transport (e.g. AlltraCustomBridge-style) could later call a dedicated function that accepts the same canonical payload, with access control analogous to the CCIP router check.

6.3 Same Address, Different Config

  • Address: Identical across all networks (CREATE2 + same bytecode + same constructor/init args).
  • Config that can differ per chain:
    • CCIP router address (or 0),
    • Relayer list (RELAYER_ROLE),
    • Optional: ComplianceGuard / PolicyManager / vault addresses if set via setters after deploy.

No per-chain address map is needed in application logic; only the single intake contract address is used, and chain-specific behaviour is controlled by which roles and router are set on that chain.


7. Security and Replay

  • Path A: Idempotency by instructionId (and optionally msgId). Only RELAYER_ROLE can submit; relayer identity is per chain.
  • Path B: Replay protection by CCIP messageId and by decoded instructionId; only the CCIP router (or ROUTER_ROLE) can call ccipReceive. Validate source chain and sender if required (e.g. only accept from the same intake contract on allowed source chains).
  • Payload integrity: Optional check of payloadHash in the canonical struct against an off-chain attested hash; contract can store or emit it for audit.

8. Downstream Actions

The intake contract does not hold balances long-term; it forwards the intent to:

  • Mint: Call token factory or mint controller (with reserve/attestation checks as in MULTI_CHAIN_EXECUTION_ISO20022_EMONEY).
  • Transfer: Call token transfer or a vault that holds tokens.
  • Bridge unlock: Call the bridge/vault contracts release or unlock function with the same canonical metadata so that bridge and e-money runbooks stay aligned.

All such downstream calls should carry or emit the same canonical identifiers (instructionId, msgId, debtorId, creditorId, payloadHash) for audit and ISO-20022 reporting.


Document Description
SMART_CONTRACTS_ISO20022_FIN_METHODOLOGY.md Canonical format, mapping, validation, and contract interface for ISO/Fin.
MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md E-Money and ISO-20022 canonical message semantics.
MULTI_CHAIN_EXECUTION_CROSS_CHAIN_MESSAGE_HANDLING.md Cross-chain message handling, same address, replay, sender verification.
MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT.md CREATE2, salts, and deployment order.

Document Control

  • Owner: Configuration / Integration
  • Review: When intake contract interface or supported chains change