Skip to content

Delphi Oracle

Delphi is an on-chain price oracle on Bitcoin Cash. Prices are published as CashTokens UTXOs sitting at a covenant address; consumers read them by spending the UTXO as an input and using transaction introspection on the NFT commitment — no off-chain fetch, no signature verification in the consumer contract.

This page documents Delphi v2 (mainnet). The previous deployment (v1) has been retired — every v1 UTXO now reports price = 0 and will stay that way. Any consumer still reading v1 should migrate.

Mainnet v2 deployment

Identity

Field Value
Symbol DELPHIV2-USD
Contract token ID be0d0d8324e8cda41d34b85bd203ce2482256eb337a0ad0fea82c2ddd7306c88
Contract address bitcoincash:rwmyzj4gr3xatylp8cm0s9mddx57ke64kzqrf5qfnes6eh8ek0sjx77t5yxzt
Wrapper token ID 436a8d86876b160fca2ba7f4532e9546dc64c9ba1497a9c1e0ff6043a773d61f
Wrapper address bitcoincash:rw70zpal3n9l2q8eaehxpnqhja39lt49e9kwh0vqh5x25zx99dsc5eppfqw5a
GP oracle pubkey 02d09db08af1ff4e8453919cc866a4be427d7bfe18f2c05e5444c196fcf6fd2818
BCMR https://meta.moria.money/delphi2_usd.json

Authority NFTs

The contract is gated by three authority NFTs. Holding the corresponding NFT is the only way to perform the action.

Authority Action Token ID
Update Advance a Delphi UTXO with a fresh price. Held by the wrapper covenant — same value as the wrapper token ID above. 436a8d86876b160fca2ba7f4532e9546dc64c9ba1497a9c1e0ff6043a773d61f
Withdraw Sweep accumulated usage fees out of the contract. 458ce09d5fe235426656da45c128b252a8b2e7ab793bfd4eab123dfd9d73bbf5
Migrate (Delphi) Spend the Delphi oracle UTXOs to upgrade away from the current contract. 268a24a5ca7a7fe68cd47f05132f0f876849497470e8dc4736614cd697d8db3f
Migrate (wrapper) Spend the GP wrapper UTXOs to upgrade away from the current wrapper. 4586ff6e513b301eca6615afacd8e0671584c78602488005b7ba8686ff28ccd3

Initial state

Field Value
Initial fee 100 sats (encoded as 1 × 100-sat unit)
UTXO count 100 (1 active + 99 reserves)

What changed from v1

If you have an integration against v1, these are the differences worth auditing before pointing it at v2:

  • Fee field has 100-sat scaling. The 2-byte fee word in the NFT commitment is multiplied by 100 to get the on-chain sats value (encoded ceiling 3,276,700 sats; minimum non-zero fee 100 sats). v1 code that reads the field as raw sats will under-pay the usage fee by 100× and the spend will fail.
  • Multiple Delphi UTXOs by default. v2 deploys with several UTXOs at the contract address (this deployment has 100). At any given time only some of them carry a live price — the rest sit at price = 0 as disabled sentinels. See the warning under Reading the price below.
  • Migrate-token escape hatch. Both the Delphi oracle and the GP wrapper carry a dedicated migrate-authority NFT. Spending one against the relevant covenant lets the operator upgrade away from the current contract. This is an operator-level safety lever and is not exercised in normal operation.

Reading the price

A v2 Delphi price lives in the NFT commitment of a CashTokens UTXO held at the contract address.

!!! danger "A UTXO with price == 0 MUST NOT be used" price = 0 is not a real price — it is a sentinel meaning the UTXO is disabled (either a not-yet-activated reserve, or a UTXO that has been explicitly retired). Consumers that read a Delphi UTXO without filtering on price != 0 will silently treat "disabled" as "BCH is worth zero dollars," which in any downstream contract that uses Delphi for collateral, liquidation, or pricing is a critical failure.

**Always filter the contract's UTXO set down to entries with `price != 0`
before using one as an oracle input.** Using `seq` as the filter is also
fine — disabled UTXOs have `seq = 0` — but `price != 0` is the rule that
matters and the one to enforce.

Pick any UTXO at that address whose token category matches the contract token ID and whose decoded price is non-zero. The commitment is a fixed 16-byte little-endian layout:

Offset Size Field Encoding
0 6 timestamp unsigned little-endian, seconds since Unix epoch
6 2 fee unsigned little-endian, multiply by 100 for sats
8 4 seq unsigned little-endian, monotonically increasing
12 4 price signed little-endian, USD price in protocol units

Pseudocode:

def parse(commitment: bytes):
    assert len(commitment) == 16
    timestamp = int.from_bytes(commitment[0:6],   "little", signed=False)
    fee_sats  = int.from_bytes(commitment[6:8],   "little", signed=False) * 100
    seq       = int.from_bytes(commitment[8:12],  "little", signed=False)
    price     = int.from_bytes(commitment[12:16], "little", signed=True)
    if price == 0:
        raise ValueError("disabled Delphi UTXO; price=0 is a sentinel, not a quote")
    return timestamp, fee_sats, seq, price

Worked example

Commitment from a real mainnet update:

9c6ff869 0000  0100  00d42019  00c4ab00
Slice Hex (little-endian) Decoded
timestamp[0..6] 9c6ff8690000 1777889180 → 2026-05-04T10:06:20Z
fee[6..8] 0100 1 unit → 100 sats
seq[8..12] 00d42019 1646804
price[12..16] 00c4ab00 43972 (signed int32, positive)

The price field is a raw integer in protocol-defined units; consult the BCMR document for the scaling factor and decimals associated with DELPHIV2-USD.

BCMR

Wallets and explorers that follow the Bitcoin Cash Metadata Registry (BCMR) can resolve the contract token ID be0d0d8324e8cda41d34b85bd203ce2482256eb337a0ad0fea82c2ddd7306c88 via the authchain anchored on its deploy output; the authhead rolls forward with each metadata publish. The registry document itself is served at https://meta.moria.money/delphi2_usd.json.

Operator notes

The oracle is updated periodically with a fresh price. Updates are driven through the GP wrapper layer: a GP-signed message attesting to the latest price is submitted to the wrapper contract, which advances the active Delphi UTXO. Because the wrapper is the only thing that checks the GP signature, anyone holding the latest GP-signed message can drive an update — there is no privileged operator key gate at the wrapper.

The current GP-signed feed is an implementation detail of the present deployment; the wrapper layer is replaceable, and the underlying source of truth for prices may change without the contract token ID itself changing.