KiiWORKS / Documentation
KiiWORKS Trade Rails
SOURCE · docs/trade-rails.md · synced from the engineering repo
KiiWORKS Trade Rails
Institutional infrastructure for global trade, anchored to BlockDAG.
The KiiWORKS trade-rails suite is the second pillar of the v2 platform. Where the DPP layer is the product spine (what a thing is, who made it, how it was made), the trade-rails layer is the flow spine — how that thing moves across borders, who has title to it at each step, what regulators are entitled to know, and how its movement is paid for.
This document is the architecture reference for the new capability surface. Implementation is a 6-engineer-month build; this commit lands the credible scaffold that compiles, tests, and proves the design.
1. Scope
Seven capability families:
- Trade documents (typed) — Bill of Lading (incl. eBL), Sea Waybill, Air Waybill, Multimodal Transport Document, Letter of Credit, Certificate of Origin, Commercial Invoice, Packing List, Warehouse Receipt.
- Customs declarations — EU Single Window / SAD, HS code classification (with full 99-chapter index), customs procedure codes, declaration lifecycle.
- CBAM declarations — Embedded emissions reports, default values, verifier attestation envelope, quarterly and annual reporting cycle.
- eFTI — Electronic Freight Transport Information envelopes with competent-authority access filtering.
- Trade-finance workflows — LC issuance / advising / confirming / presentation; eBL endorsement and surrender; documentary collection (URC 522); demand guarantees (URDG 758).
- Sanctions and dual-use screening — Typed primitives for OFAC, EU Consolidated, UK OFSI, UN Security Council, BIS Entity List, EU Dual-Use; in-memory fixture screener; audit trail.
- Multi-modal logistics standards — DCSA (existing), IATA Cargo-XML stubs, UIC RailML stubs, UNECE document-type code table, Incoterms 2020.
2. Layering
┌─────────────────────────────────────────────┐
│ CLI (kiiworks trade / customs / cbam / │
│ sanctions) │
└────────────┬────────────────────────────────┘
│ HTTP JSON
▼
┌─────────────────────────────────────────────┐
│ Platform Services (Axum @ :4000/api/*) │
│ trade · customs · cbam · sanctions · efti │
└────────────┬────────────────────────────────┘
│ Trait calls
▼
┌─────────────────────────────────────────────┐
│ Library Crates │
│ trade-documents · customs · sanctions │
└────────────┬────────────────────────────────┘
│ Type imports
▼
┌─────────────────────────────────────────────┐
│ Standards Crate (kiiworks-standards) │
│ cbam · mletr · ucp · efti · unece_extended │
│ iata · uic · dcsa · w3c · gs1 · ... │
└────────────┬────────────────────────────────┘
│ Anchor hashes
▼
┌─────────────────────────────────────────────┐
│ Kaspa BlockDAG (Toccata covenants, KIP-17) │
└─────────────────────────────────────────────┘
Each layer has a single responsibility:
- Standards — typed constants and validators. No state. No I/O.
- Library crates — domain types, validation rules, traits. No I/O.
- Platform services — Axum routes, in-memory implementations of service traits, lifecycle state machines. The seam where REST meets the domain.
- CLI — argument parsing + JSON skeleton emission. The CLI does not yet POST to the node directly — that comes in phase 2.
3. Architecture diagram
flowchart TB
subgraph CLI[CLI - tools/cli]
cli_trade[kiiworks trade lc create]
cli_customs[kiiworks customs declare]
cli_cbam[kiiworks cbam quarterly]
cli_sanctions[kiiworks sanctions screen]
end
subgraph Services[Platform Services - :4000/api]
svc_trade[trade]
svc_customs[customs]
svc_cbam[cbam]
svc_sanctions[sanctions]
svc_efti[efti]
end
subgraph Libs[Library Crates]
lib_trade_docs[trade-documents]
lib_customs[customs]
lib_sanctions[sanctions]
end
subgraph Standards[Standards Crate]
s_cbam[cbam]
s_mletr[mletr]
s_ucp[ucp]
s_efti[efti]
s_uniext[unece_extended]
s_iata[iata]
s_uic[uic]
s_dcsa[dcsa - existing]
end
subgraph Anchor[Anchoring & Identity - existing]
forge[anchor-tree/forge]
did[identity-auth]
kaspa[(Kaspa BlockDAG)]
end
cli_trade -.HTTP.-> svc_trade
cli_customs -.HTTP.-> svc_customs
cli_cbam -.HTTP.-> svc_cbam
cli_sanctions -.HTTP.-> svc_sanctions
svc_trade --> lib_trade_docs
svc_customs --> lib_customs
svc_cbam --> s_cbam
svc_sanctions --> lib_sanctions
svc_efti --> s_efti
lib_trade_docs --> s_mletr
lib_trade_docs --> s_ucp
lib_trade_docs --> s_uniext
lib_customs --> s_uniext
lib_customs --> s_dcsa
svc_trade --> forge
svc_trade --> did
forge --> kaspa
4. Standards modules added
| Module | Purpose | Tests |
|---|---|---|
cbam | Goods category, reporting period, embedded-emissions reports, verifier attestation, certificate calculation | 8 |
mletr | UNCITRAL Model Law on Electronic Transferable Records — singularity, exclusive control, transfer history | 8 |
ucp | UCP 600 articles, LC form & status, eUCP 2.1, URDG 758 guarantees, URC 522 collections | 7 |
efti | EU eFTI Regulation 2020/1056 — envelopes, competent authority access rules | 7 |
unece_extended | UN/CEFACT document-type codes (TDED 1001), Incoterms 2020, payment terms, transport modes | 7 |
iata | IATA Cargo-XML message types (FWB, FFM, FHL, …) and minimal envelope | 6 |
uic | UIC RailML / TAF-TSI rail-freight message types and envelope | 6 |
vlei | GLEIF vLEI / LEI / minimal KERI — issuer hierarchy and chain types | 18 |
All eight modules follow the existing crates/standards pattern: pure
types, no I/O, comprehensive serde round-trip tests, snake_case JSON
keys.
5. Library crates added
crates/trade-documents
Canonical Rust types for the standard family of international trade documents. The design hinges on three choices:
- One enum, many variants. All trade documents are variants of
TradeDocumentrather than separate types. The envelope (TradeDocumentEnvelope) carries id, issuer, parties, status, signatures, MLETR compliance — the variant carries the payload. This keeps the trade service’s storage and routing uniform. - eBL is a BillOfLading + MLETR compliance. Not a separate type.
An envelope is recognised as an electronic transferable record
when the inner document is potentially negotiable and the envelope
has
mletr_compliance: Some(...). The MLETR descriptor carries the singularity guarantee, control predicate, integrity method, and full transfer history. - Lifecycle is enforced by the envelope, not by the variant. A
transition(target)method on the envelope validates state transitions (Draft → Issued → Endorsed → Surrendered, etc.) and refuses illegal moves.
11 unit tests covering BoL validation, eBL recognition, multimodal mode-of-transport requirements, LC validation, lifecycle transitions, invoice total validation, AWB weight validation, serde round-trip.
crates/customs
HS code newtype with full validation, 99-chapter index with WCO HS 2022 names, 13 EU customs procedures, EU Single Window declaration shape with goods lines, transport information, and a validation pass that enforces gross-≥-net and contiguous sequence numbering.
29 unit tests across HS code parsing, chapter lookup, procedure classification (import/export), declaration validation, serde.
crates/sanctions
Six list authorities (OFAC, EU Consolidated, UK OFSI, UN Security
Council, BIS Entity List, EU Dual-Use), typed entity records, a
Screener async trait, and an in-memory fixture screener with a
deterministic name-normalization + scoring algorithm. The screener
returns Clear, PossibleMatch { matches }, or ConfirmedHit { matches }; only the last requires a hard block.
12 unit tests across list authority, entity serde, screening clear / match / confirmed-hit paths, bulk screening, empty-name rejection, country-match bonus.
6. Platform services added
| Service | Lib name (Cargo) | Crate path | Routes mount |
|---|---|---|---|
| Trade workflow | kiiworks-trade | platform/trade | /api/trade/* |
| Customs | kiiworks-customs-service | platform/customs | /api/customs/* |
| CBAM | kiiworks-cbam | platform/cbam | /api/cbam/* |
| Sanctions | kiiworks-sanctions-service | platform/sanctions | /api/sanctions/* |
| eFTI | kiiworks-efti | platform/efti | /api/efti/* |
Every service follows the established v2 pattern: a service trait, an
in-memory implementation, a TraitState containing Arc<dyn Trait>,
and a service_routes() -> Router<TraitState> function. All five are
registered in platform/node/src/services.rs so the standalone
kiiworks binary serves them at :4000 alongside the existing 39.
Test counts (in-memory implementations):
trade— 10 tests (LC lifecycle, eBL endorsement, collections, document validation)customs— 10 tests (submit/amend/withdraw/accept/release lifecycle, MRN assignment)cbam— 11 tests (declaration creation, report addition with validation, attestation, certificates calculation, submittability)sanctions— 10 tests (clear/match audit, bulk, list defaulting)efti— 10 tests (envelope storage, authority-filtered view, access-rule grants, redaction)
Total: 51 platform-service tests, plus 52 library-crate tests, plus 47 standards tests added.
7. End-to-end cross-border workflow
A canonical scenario: 100 tonnes of hot-rolled steel from Mumbai to Rotterdam, financed by an LC, carried as an eBL, declared at customs on arrival, with the CBAM declaration filed quarterly afterwards.
Step 1 — KYC + sanctions screen (pre-contract)
The supplier-side onboarding flow screens the buyer DID through
/api/sanctions/screen against OFAC, EU Consolidated, UK OFSI, UN
Security Council. On Clear, the result hash is logged to
auditable-item-stream and surfaced in the trust dashboard. On
ConfirmedHit, the workflow halts and the audit log records the
block.
Step 2 — LC issuance (UCP 600)
The buyer’s bank issues a sight LC via POST /api/trade/documents,
with TradeDocument::LetterOfCredit payload. The state machine moves
Draft → Issued. The advising bank in India is then asked to advise
the credit (POST /api/trade/lc/{id}/advise).
Step 3 — eBL issuance (MLETR)
The carrier issues an electronic Bill of Lading via POST /api/trade/documents. The envelope sets negotiable: true and
attaches an MletrCompliance block with:
singularity.method = Blockchainand a Kaspa P2PK anchor transaction id (issued viacrates/forge)control.method = PrivateKeyPossessionwith the shipper’s DID
The eBL hash is anchored on Kaspa using the existing burn-anchor strategy (P2PK 1-KAS output, no OP_RETURN — Kaspa rejects those as non-standard).
Step 4 — Endorsement chain
As the goods move, the eBL is endorsed via POST /api/trade/documents/{id}/endorse. Each endorsement appends a
ControlTransfer to the MLETR descriptor, anchored on Kaspa. The
signer is identified by an OOR vLEI (issued by the carrier’s
Legal Entity vLEI) — /api/vlei/verify walks the chain back to GLEIF
Root before the endorsement is accepted, so an endorsement signed by
an unaccredited individual fails before the on-chain anchor is even
attempted. The singularity guarantee + chain-of-control history are
what makes the
eBL functionally equivalent to a paper B/L.
Step 5 — Documents under LC
The shipper presents documents under the LC (POST /api/trade/lc/{id}/present) — the eBL id, commercial invoice id,
certificate of origin id, and packing list id. The state machine
moves to DocumentsPresented. If the issuing bank examines them and
finds compliance (UCP 600 Article 14), it accepts (/accept) then
pays (/pay). If discrepant, POST /lc/{id}/reject records the
specific discrepancies.
Step 6 — Customs declaration on arrival
On arrival at Rotterdam the consignee or his broker submits a SAD via
POST /api/customs/declarations. The declaration carries the HS code
(7208 1000 for hot-rolled steel coils, validated by crates/customs)
and the customs procedure release_for_free_circulation (40). The
service runs validate() to ensure gross-≥-net, sequence numbering,
positive invoice, then transitions to Submitted. Customs accepts
(/accept) which assigns an MRN, then releases (/release).
Step 7 — eFTI access for control authorities
Independently of customs, the eFTI envelope was filed by the carrier
when the shipment crossed the border (POST /api/efti/envelopes).
Customs queries it via
GET /api/efti/envelopes/{id}/view/customs and sees the consignment,
parties, and goods subsets only; dangerous-goods detail is redacted
unless an access rule grants it.
Step 8 — CBAM declaration (steel is in scope)
Iron and steel is a CBAM-covered category. The declarant builds a
quarterly CBAM declaration via POST /api/cbam/declarations for the
period 2026-Q3, then adds an embedded-emissions report via POST /api/cbam/declarations/{id}/reports: 100 tonnes × 2.1 tCO2e/tonne
direct = 210 tCO2e. For the transitional period 2026-Q3 (within the
declarative period — under EU Regulation 2023/956 the transitional
period runs through 2025-12-31; from 2026-01-01 the definitive period
begins and a verifier attestation becomes mandatory).
For the definitive period, the declarant attaches a verifier
attestation via POST /api/cbam/declarations/{id}/attest from an
accredited verifier asserting reasonable assurance. Only then does
is_submittable() return true. GET /certificates returns the count
of CBAM certificates required to surrender — 210 tCO2e → 210 certificates.
Step 9 — Lifecycle anchoring
At each significant lifecycle transition (LC issued, eBL issued, eBL
endorsed, customs released, CBAM submitted), the platform anchors the
state hash on Kaspa via the existing forge / anchor-tree services.
The result is a verifiable, ordered timeline of the transaction from
contract signing through final regulatory close-out.
11. Catena-X interoperability
The DPP layer also ingests product passports from
Catena-X — the dominant European automotive
data space — in Semantic Aspect Meta Model (SAMM) form. The bridge is
implemented by crates/catena-x and exposed through the platform
service:
- REST:
POST /api/dpp/import/catena-x?format=json|ttl - CLI:
kiiworks dpp import catena-x --aspect battery --file <path>
The current battery aspect (io.catenax.battery.battery_pass) is
mapped into the canonical DigitalProductPassport directly, with any
Catena-X-specific fields preserved on passport.extensions.catena_x
so no data is lost in translation. Textile and electronics aspects
follow in the next milestone.
See Catena-X Interoperability Guide for the field mapping, REST/CLI usage, and where to obtain the canonical aspect models.