This demo shows a local end-to-end document oracle flow from Canton/Daml to an EVM contract through a backend service and a SATP/Cactus gateway.
Use QUICK_SETUP.md for the command-by-command setup and test guide. This README explains what runs and how the pieces fit together.
The demo starts four main parts:
- Canton/Daml document contracts: the Canton sandbox builds the Daml package and seeds test data from
daml/Unlockit/Test.daml. The seeded document contract uses document iddoc-001. - Backend document listener: the Quarkus backend reads Canton active contracts through the JSON API proxy, maps document contracts into backend document DTOs, and submits them through the same transfer path used by
POST /api/documents/transfer. - SATP/Cactus gateway: the Oracle Case 1 gateway receives the backend request and executes the oracle transaction against the configured EVM network.
- Hardhat EVM OracleTestContract: the local Hardhat network hosts
OracleTestContract; successful transfers callsaveDocument, and tests verify results withgetDocument.
Canton sandbox document contracts
-> Canton JSON API proxy
-> backend startup reconciliation and live polling
-> SATP/Cactus Oracle Case 1 gateway
-> Hardhat EVM OracleTestContract
When the backend starts, DocumentCreatedListener performs one reconciliation pass:
- reads the current Canton ledger end offset;
- queries active contracts from Canton through the JSON API proxy;
- selects document-shaped contracts from the Daml test module;
- converts each document contract into the backend transfer DTO;
- submits the document to the SATP/Cactus gateway;
- stores the document in
OracleTestContracton the local Hardhat EVM.
This is how the startup-seeded Canton document, doc-001, reaches the EVM contract without a manual transfer call.
After startup reconciliation, the listener keeps polling Canton. It stores the latest ledger offset, checks for newer offsets on the configured interval, and re-queries active contracts when the ledger changes.
A new document created while the system is already running, such as the test script Unlockit.Test:createSecondDocument, is picked up by polling and transferred through the same backend -> gateway -> EVM path. No backend restart is required for ordinary runtime document creation.
Run the Oracle Case 1 setup before the root Compose stack. The setup compiles and deploys OracleTestContract, starts the Hardhat EVM and SATP/Cactus gateway, and writes generated runtime config under:
docker/oracle/case_1/.generated/oracle-case-1.envdocker/oracle/case_1/.generated/oracle-case-1.json
The generated env file supplies values such as:
SATP_ORACLE_NETWORK_ID=HardhatTestNetwork1SATP_ORACLE_CONTRACT_ADDRESS=<deployed OracleTestContract address>SATP_ORACLE_CONTRACT_ARTIFACT_PATH=/app/EVM/artifacts/contracts/OracleTestContract.sol/OracleTestContract.json
The root Compose backend loads the generated env file when it exists. Do not edit generated files by hand; rerun the setup script when you need a fresh deployment or address.
- Creating another Canton document at runtime: no backend restart is needed; live polling detects the ledger change.
- Restarting only the backend: startup reconciliation runs again against the current Canton active contracts.
- Restarting only Canton: the sandbox ledger is in-memory, so seeded data is recreated.
- Changing
SATP_DOCUMENTS_LISTENER_*,SATP_ORACLE_*, orCANTON_DOCUMENT_TEMPLATE_ID: restart the backend/root Compose stack so Quarkus reads the new environment. - Redeploying
OracleTestContractto a new generated address: restart the backend/root Compose stack after rerunning Oracle setup so it reloads the new address.
For exact commands, expected logs, runtime insertion checks, and troubleshooting, see QUICK_SETUP.md.