RADIX WikiRADIX Wiki

Introduction

Scrypto components execute deterministically on the Radix Engine and can only access data already present on the ledger – they cannot make HTTP calls or read external APIs. When a dApp needs external data (asset prices, exchange rates, weather data, random numbers), it requires an oracle: a service that bridges off-chain information to on-ledger state.

Oracle design is one of the most challenging aspects of decentralised application development. This article covers the two main oracle patterns on Radix, their trade-offs, and how to integrate existing oracle providers.

Push Oracles

A push oracle is an off-chain service that periodically submits transactions to update on-ledger price data. A Scrypto component stores the latest values and exposes a read method that other components call.

Architecture

  1. An off-chain relayer monitors data sources (exchange APIs, aggregator feeds).
  2. The relayer signs and submits a transaction calling update_price(asset, price, timestamp) on the oracle component.
  3. The oracle component, protected by an admin badge, stores the update in an on-ledger vault or key-value store.
  4. Consumer components call get_price(asset) to read the latest value.

Trade-offs

  • Pros: Simple consumer integration, predictable data freshness, works with any data type.
  • Cons: Relayer must pay transaction fees for every update, data staleness between updates, single-point-of-failure if the relayer goes offline.

Mitigations

Include a timestamp field in each price update and check staleness in consumer logic: reject prices older than a threshold (e.g. 5 minutes). Use multiple independent relayers with a median/aggregation mechanism to reduce trust assumptions. A staleness check alone is not enough: a feed can be rewritten on schedule and still carry a value that is wrong by orders of magnitude, which is what happened to the largest money market on Radix in August 2026 (below).

Pull Oracles

A pull oracle delivers data within the consumer's transaction rather than pre-posting it on-ledger. The oracle provider signs the data off-chain, and the consumer's transaction manifest includes both the signed data payload and a verification call to the oracle contract.

Architecture

  1. The consumer's frontend fetches a signed price attestation from the oracle provider's API.
  2. The frontend constructs a transaction manifest that first calls the oracle component's verify_and_store(signed_data) method, then calls the consumer component's business logic.
  3. The oracle component verifies the provider's signature and exposes the data for the remainder of the transaction.

Trade-offs

  • Pros: Data is always fresh (fetched at transaction time), no relayer infrastructure needed, consumer pays the gas.
  • Cons: More complex frontend integration, requires the oracle provider to run a signing API, consumer must handle the multi-step manifest.

RedStone on Radix

RedStone is an example of a pull oracle that has integrated with Radix. Its price feeds are delivered as signed payloads that Scrypto components verify on-chain, treating the data as a first-class resource within the asset-oriented model.

Supra on Radix

Supra is a second oracle provider on Radix, offering both push and pull price feeds for 100+ of the most-traded crypto asset pairs, plus decentralised randomness through a verifiable random function (VRF). The VRF is useful for on-ledger gaming, lotteries, and fair NFT distribution, where a manipulable random source would be exploitable.

When a feed is fresh and wrong

Both patterns above treat the danger as data going out of date. It is worth reading one production failure closely, because the mitigation recommended above – a timestamp and a staleness threshold – would not have caught it. On 30 August 2026 the largest lending market on Radix was drained by a feed that was neither stale nor unsigned. It was being rewritten every ten minutes, exactly as designed, with a number that had been wrong by roughly seven orders of magnitude for two days.

What the ledger records

Weft Finance reads collateral values from a single push oracle it registers as "Default PriceFeed" (component). A relayer account calls update_prices on it with a map of twenty assets, on a ten-minute cadence, authorised by one non-fungible badge; three of those badges exist and the resource carries no on-ledger metadata, so nothing on the ledger says whose price authority this is.

At 12:35:17 UTC on 28 August 2026, in one of those routine calls (transaction, state version 556,254,628), the entry for HUG went from 0.000131085370299542 XRD, a figure the feed had carried unchanged for at least four weeks, to 1289.783156723014634465 – the band the same feed uses for dollar stablecoins. It stayed in that band for the next 53 hours, drifting a little on each cycle, and 324 further transactions touched the component before the borrow at 18:02:58 on 30 August drew about 71 million XRD of debt against 539,703 HUG the same transaction had bought for 70.6 XRD. The last write before that borrow put HUG at 1,330.41 XRD.

Why a staleness check does not help

Every one of those 324 writes carried a current timestamp, and most carried a value that differed from the one before it. A consumer rejecting anything older than five minutes would have accepted all of them. The price was live; what it meant was wrong. Freshness describes when a value was written and says nothing about whether it is true, so a staleness guard is necessary and never sufficient.

Checks that address the actual failure

  • Cap the move per update. HUG changed by a factor of about ten million between two consecutive writes ten minutes apart. A per-asset deviation cap turns that into a rejected update rather than a priced position.
  • Bound each asset to a plausible band and halt the market for it outside that band, rather than continuing to lend against a number no one has looked at.
  • Cross-check against a venue you can read on-ledger. HUG's real price was available inside the attacking transaction itself, on the Ociswap pool that sold it. A component that compares a feed against on-ledger pool state is comparing two independent sources rather than trusting one.
  • Price against depth, not quantity. On the cached figure the collateral scanned as roughly 718 million XRD; the entire HUG market held about a thousand dollars of pooled liquidity. A borrow larger than the market for the collateral is a liquidation that cannot clear.
  • Keep an off switch that does not need a redeploy – a per-asset disable the protocol can reach without shipping new code.

What the operator did next

The remedy was not to price the affected assets correctly. From 00:15:54 UTC on 31 August 2026 the same ten-minute call floors ten native Radix tokens at 0.0000000001 XRD apiece – WEFT itself, HUG, EARLY, OCI, ASTRL, DFP2, CAVIAR, SRG, FLOOP and MOX – while the ten wrapped and bridged assets in the same map keep real quotes. Read at 07:05:59 UTC the floor was still being rewritten on every cycle. Pricing an asset at effectively zero withdraws it from collateral service through the oracle, without touching the component; it is the off switch of the previous point, reached by the only lever the operator had left.

Next Steps

HydrateLast updated 2d agov2.3.112 revisionsVerified Aug 31, 2026