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:

  1. 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.
  2. Customs declarations — EU Single Window / SAD, HS code classification (with full 99-chapter index), customs procedure codes, declaration lifecycle.
  3. CBAM declarations — Embedded emissions reports, default values, verifier attestation envelope, quarterly and annual reporting cycle.
  4. eFTI — Electronic Freight Transport Information envelopes with competent-authority access filtering.
  5. Trade-finance workflows — LC issuance / advising / confirming / presentation; eBL endorsement and surrender; documentary collection (URC 522); demand guarantees (URDG 758).
  6. 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.
  7. 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

ModulePurposeTests
cbamGoods category, reporting period, embedded-emissions reports, verifier attestation, certificate calculation8
mletrUNCITRAL Model Law on Electronic Transferable Records — singularity, exclusive control, transfer history8
ucpUCP 600 articles, LC form & status, eUCP 2.1, URDG 758 guarantees, URC 522 collections7
eftiEU eFTI Regulation 2020/1056 — envelopes, competent authority access rules7
unece_extendedUN/CEFACT document-type codes (TDED 1001), Incoterms 2020, payment terms, transport modes7
iataIATA Cargo-XML message types (FWB, FFM, FHL, …) and minimal envelope6
uicUIC RailML / TAF-TSI rail-freight message types and envelope6
vleiGLEIF vLEI / LEI / minimal KERI — issuer hierarchy and chain types18

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 TradeDocument rather 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

ServiceLib name (Cargo)Crate pathRoutes mount
Trade workflowkiiworks-tradeplatform/trade/api/trade/*
Customskiiworks-customs-serviceplatform/customs/api/customs/*
CBAMkiiworks-cbamplatform/cbam/api/cbam/*
Sanctionskiiworks-sanctions-serviceplatform/sanctions/api/sanctions/*
eFTIkiiworks-eftiplatform/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 = Blockchain and a Kaspa P2PK anchor transaction id (issued via crates/forge)
  • control.method = PrivateKeyPossession with 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.