Skip to content
QIRO

Documentation

Integration.

Everything the interface needs to run on real data, and exactly what it does when it can't.

Data mode
demo
Registry
unset
Env errors
0

Environment

Every network-facing value is read once in lib/chain/config.ts and validated with zod. Components never read process.env.

VariableCurrentRequiredNotes
NEXT_PUBLIC_RPC_URLhttps://rpc.mainnet.chain.robinhood.comnoJSON-RPC endpoint. Defaults to the public Robinhood Chain mainnet RPC.
NEXT_PUBLIC_CHAIN_ID4663noEVM chain id. 4663 mainnet · 46630 testnet.
NEXT_PUBLIC_EXPLORER_URLhttps://robinhoodchain.blockscout.comnoBlockscout origin used for address / tx / block links.
NEXT_PUBLIC_QIRO_REGISTRY_ADDRESSunsetyesQiroRegistry address. Unset → demo data mode.
NEXT_PUBLIC_QIRO_SETTLEMENT_ADDRESSunsetnoQiroSettlement address. Unset → settlement record shows "not configured".
NEXT_PUBLIC_QIRO_DEPLOY_BLOCKunsetnoRegistry deploy block — narrows provenance log scans.
NEXT_PUBLIC_REFERENCE_API_URLunsetnoHTTPS reference service. GET {url}/references/{id}.
NEXT_PUBLIC_AGE_FRESH_SECONDS300noFRESH upper bound (seconds).
NEXT_PUBLIC_AGE_AGING_SECONDS1800noAGING upper bound / STALE lower bound (seconds).
NEXT_PUBLIC_ALIGNMENT_TOLERANCE_BPS10noMax claim/reference value difference for ALIGNED.

Copy .env.example to .env.local. NEXT_PUBLIC_* values are inlined at build time — rebuild after changing them.

Registry interface

The expected ABI lives in lib/contracts/abis/registry.ts and the normalisers in lib/contracts/registry.ts. Replace the ABI with the compiled artifact when the production registry ships; only the normaliser needs to follow.

FunctionReturnsFields
claimCount()uint256Number of claims ever registered.
claimIdAt(uint256)bytes32Claim id by index; the UI lists the newest 200.
getClaim(bytes32)Claimid · label · issuer · asset · assetSymbol · assetName · assetType · value · valueDecimals · quantity · quantityDecimals · timestamp · blockNumber · referenceId · state
getReference(bytes32)Referenceid · label · source · sourceName · asset · value · valueDecimals · timestamp · blockNumber · status

Events (provenance timeline)

  • ClaimCreated(bytes32 claimId, address issuer, address asset, uint256 value, bytes32 referenceId)
  • ReferenceLinked(bytes32 claimId, bytes32 referenceId)
  • ReferenceUpdated(bytes32 referenceId, uint256 value, uint64 timestamp)
  • SettlementStateChanged(bytes32 claimId, uint8 state)

Enums — assetType 0 cash-equivalent · 1 treasury · 2 equity · 3 commodity · 4 credit · 5 fund. state 0 pending · 1 active · 2 settled · 3 disputed. source 0 onchain · 1 api · 2 oracle · 3 manual. status 0 unknown · 1 available · 2 unavailable. Human ids (qUSD-04291) map to bytes32 as right-padded UTF-8, or keccak256 when longer than 32 bytes.

Settlement contract

getSettlement(bytes32) → expectedValue · referenceValue · valueDecimals · state · settledAt

SettlementAligned(bytes32 claimId, bytes32 referenceId, uint256 expectedValue, uint256 referenceValue)

Reference adapters

lib/references/{onchain,api,oracle,manual}.ts. Each adapter resolves a locator into the same Reference shape or reports an explicit failure: not-configured · not-found · unavailable · malformed · error.

  • onchainnot configured

    Registry (on-chain)

  • apinot configured

    Reference API (HTTPS)

  • oracleconfigured

    Oracle feed (AggregatorV3)

  • manualnot configured

    Manual attestation

Resolution order when a claim does not name a source: onchain → api → manual. Oracle needs a feed address per reference (AggregatorV3 latestRoundData).

Reference API payload

{
  "referenceId": "USDG-RESERVE-882",
  "source": "Treasury Reference",
  "asset": "USDG",
  "value": "24850.00",          // string | number | null
  "currency": "USD",
  "decimals": 2,
  "timestamp": 1756221221,      // unix seconds | ISO-8601 | null
  "blockNumber": null,
  "transactionHash": null,
  "status": "available",        // available | unavailable | unknown
  "metadata": { "custodian": "Reserve account 882" }
}

Validated with zod; anything that does not match is REFERENCE UNAVAILABLE (malformed), never a guessed value.

Age engine

age = now − last observation, computed on one shared 1s clock (hooks/useNow.ts). A missing timestamp is AGE UNKNOWN, not 0.

Fresh
0 – 5 min
Aging
5 min – 30 min
Stale
30 min+

Formats — human 18s · 02m 41s · 1h 18m · 2d 04h; clock hh:mm:ss. AGE DELTA = |claim age − reference age| with direction (claim older / reference older / in sync). Requires both timestamps.

Alignment

lib/settlement/alignment.ts. Evaluated in order: no reference → REFERENCE UNAVAILABLE · unknown reference timestamp → UNKNOWN · claim pending → PENDING · reference stale → STALE REFERENCE · missing value / currency mismatch → UNKNOWN · |Δ| > 10 bps → VALUE MISMATCH · disputed → PENDING · otherwise ALIGNED.

Money is compared as fixed-point bigint scaled to the larger decimals; no floating point until display.

Demo isolation

lib/data/demo.ts is the only file that knows demo records exist. It implements the same ClaimSource interface as lib/data/onchain.ts and is selected in lib/data/source.ts purely on whether the registry address is set.

  • · Every demo record carries origin: 'demo' and renders a DEMO badge.
  • · Demo block numbers and addresses never link to the explorer.
  • · Demo timestamps are offsets from first load, so ages are real elapsed time — the feed does not fabricate new activity.
  • · Chain lookups (tx hash, address) and the network indicator always hit the live RPC, even in demo mode.

Trust rule

Qiro never fabricates financial verification.

  • Reference cannot be fetched → REFERENCE UNAVAILABLE
  • Timestamp cannot be determined → AGE UNKNOWN
  • Settlement cannot be verified → UNVERIFIED / UNKNOWN
  • Data is not from a real source → DEMO