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