Skip to main content
What you’ll be able to do
  • Read current oracle values.
  • Use validated oracle data in your smart contracts.
  • Retrieve an earlier observation retained by the oracle.
The oracle contract is not on Metal Testnet yet. Follow this guide on a network that has code at its address.
Metal’s oracle makes data such as exchange rates and asset prices available to applications and smart contracts. Validators combine observations from the configured data sources and publish the results. A payment contract can use an exchange rate to calculate an amount, while an application can use an asset price to calculate a valuation. This guide reads values stored in the oracle contract at 0x00000000000000000000000000000000000000fd and checks them before use. For signed observations supplied with a transaction, see the formats and verification interface in Oracle reports.

Confirm the data source

Check that client.getCode({ address: oracle }) returns nonempty runtime bytecode. Get the item name, units, quote direction, and acceptable bounds from the feed provider, then match them to the catalog’s scale and aggregation settings. Define the catalog and observation reads with viem’s ABI parser:
Read the catalog and observation at the same finalized block, using itemName from the feed configuration. Save the block hash, item ID, decimals, and unit definition with the result.
mode is 0 median with confidence, 1 quorum-identical, 2 bit vote, 3 minimum, or 4 maximum. This valuation procedure expects mode 0. Choose checks suited to the data when using another mode. heartbeatMs controls periodic writes in block time, so updates can stop during a chain halt.

Validate a value

The confidence half-width (conf) describes the uncertainty on either side of the reported value. Set the maximum age (maxAgeMs), maximum confidence half-width in basis points (maxConfBps), and rejected flags (stopFlags) before reading. acceptPrice accepts a positive price within those bounds, including values at the limits. It checks observation and write times against the application’s current clock to detect stale data even during a chain halt.
The configured bounds allow an age of up to 30 seconds and a confidence half-width of up to 1% of the price, while rejecting all five flags. Adjust them to fit the feed and business action. value and conf share the catalog’s fixed-point scale, so validate them with integer arithmetic and convert to a decimal string for display. A control update can change flags while the stored value and height stay the same, so check the flags on every read. Stop the operation on UnknownItem, missing code, transport errors, or a rejected value.

Use a value in a contract

The BoundedPrice contract validates the observation during the transaction that uses it, so it checks the value and flags present at execution. Its item, scale, and bounds are fixed at deployment. Confirm the constructor inputs against the catalog, then follow Deploy an application contract.
Oracle timestamps use milliseconds. The contract checks them against block.timestamp * 1000 + 999, the last millisecond of the current second. This accepts observations from within that second and can reject a value up to 999 milliseconds before its age limit.
Have your application contract call read() and use the returned value in the same transaction, allowing a failed check to revert the action. The contract checks age against block.timestamp, while the application checks its current clock before submission.

Verify the integration

Save an accepted value with its decimal string, units, block hash, observation and write times, and configured limits. Test values at and just beyond each age and confidence limit, each rejected flag, an unknown item, and RPC failure. Each rejected case must stop the valuation or action. If you use the contract, compile it and verify a transaction that uses an accepted observation. Include timestamps within the current second and just beyond it, and age limits measured from that second’s final millisecond.

Read an earlier observation

Use an earlier observation to check a past valuation or reconcile an application record. observation.height identifies the block that wrote the observation. Request that height at the same pinned state:
History has limited retention, and newer writes can replace earlier entries. at requires the exact height of a retained write. Otherwise it returns NotInHistory. Save observations you need to retain with their block numbers and hashes, or use an archive RPC provider that supports reads at older blocks. For a historical valuation, evaluate the observation using the valuation time and policy recorded for that action. For a current payment, check its age against the current time. Test both a retained observation and NotInHistory.