# Methodology: Smart Contracts Accepting ISO-20022 and Fin Messages **Version:** 1.0 **Last Updated:** 2026-02-23 **Status:** Active **Scope:** Chain 138 (and multi-chain) e-money and bridge contracts --- ## 1. Purpose and Scope This document defines the **methodology** for designing and operating smart contracts that **accept** ISO-20022 financial messages (MX/XML) and, where applicable, **SWIFT Fin** (MT) messages, by normalising them to a single **canonical on-chain representation** and processing them through a well-defined contract interface. ### 1.1 Objectives - **Interoperability:** Enable value transfers and settlement flows that originate from or are traceable to ISO-20022 (and Fin) messaging. - **Auditability:** Ensure every on-chain transfer, mint, burn, or cross-chain action can be correlated with a standardised message identifier and metadata (e.g. MsgId, UETR, debtor/creditor, purpose). - **Compliance:** Support regulatory and E-Money requirements (par redeemability, safeguarded reserves, transaction monitoring) while preserving ISO-20022 semantics at the boundary. ### 1.2 Out of Scope - Off-chain generation or routing of ISO-20022/Fin messages (covered by [ISO 20022 Mapping Table](../../gru-docs/docs/integration/iso20022/Mapping_Table.md) and [dbis_core ISO 20022 integration](../../dbis_core/docs/nostro-vostro/iso20022-mapping.md)). - Contract deployment or network topology (see deployment runbooks). --- ## 2. Message Sources: ISO-20022 and Fin ### 2.1 ISO-20022 (MX) Messages | Message Type | Purpose | Typical Use in Smart Contract Context | |-------------------|----------------------------------|----------------------------------------| | **pain.001** | Customer credit transfer initiation | Initiation of a payment that may settle on-chain | | **pacs.008** | FI-to-FI customer credit transfer | Settlement instruction; primary input for on-chain credit | | **pacs.009** | FI-to-FI direct debit | Debit-side settlement | | **pacs.002** | Payment status report | Status/correlation off-chain or in events | | **camt.053** | Bank statement | Off-chain reconciliation | | **camt.054** | Debit/credit notification | Notifications; optional event mapping | Messages are **XML** with namespaces per ISO 20022 XSDs (e.g. `urn:iso:std:iso:20022:tech:xsd:pacs.008.001.10`). Parsing and validation are done **off-chain**; only a **canonical payload** is passed to the contract. ### 2.2 SWIFT Fin (MT) Messages Where legacy flows use **SWIFT Fin** (e.g. MT103, MT202), the methodology treats them as **additional input formats** that must be **mapped into the same canonical structure** as ISO-20022 before being passed to smart contracts. | MT Type | Purpose | Mapping Notes | |-----------|----------------------|----------------------------------------------------| | **MT103** | Single customer transfer | Field 20 → instructionId; 32A → amount/currency; 50/59 → debtor/creditor | | **MT202** | Bank transfer | Map to pacs.008-like canonical fields | Fin messages are **normalised to the canonical format** (Section 3) so that contracts do not need separate MT vs MX logic. --- ## 3. Canonical Message Format (On-Chain Contract View) All accepted messages (ISO-20022 MX or SWIFT Fin) are reduced to a **single canonical struct** used in contract interfaces and events. This aligns with the extended CanonicalMessage described in [MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md](../runbooks/MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md). ### 3.1 Canonical Struct (Semantic Definition) | Field | Type | Purpose | |--------------------|---------|--------| | `msgType` | string | Message type: `pacs.008`, `pain.001`, `camt.054`, or normalized equivalent (e.g. `MT103`) | | `instructionId` | bytes32 | InstrId – unique instruction reference (hashed if longer than 32 bytes) | | `endToEndId` | string | EndToEndId (optional) | | `msgId` | string | MsgId (optional) | | `uetr` | string | UETR (optional) | | `accountRefId` | string | Account reference (debtor account or equivalent) | | `counterpartyRefId`| string | Counterparty account reference (creditor or equivalent) | | `debtorId` | string | Debtor identifier (optional) | | `creditorId` | string | Creditor identifier (optional) | | `purpose` | string | Purpose / remittance info (optional) | | `settlementMethod` | string | Settlement method (optional) | | `categoryPurpose` | string | Category purpose (optional) | | `token` | address | Token contract address | | `amount` | uint256 | Amount (in token’s smallest unit) | | `currencyCode` | string | Currency code (ISO 4217) | | `payloadHash` | bytes32 | Hash of off-chain payload (full MX/MT or selected elements) for audit | Strings that exceed on-chain limits (e.g. 32 bytes for a single storage slot) should be **hashed** for storage and the full value emitted in events or stored in an off-chain index keyed by `instructionId` or `msgId`. ### 3.2 Solidity-Oriented Representation Contracts may use a struct such as: ```solidity struct CanonicalMessage { string msgType; bytes32 instructionId; string endToEndId; string msgId; string uetr; string accountRefId; string counterpartyRefId; string debtorId; string creditorId; string purpose; string settlementMethod; string categoryPurpose; address token; uint256 amount; string currencyCode; bytes32 payloadHash; } ``` Optional fields can be empty strings or zero values where not applicable. Events should expose at least `instructionId`, `msgId` (if present), `token`, `amount`, `debtorId`, `creditorId`, and `payloadHash` so that off-chain systems can map back to ISO-20022. --- ## 4. End-to-End Flow: From Fin/ISO-20022 to Smart Contract ### 4.1 High-Level Pipeline ``` [ISO-20022 MX / SWIFT Fin] → Parse & Validate (off-chain) → Map to Canonical → Submit to Contract → Contract applies policy & executes ``` 1. **Ingest:** Receive MX (XML) or Fin (MT) message at an off-chain service (e.g. [dbis_core Iso20022Service](../../dbis_core/src/integration/iso20022/iso20022.service.ts), [Iso20022Adapter](../../dbis_core/src/integration/plugins/iso20022-adapter.ts), or a dedicated gateway). 2. **Parse and validate:** Check schema, mandatory elements, and business rules (amounts, currency, identifiers). Reject invalid messages before any on-chain step. 3. **Map to canonical:** Fill the canonical struct from the message (see Section 5). For MT, use a dedicated MT→canonical mapping (e.g. MT103 field 20 → instructionId, 32A → amount/currencyCode, 50/59 → debtorId/creditorId). 4. **Submit to contract:** Call the contract’s **accept** entry point (e.g. `submitInbound` / `submitOutbound` or equivalent) with the canonical payload. The contract must verify sender (relayer/guardian), idempotency (e.g. by `instructionId` or `msgId`), and policy (ComplianceGuard, PolicyManager, allowlists). 5. **Execute and emit:** Contract performs transfer/mint/burn/cross-chain and emits events that include canonical metadata so that off-chain systems can map to ISO-20022 reports (pacs.002, camt.054, etc.). ### 4.2 Idempotency and Replay Protection - **Unique key:** Use `instructionId` (and optionally `msgId` or `uetr`) as the idempotency key. Contracts must maintain a mapping (e.g. `processedInstructions[instructionId]`) and **revert or no-op** if the same key is submitted again. - **Replay:** Ensure the same MX/Fin message cannot be replayed on another chain or at another time by binding the canonical payload to chain and, if needed, to a nonce or timestamp validated off-chain or on-chain. --- ## 5. Mapping Rules: ISO-20022 and Fin → Canonical ### 5.1 ISO-20022 MX → Canonical Use the same semantic mapping as in the [ISO 20022 Mapping Table](../../gru-docs/docs/integration/iso20022/Mapping_Table.md) and [dbis_core iso20022-mapping](../../dbis_core/docs/nostro-vostro/iso20022-mapping.md), then project onto the canonical struct: | Canonical Field | ISO-20022 Source (e.g. pacs.008) | |----------------------|-----------------------------------| | msgType | Message type (e.g. `pacs.008`) | | instructionId | `PmtId/InstrId` (hash if needed) | | endToEndId | `PmtId/EndToEndId` | | msgId | `GrpHdr/MsgId` | | uetr | UETR element if present | | accountRefId | `DbtrAcct/Id` (IBAN or Othr/Id) | | counterpartyRefId | `CdtrAcct/Id` (IBAN or Othr/Id) | | debtorId | `Dbtr/Nm` or `Dbtr/Id` | | creditorId | `Cdtr/Nm` or `Cdtr/Id` | | purpose | `RmtInf/Ustrd` or `Purp` | | settlementMethod | Settlement method element | | categoryPurpose | `CategoryPurp` | | token | Resolved from currency/account (off-chain config) | | amount | `IntrBkSttlmAmt` (scaled to token decimals) | | currencyCode | `IntrBkSttlmAmt/@Ccy` | | payloadHash | `keccak256(rawMessage)` or hash of selected elements | ### 5.2 SWIFT Fin (MT) → Canonical Example for **MT103**: | Canonical Field | MT103 Field | Notes | |----------------------|-------------|--------| | msgType | — | Set to `MT103` | | instructionId | 20 | Hash if > 32 bytes | | endToEndId | 121 (UETR) or 20 | If present | | msgId | — | From header or generate | | uetr | 121 | If present | | accountRefId | 50a / 52a | Sender account | | counterpartyRefId | 59a | Beneficiary account | | debtorId | 50K / 50a | Ordering customer | | creditorId | 59 / 59a | Beneficiary | | purpose | 72 | Sender to receiver info | | token | — | From currency in 32A + config | | amount | 32A | Parse amount; scale to token decimals | | currencyCode | 32A | Currency from 32A | | payloadHash | — | Hash of MT text block or full message | Contracts only ever see the **canonical** struct; they do not need to know whether the source was MX or MT. --- ## 6. Contract Interface Requirements ### 6.1 Entry Points for “Accepting” Messages Smart contracts that **accept** ISO-20022/Fin semantics should expose at least one of the following (or equivalent): - **Inbound (e.g. submitInbound):** For instructions that result in **credit** to the chain (e.g. mint, or release from bridge). Caller must be an authorised relayer/guardian; payload is the canonical struct. - **Outbound (e.g. submitOutbound):** For instructions that result in **debit** from the chain (e.g. burn, or lock for bridge). Same authorisation and canonical payload. Naming may vary (e.g. `processInboundMessage`, `acceptCreditTransfer`); the important part is that the **payload is the canonical struct** and that **idempotency** and **policy checks** are enforced. ### 6.2 Authorisation - Only designated roles (e.g. `ROUTER_ROLE`, `RELAYER_ROLE`, or a guard contract) may call the submit functions. Use AccessControl or equivalent. - Optionally, require that the **sender** of the transaction is a known **guardian** or **relayer** address list, and that the canonical payload’s `payloadHash` matches an off-chain attested hash. ### 6.3 Events Emit events that carry enough canonical metadata for off-chain systems to map to ISO-20022 status and reporting (e.g. pacs.002, camt.054): - At least: `instructionId`, `msgId` (if any), `token`, `amount`, `debtorId`, `creditorId`, `payloadHash`, success/failure. - Prefer including `msgType`, `endToEndId`, `uetr` where available so that reconciliation and compliance reporting are straightforward. ### 6.4 Integration with E-Money and Compliance - **ComplianceGuard / PolicyManager / ComplianceRegistry:** Before executing the transfer/mint/burn, contracts should enforce allowlists, KYT, and circuit breakers as described in [MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md](../runbooks/MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md). The canonical struct supplies `debtorId`, `creditorId`, and `purpose` for policy checks. - **Reserve and par redeemability:** For base-money mints, ensure reserve attestation and par redeemability rules are applied as in the same runbook; the canonical message does not replace those checks. --- ## 7. Validation and Security ### 7.1 Off-Chain Validation (Before Submit) - **Schema:** Validate MX against the appropriate ISO 20022 XSD; validate MT format per SWIFT rules. - **Business rules:** Amount > 0, currency matches token, mandatory identifiers present, no duplicate `instructionId`/`msgId` in the system. - **Payload hash:** Compute `payloadHash` over the raw or normalized message and attach to the canonical struct so the contract (or a verifier) can optionally check it. ### 7.2 On-Chain Checks - **Idempotency:** Revert or skip if `instructionId` (or chosen key) already processed. - **Role:** Only authorised roles can call submit. - **Token:** Ensure `token` is a known, allowed token (e.g. via TokenRegistry or allowlist). - **Amount:** Ensure `amount` is within bounds and, for mints, consistent with reserve/attestation logic. ### 7.3 Audit and Non-Repudiation - Store or log `payloadHash` and `instructionId` on-chain so that auditors can match on-chain execution to off-chain MX/Fin messages. - Prefer emitting full canonical metadata in events and indexing them off-chain for compliance and reconciliation. --- ## 8. Implementation Checklist - [ ] **Off-chain:** Parser for ISO-20022 MX (and optionally SWIFT Fin MT) producing the canonical struct. - [ ] **Off-chain:** Mapping tables and validation rules (amounts, currency, identifiers) aligned with [Mapping_Table.md](../../gru-docs/docs/integration/iso20022/Mapping_Table.md) and [iso20022-mapping.md](../../dbis_core/docs/nostro-vostro/iso20022-mapping.md). - [ ] **Contract:** Canonical struct and submit interface (e.g. `submitInbound`/`submitOutbound`) with role-based access. - [ ] **Contract:** Idempotency (e.g. `processedInstructions[instructionId]`) and policy hooks (ComplianceGuard, PolicyManager, ComplianceRegistry). - [ ] **Contract:** Events that expose canonical metadata for ISO-20022 mapping and reporting. - [ ] **Integration:** Bridge and e-money entry points (BridgeVault, UniversalCCIPBridge, etc.) carry or reference canonical metadata in events as per [MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md](../runbooks/MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md). --- ## 9. Related Documents | Document | Description | |----------|-------------| | [ISO20022_INTAKE_GATEWAY_CONTRACT_MULTI_NETWORK.md](ISO20022_INTAKE_GATEWAY_CONTRACT_MULTI_NETWORK.md) | How the intake/gateway contract receives ISO messages on different blockchain networks (relayer vs cross-chain, same address, per-chain config) | | [MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md](../runbooks/MULTI_CHAIN_EXECUTION_ISO20022_EMONEY.md) | ISO-20022 canonical message and E-Money requirements for GRU multi-chain | | [OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md](../03-deployment/OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md) | End-to-end map: OMNL, DBIS Core, Smart Vault, RTGS, settlement events, ISO/DID; Chain 138 `ISO20022Router` in [CONTRACT_ADDRESSES_REFERENCE.md](../11-references/CONTRACT_ADDRESSES_REFERENCE.md) | | [Mapping_Table.md](../../gru-docs/docs/integration/iso20022/Mapping_Table.md) | ISO 20022 (pain.001, pacs.008, etc.) field-level mapping and validation | | [iso20022-mapping.md](../../dbis_core/docs/nostro-vostro/iso20022-mapping.md) | ISO 20022 to DBIS API mapping and Iso20022Adapter usage | | [iso20022-message-flow.md](../../dbis_core/docs/flows/iso20022-message-flow.md) | ISO 20022 message processing flow | | [LEGAL_COMPLIANCE_REQUIREMENTS.md](../../explorer-monorepo/docs/LEGAL_COMPLIANCE_REQUIREMENTS.md) | Legal and ISO 20022 compliance for smart contracts | | [OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md](../03-deployment/OMNL_DBIS_CORE_CHAIN138_SMART_VAULT_RTGS_RUNBOOK.md) | Full-stack map: OMNL, Core, RTGS, ISO on-chain, DID, FX, Smart Vaults (section 14) | --- **Document Control** - **Owner:** Configuration / Integration - **Review:** Align with runbook and mapping table changes - **Next review:** When contract interfaces or ISO-20022 message set change