Schemas
All dossiers serialize as canonical JSON: sorted keys, UTC Z timestamps, decimal strings, SET vs SEQ array semantics.
Files referenced by: {name, sha256, size}; no binary inline.
Redactions: appear in redactions[] with salted commitments.
schema_id: part of the claim_id domain; versions are immutable.
A. TRADE.ON_BOARD.v1
{
"schema_id":"TRADE.ON_BOARD.v1","version":"1.0",
"fields":{
"order_id":{"type":"string_id","required":true},
"bl_number":{"type":"string_id","required":true},
"seal_number":{"type":"string_id","required":true},
"container_ids":{"type":"array|string_id","cardinality":"SET","required":true},
"load_port":{"type":"string_id","required":true},
"voyage":{"type":"string_id","required":false},
"created_at":{"type":"timestamp_rfc3339","required":true}
},
"files_required":[{"name":"bl.pdf"},{"name":"seal.jpg"}],
"quorum":{"roles":["TERMINAL","CARRIER"],"min_attestations":2,"min_distinct_roles":2},
"freshness_hours":{"TERMINAL":48,"CARRIER":48},
"post_production":true
}
B. TRADE.ARRIVAL_QA.v1
{
"schema_id":"TRADE.ARRIVAL_QA.v1","version":"1.0",
"fields":{
"order_id":{"type":"string_id","required":true},
"asn_number":{"type":"string_id","required":true},
"dc_id":{"type":"string_id","required":true},
"damage_pct":{"type":"decimal_string(precision=2)","required":true},
"shelf_life_days":{"type":"decimal_string(precision=0)","required":true},
"received_at":{"type":"timestamp_rfc3339","required":true}
},
"files_required":[{"name":"dc_receipt.pdf"}],
"quorum":{"roles":["DC_3PL"],"min_attestations":1,"min_distinct_roles":1},
"freshness_hours":{"DC_3PL":24}
}
C. TOKENS.ENERGY.MWH.v1
{
"schema_id":"TOKENS.ENERGY.MWH.v1","version":"1.0",
"fields":{
"device_id":{"type":"string_id","required":true},
"start_ts":{"type":"timestamp_rfc3339","required":true},
"end_ts":{"type":"timestamp_rfc3339","required":true},
"quantity_Wh":{"type":"decimal_string(precision=0)","required":true},
"grid_region":{"type":"string_id","required":true}
},
"files_required":[{"name":"meter_export.csv"}],
"quorum":{"roles":["METROLOGY","AUDITOR"],"min_attestations":2,"min_distinct_roles":2},
"freshness_days":{"METROLOGY":7,"AUDITOR":14}
}
D. TOKENS.CARBON.VCM.v1
{
"schema_id":"TOKENS.CARBON.VCM.v1","version":"1.0",
"fields":{
"program":{"type":"enum","values":["VERRA","GS"],"required":true},
"project_id":{"type":"string_id","required":true},
"vintage":{"type":"string_id","required":true},
"unit_serial":{"type":"string_id","required":true}
},
"files_required":[{"name":"issuance_cert.pdf"}],
"quorum":{"roles":["REGISTRY"],"min_attestations":1,"min_distinct_roles":1},
"freshness_days":{"REGISTRY":30}
}
17. APPENDIX — CLAIM ID FORMULAS
General form:
claim_id = keccak256(chain_id || lane || schema_id || key_blob || pov_hash)
pov_hash: ensures two dossiers with same identity fields but different evidence become different claims.
A. Trade — On-Board (sealed):
key_blob = bl_number || seal_number || sha256( join_sorted(container_ids, "\n") )
B. Trade — Customs Cleared:
key_blob = customs_entry_number || country_code || importer_tax_id
C. Trade — Arrival & QA:
key_blob = asn_number || dc_id || window_bucket(received_at, 3600s)
D. Tokens — Energy (1 MWh):
key_blob = device_id || start_ts || end_ts || quantity_Wh
E. Tokens — Carbon (VCM program serial):
key_blob = program || project_id || vintage || unit_serial
F. Mirror mapping (external registry):
key_blob = program || project_id || vintage || serial
G. Replacement lineage:
corrective claim computes its own claim_id and stores replaces: old_claim_id. Proof pages show the chain.
Mirrors bind to an existing claim_id: they do not create a second claim. We store mirror_id with claim_id linkage.
17. APPENDIX — GAS BENCHMARKS
Notes: gas varies by calldata size, role set, and storage warm/cold state. These are p50/p95 targets from devnets; updated with on-chain telemetry post-launch. Fees shown at 0.02 gwei L2 gas and $2,000/ETH (changeable).
Tx type
Core work
Gas p50
Gas p95
Est. fee (USD) p50
trade.proof (Gate PASS)
verify roles, equality, reserve One-Claim
120k
180k
~$0.05
trade.emt+release
mint EMT, flip Locked→Unlocked, fee calc, 50% burn
210k
300k
~$0.09
tokens.mint
Gate PASS + token storage
160k
220k
~$0.07
tokens.settle (Buy)
transfer, 4% fee, 50% burn
190k
260k
~$0.08
tokens.retire
mark retired, 4% fee, 50% burn
200k
280k
~$0.09
registry.mirror.create
bind external serial to claim_id
110k
160k
~$0.05
pov.revoke
record revocation + freeze flags
95k
140k
~$0.04
trade.replace
corrective EMT (replaces)
180k
250k
~$0.08
gov.param.change (Timelock exec)
ParameterStore update
80k
120k
~$0.03
What’s expensive? Big dossiers (large arrays) and many roles increase calldata; Merkle-proof verification (on-chain) adds ~40–70k per proof (we often accept attested off-chain checks to keep business clocks fast). Burns are constant-cost ERC-20 transfers.
17. APPENDIX — CONTRACT HEADERS
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice PoV Gate
interface IPoVGate {
/// @dev returns PASS and a handle; fails with explicit errors on mismatch
function submitProof(
bytes32 schemaId,
bytes32 povHash,
bytes calldata dossierBytes, // canonical JSON bytes (optional echo)
bytes calldata attestorBundle, // role-signed attestations
bytes calldata keyBlob, // identity fields blob
bytes32 claimIdPreview
) external returns (bytes32 gatePassId, bytes32 claimId);
event GatePass(bytes32 indexed schemaId, bytes32 indexed claimId, bytes32 povHash);
error E_CANONICAL_DRIFT(); error E_FORMAT_INVALID(); error E_SET_NOT_SORTED();
error E_QUORUM_MISSING(); error E_STALE_ATTEST(); error E_HASH_MISMATCH();
error E_ONECLAIM_TAKEN(); error E_PENDING_FUNDS();
}
/// @notice One-Claim (global uniqueness)
interface IOneClaim {
function reserve(bytes32 claimId) external; // only Gate
function finalize(bytes32 claimId) external; // only Gate/Settlement
function status(bytes32 claimId) external view returns (uint8); // 0 FREE,1 RESERVED,2 FINAL
event ClaimFinalized(bytes32 indexed claimId);
error AlreadyTaken();
}
/// @notice EMT (non-transferable stage receipts)
interface IEMT {
function mint(bytes32 orderId, bytes32 stageId, bytes32 subLotId,
bytes32 claimId, bytes32 povHash) external;
event EMTMinted(bytes32 indexed orderId, bytes32 indexed stageId,
bytes32 indexed subLotId, bytes32 claimId, bytes32 povHash);
}
/// @notice Trade Settlement (Locked→Unlocked EDSD + fee/burn)
interface ITradeSettlement {
function release(bytes32 orderId, bytes32 stageId, bytes32 gatePassId) external;
event ReleasePosted(bytes32 indexed orderId, bytes32 indexed stageId,
uint256 amountEdsd, uint256 fee, bytes32 burnHash);
}
/// @notice Tokens marketplace (buy/retire)
interface ITokens {
function mint(bytes32 schemaId, bytes32 povHash, bytes calldata dossierBytes,
bytes calldata attestorBundle, bytes calldata keyBlob) external returns (uint256 tokenId);
function settle(uint256 tokenId, address buyer) external;
function retire(uint256 tokenId, address beneficiary, string calldata purpose) external;
event TokenMinted(uint256 indexed tokenId, bytes32 claimId, bytes32 povHash);
event TokenSettled(uint256 indexed tokenId, address buyer, uint256 fee, bytes32 burnHash);
event TokenRetired(uint256 indexed tokenId, address beneficiary, uint256 fee, bytes32 burnHash);
}
/// @notice Fee Router / Burner
interface IFeeRouter {
function settleTradeFee(bytes32 orderId, bytes32 stageId, uint256 releaseAmountEdsd) external
returns (uint256 fee, bytes32 burnHash);
function settleTokenFee(uint256 amountEdsd) external returns (uint256 fee, bytes32 burnHash);
event FeeBurned(bytes32 indexed ref, uint256 fee, uint256 burnedEdm, bytes32 burnTx);
}
/// @notice Registry Mirror
interface IRegistryMirror {
function create(bytes32 programId, bytes32 serialHash, bytes32 claimId, bytes32 povHash,
bytes calldata registrySig) external returns (bytes32 mirrorId);
function replace(bytes32 mirrorId, bytes32 newSerialHash, bytes calldata registrySig) external;
event MirrorCreated(bytes32 indexed mirrorId, bytes32 indexed claimId, bytes32 programId);
event MirrorReplaced(bytes32 indexed oldId, bytes32 indexed newId);
}
/// @notice Attestor Registry
interface IAttestorRegistry {
function addAttestor(address entity, bytes32[] calldata roles, bytes32[] calldata schemaIds) external;
function setKey(address entity, bytes32 keyId, bool active) external;
function suspend(address entity) external;
function isActive(address entity, bytes32 role) external view returns (bool);
event AttestorAdded(address indexed entity); event AttestorSuspended(address indexed entity);
}
/// @notice Governance Parameter Store (bounded)
interface IParameterStore {
function set(bytes32 key, bytes calldata value) external; // bounds enforced internally
function get(bytes32 key) external view returns (bytes memory value);
event ParamChanged(bytes32 indexed key, bytes oldVal, bytes newVal, uint64 effectiveFrom);
}
Full ABIs + error catalogs ship in the SDK and /v1/contracts.
17. APPENDIX — KPIs & SLOs
A. L2 & Infra:
Block time (p50/p95): ≤ 2s / 4s;
Batch to L1 (median): 2–10 min; anchor-guarded switch at ≥ 60 min lag;
Forced inclusion resolution: ≤ 30 min;
Availability: ≥ 99.9% monthly
B. PoV / Admissibility:
EMT→release latency (p50/p95): ≤ 5s / 15s;
Gate fail mix: serialization ≤ 1%; identity ≤ 2%; sensors ≤ 1%;
Duplicate block rate (One-Claim): > 99.9%;
Revocation SLA: detect→freeze ≤ 15 min; pack ≤ 4 h; resume ≤ 72 h p95
C. Marketplaces (Ops):
Disputes per 100 gates: ≤ 3;
False-block (buyer review) rate: ≤ 1%;
Top-up SLA breaches: ≤ 1% of gates;
Throughput: capacity ≥ 300 orders/month per mature region
D. Finance & Economics:
Burn coverage: 100% of settlements/releases with visible burn hash;
PoR daily freshness: 100%;
Escrow reconciliation (Trade):
escrow_start − Σ(stage_fees) = escrow_end 100%;
Advance loss rate (if enabled): 0; auto-sweep success ≈100%
E. Compliance & Interop:
Mirror SLA (freeze→replace): ≤ 48 h p95;
Audit replay success: 100% from L1 blobs + proof packs;
Redaction compliance: 100% of redactable paths carry salted commitments
F. Governance:
Param changes within bounds: 100%; no failed executes;
Timelock visibility: 100% proposals w/ ≥ 72 h queue;
Vote participation (avg): ≥ 15% veEDM;
No proposals against brakes: 100% filtered
Formulas & sources:
Latencies from L2 indexer; burns from Fee Router events; duplicates from One-Claim logs; PoR from treasury snapshots; mirrors from mirror events; governance from Governor/Timelock events. Each KPI links to a dashboard and raw event queries in the Explorer.
Last updated