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.
| Variable | Current | Required | Notes |
|---|---|---|---|
| NEXT_PUBLIC_RPC_URL | https://rpc.mainnet.chain.robinhood.com | no | JSON-RPC endpoint. Defaults to the public Robinhood Chain mainnet RPC. |
| NEXT_PUBLIC_CHAIN_ID | 4663 | no | EVM chain id. 4663 mainnet · 46630 testnet. |
| NEXT_PUBLIC_EXPLORER_URL | https://robinhoodchain.blockscout.com | no | Blockscout origin used for address / tx / block links. |
| NEXT_PUBLIC_QIRO_REGISTRY_ADDRESS | unset | yes | QiroRegistry address. Unset → demo data mode. |
| NEXT_PUBLIC_QIRO_SETTLEMENT_ADDRESS | unset | no | QiroSettlement address. Unset → settlement record shows "not configured". |
| NEXT_PUBLIC_QIRO_DEPLOY_BLOCK | unset | no | Registry deploy block — narrows provenance log scans. |
| NEXT_PUBLIC_REFERENCE_API_URL | unset | no | HTTPS reference service. GET {url}/references/{id}. |
| NEXT_PUBLIC_AGE_FRESH_SECONDS | 300 | no | FRESH upper bound (seconds). |
| NEXT_PUBLIC_AGE_AGING_SECONDS | 1800 | no | AGING upper bound / STALE lower bound (seconds). |
| NEXT_PUBLIC_ALIGNMENT_TOLERANCE_BPS | 10 | no | Max 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.
| Function | Returns | Fields |
|---|---|---|
| claimCount() | uint256 | Number of claims ever registered. |
| claimIdAt(uint256) | bytes32 | Claim id by index; the UI lists the newest 200. |
| getClaim(bytes32) | Claim | id · label · issuer · asset · assetSymbol · assetName · assetType · value · valueDecimals · quantity · quantityDecimals · timestamp · blockNumber · referenceId · state |
| getReference(bytes32) | Reference | id · 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.
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