TRACE Example App

TRACE is a full-stack SAP Fiori application demonstrating how ODATANO integrates Cardano into enterprise workflows. It tracks pharmaceutical drug batches from manufacturer to pharmacy using NFTs as on-chain proof and CIP-30 browser wallets for signing.

What TRACE Demonstrates

  • Batch NFT Minting — Manufacturer mints a unique NFT per drug batch with on-chain datum via Plutus V3
  • Chain of Custody Transfers — Each handoff (manufacturer → distributor → pharmacy) is a Plutus spend transaction
  • Document Anchoring — SHA-256 hashes of certificates, lab reports, and cold-chain telemetry anchored via CIP-20 metadata
  • Public Verification — Anyone can verify a batch’s full custody chain against on-chain data
  • Zero Key Custody — TRACE/ODATANO never hold private keys; all signing happens in the user’s browser wallet

Tech Stack

LayerTechnology
Smart ContractsAiken (Plutus V3)
BlockchainCardano preview testnet
Chain Gateway@odatano/core (CAP plugin)
BackendSAP CAP v9, Node.js, TypeScript
DatabaseSQLite (dev) / SAP HANA (prod)
FrontendFreestyle SAPUI5 (sap_horizon theme)
SigningCIP-30 browser wallets (Nami, Eternl, Lace)

Transaction Signing Flow

1. User clicks action (e.g. "Mint NFT")
2. App calls OData action        → { unsignedCbor, buildId }
3. App calls wallet.signTx(cbor) → browser wallet popup
4. User confirms in wallet        → signedCbor
5. App calls SubmitSigned         → { txHash, status: "SUBMITTED" }
6. Background polling (30s)       → status: "CONFIRMED" | "FAILED"

Smart Contract

The Aiken validator (pharma_trace.ak) enforces two rules on-chain:

Mint policy — Only the manufacturer (parameterized VKH) can mint, and exactly 1 token per transaction.

Spend validator — Transfers require the current holder’s signature and a continuing output with updated datum.

Datum:    ChainOfCustody { manufacturer, current_holder, batch_id, step }
Redeemer: Action::Transfer { next_holder }

OData Actions

ActionDescription
MintBatchNft(batchId)Build unsigned mint transaction
TransferBatch(batchId, toParticipantId, ...)Build unsigned transfer transaction
SubmitSigned(buildId, signedTxCbor)Submit externally signed transaction
CheckPendingTransactions()Poll all SUBMITTED events for confirmation
AnchorDocument(batchId, documentHash, ...)Anchor document hash on-chain
VerifyBatch(batchIdOrFingerprint)Public chain-of-custody verification

Quick Start

# Prerequisites: Node.js >= 18, CIP-30 wallet on preview network

git clone https://github.com/ODATANO/TRACE && cd TRACE
npm install
npm run deploy       # Creates SQLite DB + seed data

TX_BUILDERS=buildooor npx cds watch

Open http://localhost:4004/trace/webapp/index.html.

Data Model

Participants (Manufacturer | Distributor | Pharmacy | Regulator)

     └──< Batches (DRAFT → MINTED → IN_TRANSIT → DELIVERED | RECALLED)

            ├──< OnChainAssets   (policyId, assetName, UTxO ref)
            ├──< ProofEvents     (MINT, TRANSFER, VERIFY, DOCUMENT_ANCHOR)
            └──< DocumentAnchors (doc hash, type, cold-chain temps)

GitHub

Source code and documentation: github.com/ODATANO/TRACE