Integration
Integrate
Quotes are signed off-chain and posted on demand. Anyone may relay a quote; only the signature is trusted. The contract is live on Robinhood Chain mainnet, an Arbitrum Orbit L2, so the same Solidity deploys to Arbitrum unchanged.
1 · Read the consumer interface
The function a liquidation path should call is getPriceIfTraded. It refuses to return a modelled weekend price at all, rather than returning one and hoping the caller checks.
interface IHoodOracle {
struct Quote {
uint128 price; // 8 decimals
uint64 confidenceBps;
uint8 session; // 0 REG 1 PRE 2 POST 3 CLOSED 4 HOLIDAY
uint8 provenance; // 0 TRADED 1 DERIVED 2 STALE
uint8 sourceCount;
uint64 maxDeviationBps;
uint64 lastTradeTime;
uint64 publishTime;
}
function getQuote(string calldata t) external view returns (Quote memory);
function getPriceIfTraded(string calldata t, uint64 maxBps) external view returns (uint128);
function getBandedPrice(string calldata t, bool lower) external view returns (uint128);
function isLive(string calldata t, uint64 maxBps) external view returns (bool);
}2 · Write policy that was previously impossible
contract LendingMarket {
IHoodOracle public oracle;
// Liquidation demands a live print inside 50bps. A weekend
// quote reverts here rather than liquidating on a model.
function liquidate(address user, string calldata ticker) external {
uint128 px = oracle.getPriceIfTraded(ticker, 50);
_liquidate(user, px);
}
// Collateral is always valued at the pessimistic edge of the
// band, so a wide weekend band automatically reduces borrowing
// power instead of being ignored.
function collateralValue(string calldata ticker, uint256 qty)
public view returns (uint256)
{
uint128 conservative = oracle.getBandedPrice(ticker, true);
return (uint256(conservative) * qty) / 1e8;
}
// New borrows pause while the tape is shut.
function borrow(string calldata ticker, uint256 amount) external {
require(oracle.isLive(ticker, 100), "market shut");
_borrow(msg.sender, amount);
}
}3 · Relay a quote on-chain
import { createWalletClient, http } from "viem";
import { arbitrumSepolia } from "viem/chains";
const r = await fetch("https://your-host/api/quote/HOOD").then((x) => x.json());
await wallet.writeContract({
address: HOOD_ORACLE,
abi: hoodOracleAbi,
functionName: "postQuote",
args: [
r.quote.ticker,
{
price: BigInt(Math.round(r.quote.price * 1e8)),
confidenceBps: BigInt(r.quote.confidenceBps),
session: r.quote.session,
provenance: r.quote.provenance,
sourceCount: r.quote.sourceCount,
maxDeviationBps: BigInt(Math.round(r.quote.maxDeviationBps)),
lastTradeTime: BigInt(r.quote.lastTradeTime),
publishTime: BigInt(r.quote.publishTime),
},
r.signature,
],
});Guards the contract enforces
| Guard | Why |
|---|---|
UnknownSigner | Only allow-listed signers are accepted. |
NotNewer | Blocks replay of an older quote, including re-posting a stale favourable price. |
QuoteTooOld / QuoteFromFuture | Bounds clock skew in both directions. 60s of forward tolerance, configurable age limit backwards. |
BandTooWide | A quote past the publish ceiling is rejected rather than stored. |
ZeroPrice | Upstream returns Price: 0 for unsupported tickers. That must never reach storage. |
InvalidEnum | Out-of-range session or provenance bytes are refused, so a consumer's switch cannot fall through. |
Not audited. This is an evaluation build. The contract has not been audited. The confidence model is calibrated, on two years of realised gaps with observed coverage between 93.4% and 96.4%, but a fit on ordinary days does not anticipate a structural break. Do not settle real money against it yet.
Contract source: contracts/HoodOracle.sol