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
onchain
Registry
set
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_ADDRESS0x78B36f1141Be113459a1640b4F92Fe63eEb87576yesQiroRegistry address (contracts/src/QiroRegistry.sol). Unset → labelled demo data.
NEXT_PUBLIC_QIRO_SETTLEMENT_ADDRESSunsetnoSeparate settlement contract. Unset → the registry’s own settle()/getSettlement() are used.
NEXT_PUBLIC_QIRO_DEPLOY_BLOCK48200286noRegistry deploy block — narrows provenance log scans.
NEXT_PUBLIC_REFERENCE_API_URL/apinoReference service origin. Defaults to this app’s /api (app/api/references/[id]), which resolves yahoo:<SYMBOL> locators.
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

contracts/src/QiroRegistry.sol — compiled with solc 0.8.24 (paris) by `npm run compile` in contracts/, tested with Hardhat in contracts/hh. The generated ABI is lib/contracts/abis/qiro-registry.ts; normalisers live in lib/contracts/registry.ts, writes in lib/contracts/writes.ts. Deploy + seed from your own wallet with public/deploy.html (served locally at /deploy.html).

One contract carries both surfaces: the registry (claims, references) and settlement (settle / getSettlement). Reserve references are computed live from an ERC-20 balance; external references store a locator that the interface resolves through the adapter for their source.

FunctionReturnsFields
registerClaim(ClaimInput)bytes32Permissionless. msg.sender becomes the issuer; timestamp/block are taken from the chain. registerClaims(ClaimInput[]) batches.
updateClaim(bytes32, value, quantity, state)—Issuer only. Posts a new observation of the claim.
registerReference(label, source, sourceName, asset, valueDecimals, locator)bytes32External reference (api/oracle/manual) with an off-chain locator such as yahoo:AAPL. registerReferences([...]) batches.
registerReserveReference(label, sourceName, asset, token, holder)bytes32Reserve reference: the live ERC-20 balance of holder — computed on every read, never stale.
settle(bytes32 claimId)boolPermissionless on-chain settlement for reserve-backed claims: compares claim value with the live balance within toleranceBps; moves state to settled / disputed.
claimCount() · claimIdAt(i) · referenceCount() · referenceIdAt(i)uint256 · bytes32Enumeration; 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) · referenceLocator(bytes32) · reserveOf(bytes32)Reference · string · (token, holder)id · label · source · sourceName · asset · value · valueDecimals · timestamp · blockNumber · status
getSettlement(bytes32)SettlementexpectedValue · referenceValue · valueDecimals · state · settledAt

Events (provenance timeline)

  • ClaimCreated(bytes32 claimId, address issuer, address asset, uint256 value, bytes32 referenceId)
  • ClaimUpdated(bytes32 claimId, uint256 value, uint256 quantity, uint8 state)
  • ReferenceRegistered(bytes32 referenceId, address owner, uint8 source, string locator)
  • ReferenceLinked(bytes32 claimId, bytes32 referenceId)
  • ReferenceUpdated(bytes32 referenceId, uint256 value, uint64 timestamp)
  • SettlementAligned(bytes32 claimId, bytes32 referenceId, uint256 expectedValue, uint256 referenceValue)
  • SettlementMismatch(bytes32 claimId, bytes32 referenceId, uint256 expectedValue, uint256 referenceValue)
  • 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.

Writing from the interface

/claims/new registers a claim from the connected wallet: asset metadata and quantity are read live from the ERC-20 (totalSupply), the value from the live reference at issuance. Claim pages expose settle() for reserve-backed claims and issuer-only state changes. Every write is simulated first so reverts surface before the wallet prompt.

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.

  • onchainconfigured

    Registry (on-chain)

  • apiconfigured

    Reference API (HTTPS)

  • oracleconfigured

    Oracle feed (AggregatorV3)

  • manualnot configured

    Manual attestation

With a registry configured the registry record is authoritative: reserve references come straight from the chain; external ones are fetched through the adapter named by their source using the stored locator (api → yahoo:SYMBOL via the reference route; oracle → an AggregatorV3 feed address), falling back to the last observation the reference owner posted on-chain. Without a registry the adapters are walked in order onchain → api → manual.

Reference API payload

GET {NEXT_PUBLIC_REFERENCE_API_URL}/references/{id}?locator=yahoo:AAPL
{
  "referenceId": "PX-AAPL",
  "source": "Yahoo Finance",
  "asset": "AAPL",
  "value": "314.5800",          // string | number | null
  "currency": "USD",
  "decimals": 4,
  "timestamp": 1787860801,      // the exchange's regularMarketTime (unix seconds | ISO-8601 | null)
  "blockNumber": null,
  "transactionHash": null,
  "status": "available",        // available | unavailable | unknown
  "basis": "unit",              // unit → multiplied by the claim quantity · total → compared directly
  "metadata": { "exchange": "NasdaqGS", "marketState": "CLOSED", "locator": "yahoo:AAPL" }
}

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