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 = 0as 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.