Proposal: add ISO 20022 ↔ Canton Settlement Adapter#403
Conversation
|
SIG labels auto-detected and applied: If this is incorrect, you can ask the reviewers to update the labels. |
|
Champion identified Canton Foundation The committee will verify this champion during review. |
|
|
Thanks for the feedback. 1 - Canton party IDs aren't derivable from banking identifiers and there's no global directory, so the adapter doesn't try to infer anything. Resolution is explicit: a configured, institution-owned directory that maps IBAN/BIC/LEI to a Canton party id and its hosting participant. That data isn't something new to build, it's the bank's existing SSI/counterparty information expressed as signed config, and each institution only needs to know its own counterparties. If a counterparty can't be matched cleanly, the adapter rejects the message with a pacs.002 reason code instead of guessing. We can also resolve through CNS when a counterparty has published its mapping there, and through vLEI down the line, but neither is needed for v1. 2 - Ccy=USD is a currency, not a token, so we never assume USD means USDC. CIP-56 already makes the instrument explicit: an InstrumentId is { admin: registry party, id }, so "which USD" really means "which registry." The token is chosen explicitly, in priority order: from the settlement agreement or account between the two parties (again the SSI model, e.g. A and B agree to settle USD in JPM Coin), from an explicit instrument reference in the message (a structured or Prtry field), or from a per-deployment default when only one instrument exists for that currency. If a currency could map to more than one instrument and nothing makes it clear, we reject rather than settle in the wrong token. For transparency I've also updated the proposal to spell this out directly: the Party Resolution directory (with the fail-closed reject behaviour), the explicit instrument-resolution rules, and a note on ISO 4217 coverage (we only settle currencies that have a configured CIP-56 instrument; everything else is a clean reject). |
|
|
The reason is that ISO 20022
So v1 supports
A single-leg credit transfer does not use the Allocation model. It uses a TransferFactory transfer instead. The sender authorises the transfer instruction, and if the registry requires receiver acceptance, the receiver authorises the accept step separately. The When the Allocation / DvP path is added, the executor will be a configured settlement-coordinator party: either the adapter/operator party or a settlement agent agreed between the institutions. It is a deployment or bilateral-configuration role, not a field taken from the ISO message. So the executor is not derived from |
daravep
left a comment
There was a problem hiding this comment.
Thank you for your proposal. I do think that integration work into existing systems is going to be key for the network and as such I welcome your proposal.
I left a few comments for your consideration.
|
|
||
| ## Abstract | ||
|
|
||
| The ISO 20022 ↔ Canton Settlement Adapter is an open-source, bidirectional library that translates standardized ISO 20022 bank messages (`pacs.008`, `pacs.002`, `camt.05x`) into CIP-56 token transfers and Delivery-vs-Payment (DvP) settlements via the CIP-0103 dApp / JSON Ledger API, and back again. |
There was a problem hiding this comment.
I am a bit surprised to read CIP-103 as the dApp standard is specifically geared towards end-user experience and wallet discovery, whereas I would expect this adaptor to be an integration process.
There was a problem hiding this comment.
Agreed. This is an unattended back-office integration, so it runs on the JSON/gRPC Ledger API directly, plus the token-standard registry off-ledger APIs, with signing through the institution's own provider. CIP-0103 only enters if someone wants to route signing through a dApp-API wallet, which is optional — not the integration path. Tightened in the proposal.
| This proposal closes that gap with a shared reference implementation for the most common settlement message family: | ||
|
|
||
| - **Inbound:** `pacs.008` (FI-to-FI customer credit transfer) is translated into a CIP-56 transfer or DvP via CIP-0103, and a `pacs.002` (payment status report) is returned. (`pain.001` payment initiation follows the same inbound path and is a stretch goal, not a v1 commitment.) | ||
| - **Outbound:** on-ledger settlement events are turned into `camt.05x` (account report / statement) for the institution's back office and reconciliation. |
There was a problem hiding this comment.
Note that ISO20022 has been integrated for some commercial projects in the past. The code is not OSS but the integration spanned a very large scope of the ISO20022 messages. I'd be happy to share some insights in a bilateral convo.
There was a problem hiding this comment.
That'd be really useful, so yes, let's talk privately
|
|
||
| **a. ISO 20022 ingestion & validation.** Official ISO 20022 XSD schemas are used to generate strongly-typed message bindings (JAXB on the JVM). Inbound messages are validated against the schema and the relevant CBPR+/HVPS+ usage guideline before any ledger action. We do not hand-roll message parsing. | ||
|
|
||
| **b. Declarative mapping engine.** A declarative rule set maps ISO 20022 fields to CIP-56 transfer/DvP parameters. Mappings are configuration-driven, so an institution can extend them to its own usage guideline without forking the core. The reusable core is the canonical mapping plus the message-construction logic; institution-specific enrichment lives in config, not in the library. |
There was a problem hiding this comment.
I wouldn't build a declarative mapping engine. Effectively "configuration files" are also code, just built in a custom syntax. You might get more flexibility at less complexity if you provide these mapping capabilities as an extensible interface of the adaptor code itself. I'd rather code these mappings up as a JVM function.
There was a problem hiding this comment.
Yeah, I switched to a typed mapper interface in the adapter, integrators implement a JVM function with real types and tests, and extend by implementing the interface. Only the tabular lookups stay as data: the party directory and the currency - InstrumentId map. Updated in the spec.
| | --- | --- | --- | | ||
| | `CdtTrfTxInf/IntrBkSttlmAmt` (+ `@Ccy`) | `amount` | Decimal amount; currency drives instrument resolution (see below) | | ||
| | `CdtTrfTxInf/Dbtr` + `DbtrAcct` (IBAN) / `DbtrAgt` (BIC) | `sender` (Canton party) | Resolved via the Party Resolution directory | | ||
| | `CdtTrfTxInf/Cdtr` + `CdtrAcct` (IBAN) / `CdtrAgt` (BIC/LEI) | `receiver` (Canton party) | Resolved via the Party Resolution directory | |
There was a problem hiding this comment.
I think you should update this to CIP-112 that introduces better account structures.
There was a problem hiding this comment.
Yeah, I'd already been leaning this way on V2, had been discussing it with @meiersi-da too. The V2 Account fits the ISO block much better than a flat party: owner is the Dbtr/Cdtr, provider is the account-servicing agent (the DbtrAgt/CdtrAgt BIC), and id is the IBAN. I've pointed the mapping at a V2 Account; v1 assets stay party-level (basicAccount) for now, so it's an upgrade rather than a new dependency.
|
|
||
| | Component | Responsibility | | ||
| | --- | --- | | ||
| | **Message Gateway** | Ingests/emits ISO 20022 XML over standard transports (HTTPS/SFTP), validates against XSD plus CBPR+/HVPS+ usage guidelines, and de-duplicates by `MsgId`/`EndToEndId`. | |
There was a problem hiding this comment.
Do you have the non-happy path on the radar? I would assume so but I think you should maintain a list of possible failures and provide insights on how these will be handled (e.g. mismatch between party in the party directory and on-ledger topology state, unavailable counter participants, timeouts, etc.).
There was a problem hiding this comment.
Yes, it's in the spec as a maintained list. Each failure resolves to a deterministic pacs.002 with an ISO reason code; transient cases hold in PDNG with bounded retry and reject only on expiry.
| Failure | Handling - pacs.002 |
|---|---|
| Party directory entry mismatches on-ledger topology (party absent / not hosted as expected) | reject BE06 (AC04 if account closed) |
| Counterparty participant unavailable / settlement doesn't complete | PDNG, bounded retry, then RJCT ED05 |
Receiver doesn't accept before executeBefore (timeout) |
PDNG, then RJCT on expiry |
| Insufficient holdings | RJCT AM04 |
| Currency with no configured CIP-56 instrument | RJCT AM03 |
Unsupported SttlmMtd (COVE/CLRG) |
RJCT NARR |
Registry / createdEventBlob fetch failure |
refetch / retry; persistent - RJCT ED05 |
| Transient ledger contention | retry preserving change ID; permanent - RJCT ED05 |
| Malformed message (XSD / CBPR+ / HVPS+) | RJCT FF01 before any ledger action |
Duplicate MsgId/EndToEndId |
no second settlement; original status returned (DU01/DU04 if a true duplicate) |
| DvP single-leg failure | both-or-neither, never partial; single combined RJCT ED05 |
Idempotency (MsgId/EndToEndId - ledger change ID) prevents double-settlement, and atomic settlement means a failed submission leaves nothing settled - always a pacs.002 reject, never a pacs.004 return.
…ation, typed mapper interface, CIP-0112 accounts, failure-handling taxonomy, and Token Standard V2 alignment
Thanks @daravep , appreciate the review. Replied inline, and I've updated the proposal on the back of it, including the Token Standard V2 (CIP-0112) piece, which I'd discussed with @meiersi-da, so it's now reflected as the forward path. |
|
@akameoww Do you have a specific design partner or user zero lined up for this? In my experience, such components end up with a fair amount of customisation and special requirements that emerge in the context of the kinds of projects where ISO 20022/FIX compatibility is an issue. So to give this the highest potential for success, either this has to be developed in the context of a specific project, or with specific design partners in hand, or be structured to be highly customizable - e.g. as sample code or just as a codec/library that is flexible to integrate. |
Good point, and it matches what we've seen, ISO 20022 integrations always pick up institution-specific quirks. That's exactly why we built the adapter as a flexible library, not a turnkey product, so the mapping engine is an extensible typed interface (institutions override by implementing it, not forking the core), it ships as an embeddable library plus a reference integration to reuse as-is, and the public conformance vectors let anyone verify a customized deployment is still spec-correct. So the customizability route you describe is already baked in, that part's settled |
|
I was part of a team that implemented a component that did almost exactly this for both ISO and FIX messaging, and in the end I would caution against it. In the course of working on it we found quite a few negative outcomes that would make me suggest that this isn't the best solution for addressing legacy integration to a distributed ledger. Despite the fact we successfully managed to build a reusable ISO adapter driven entirely by XSDs and configuration, we decided to leave it with the one implementation and not look to carry it forward into future solutions. Our findings were:
Take it for what it's worth, but my experience is all of the above are very hard to mitigate against because they are natural outcomes of the way people think about the component as opposed to something that can be solved by a smarter implementation. |
Thank you, this is genuinely valuable feedback, especially coming from someone who's built this at scale. I'll be straight about where it leaves the proposal. The strongest version of your point is that a universal, build-it-for-the-future ISO 20022 adapter is the wrong unit of work. Without a concrete client it rots, and at worst it turns the ledger into a message gateway and gives an institution permission to never move into a composable model. That's a fair correction to how the proposal currently reads, and I agree with it. A few things I'd keep, because I think they line up with your own conclusions:
Where I think you're most right is on demand and on the identity/trust model. Those can't be designed in the abstract. I'm anchoring this around concrete design partners and a specific legacy process, and validating the identity-mapping and trust assumptions directly with the client's team. Given you've actually been through this, would you be open to reviewing the design with us? Specifically where the "edge" line sits, what must never become configurable, and the identity/trust pitfalls you hit. |
Development Fund Proposal Submission
Proposal file:
/proposals/proposal-iso-20022-canton-settlement-adapter.mdSummary
This proposal requests funding for the ISO 20022 ↔ Canton Settlement Adapter, an open-source, bidirectional library that lets banks, PSPs, and custodians initiate and reconcile settlement on Canton straight from their existing payment systems, without a core-banking rewrite.
Canton's own documentation states there is no native ISO 20022 capability, and that integrators "must build an intermediary translation layer" themselves. With JPM Coin (Kinexys), DTCC tokenized Treasuries, and Visa (Super Validator) all live in 2026, that layer is the last step missing for institutional adoption. Today it is rebuilt privately by each institution, or it blocks onboarding.
We build it once, as a public good: standardized ISO 20022 messages (
pacs.008,pacs.002,camt.05x) translate into CIP-56 token transfers and atomic DvP via the CIP-0103 dApp / JSON Ledger API, and back again.In short:
It is not a message bus and not a new rail. Translation happens at the edge; Canton's private, atomically-composable settlement stays native.
What this delivers
pacs.008→ CIP-56 transfer/DvP) plus a public golden-vector conformance suite;pacs.008drives a CIP-56 transfer on DevNet and returns apacs.002(open-source, CI-green, recorded demo);pacs.002status andcamt.05xstatements generated from on-ledger events, with idempotent reconciliation keyed byMsgId/EndToEndId;InstrumentId).Disclosed Contracts and createdEventBlob Handling
The adapter does not fake or manually serialize
createdEventBlob.It reuses the existing token-standard registry choice-context mechanism: it queries the registry off-ledger API (e.g.
POST /registry/transfer-instruction/v1/transfer-factory) forfactoryId,choiceContextData, anddisclosedContracts. Where acreatedEventBlobhas to be (re)fetched, it is read from the participant via the JSON Ledger API active-contracts query withincludeCreatedEventBlob=true(or equivalent gRPC), cached by contract id, and attached to the submission.The transfer is then exercised through the normal CIP-0103 / JSON Ledger API command path, the same way a compliant wallet does. No protocol or CIP-56/CIP-0112 changes are required.
Checklist
/proposals/Notes for Reviewers
This proposal is intentionally narrow and single-objective: v1 covers
pacs.008/pacs.002/camt.05xplus DvP only; all other ISO 20022 message types are explicitly deferred / out of scope.The main points:
pacs.008→ CIP-56 transfer →pacs.002lands on DevNet at Milestone 1, and a public conformance suite makes "adopted" objective rather than aspirational.