XChain Platform Action - PRICE
This action publishes oracle price data on-chain. Version 0 anchors PBFT-consensus COIN/FIAT price snapshots produced by validators qualifying for the price capability and broadcast on-chain by a validator qualifying for the oracle_publish capability (both capabilities are auto-qualified by aggregate stake amount per the capability model — see STAKE). Version 1 is permissionless: any address may operate a user-run TOKEN/FIAT price oracle, no stake required.
PARAMS
Version 0 — Validator COIN/FIAT Price Snapshot
| Name | Type | Description |
|---|---|---|
VERSION |
String | Format version (0) |
ROUND |
Integer | Oracle round number (= BTC block height that triggered the round) |
TIMESTAMP |
Integer | block_time of the BTC block that triggered the round (seconds) |
PAIR_COUNT |
Integer | Number of COIN/FIAT price pairs in this payload |
PAIR_ID |
String | COIN/FIAT pair identifier, e.g. BTC/USD (repeated per pair) |
PAIR_PRICE |
String | Price as decimal string, 8 decimal places (repeated per pair) |
SIG_COUNT |
Integer | Number of price-capable validator signatures |
PUBKEY |
String | 64-char hex Ed25519 signing pubkey (repeated per signature) |
SIGNATURE |
String | 128-char hex Ed25519 signature over round data (repeated per sig) |
Version 1 — User Oracle TOKEN/FIAT Price
| Name | Type | Description |
|---|---|---|
VERSION |
String | Format version (1) |
COIN |
String | Chain identifier for the token (e.g. BTC, LTC, DOGE) |
TICK |
String | Token name (e.g. PEPECASH) |
FIAT |
String | Fiat currency code (e.g. USD, JPY, EUR) |
VALUE |
String | Price as decimal string, 8 decimal places |
FEE |
String | Oracle usage fee as decimal (e.g. 0.01 = 1%) |
MEMO |
String | Optional description or timestamp |
Formats
Version 0 — Validator COIN/FIAT Price Snapshot
VERSION|ROUND|TIMESTAMP|PAIR_COUNT|PAIR_ID|PAIR_PRICE|...|SIG_COUNT|PUBKEY|SIGNATURE|...
Pair data (PAIR_ID|PAIR_PRICE) repeats PAIR_COUNT times.
Signature data (PUBKEY|SIGNATURE) repeats SIG_COUNT times.
Version 1 — User Oracle TOKEN/FIAT Price
VERSION|COIN|TICK|FIAT|VALUE|FEE|MEMO
Examples
PRICE|0|850010|1712500000|3|BTC/USD|100000.12345678|LTC/USD|85.50000000|DOGE/USD|0.15000000|3|aabb...01|ccdd...sig1|aabb...02|ccdd...sig2|aabb...03|ccdd...sig3
An `oracle_publish`-capable validator anchors PBFT-consensus price snapshot for BTC block 850010 with 3 COIN/FIAT pairs and 3 `price`-capable validator signatures
PRICE|0|850010|1712500000|6|BTC/USD|100000.12345678|BTC/EUR|92000.00000000|LTC/USD|85.50000000|LTC/EUR|78.50000000|DOGE/USD|0.15000000|DOGE/EUR|0.14000000|5|aa...01|cc...s1|aa...02|cc...s2|aa...03|cc...s3|aa...04|cc...s4|aa...05|cc...s5
Multi-FIAT snapshot: 3 coins × 2 fiat currencies = 6 pairs, signed by 5 validators
PRICE|1|BTC|PEPECASH|USD|0.05000000|0.01|hourly update
User oracle publishes PEPECASH price on BTC chain at $0.05 USD with 1% usage fee
PRICE|1|BTC|PEPECASH|JPY|7.50000000|0.02|
User oracle publishes PEPECASH price in JPY with 2% usage fee
Rules
Version 0 — Validator COIN/FIAT Price Snapshot
Chain & Publisher
- Publishable on any chain (BTC, LTC, DOGE) — DOGE is recommended for lowest tx fees but the protocol does not require it
SOURCEmust own an active stake against a pubkey that qualifies for theoracle_publishcapability at the publishing BLOCK_INDEX (i.e. the pubkey’s aggregate active stake ≥min_stake[oracle_publish], governance-configurable)
Round Identity
ROUNDcorresponds to the BTC block height that triggered the oracle round- One round per BTC block (BTC blocks average ~10 minutes but can vary from 1 to 60+ minutes)
- Each round may only be published once — duplicate
ROUNDvalues are deduplicated by the hub (first valid submission wins)
Leader Rotation & Failover
- Pubkeys qualifying for
oracle_publishat round N are sorted bysigning_pubkey(deterministic ordering — every node agrees) - Leader for round N:
N % oracle_publish_capable_count(index into sorted list) - If round N is not published by the time BTC block N+1 arrives, the next
oracle_publish-capable validator in rotation becomes eligible to publish - Failover cascades: if that validator also misses, the next one is eligible at BTC block N+2, and so on
- The first valid PRICE tx on-chain for a given round wins (and defines the round’s reward split — see Round Rewards)
Batch Publishing
- A single PRICE v0 transaction may contain multiple rounds (for failover catch-up)
- When a failover publisher takes over, they batch all missed rounds into one or more transactions
- No artificial cap on rounds per batch — bounded only by P2SH encoding limits (~65KB max)
- If the batch exceeds a single P2SH transaction, multiple PRICE transactions are sent
- Each round in the batch derives its own reward split from its own signer list (publishing itself earns no extra reward — see Round Rewards)
Signature Validation
- Each
PUBKEYmust correspond to a pubkey qualifying forpriceat the BLOCK_INDEX of the PRICE tx (SUM(amount)across active stake rows ≥min_stake[price], governance-configurable; rows are active whereactivation_block ≤ block_index < COALESCE(deactivation_block, +∞)) - Each
SIGNATUREmust be a valid Ed25519 signature over the canonical PRICE v0 payload by the correspondingPUBKEY - Canonical payload format:
JSON.stringify({round, timestamp, pairs})wherepairsis sorted ascending bypairfield SIG_COUNTmust meet PBFT quorum:>= max(2 * floor((price_capable_count - 1) / 3) + 1, ceil((price_capable_count + 1) / 2)), whereprice_capable_countis the number of pubkeys qualifying forpriceat the PRICE tx’s BLOCK_INDEX. The simple-majority floor prevents the bare2f+1form from degenerating to a quorum of 1 at N=3- Duplicate pubkeys in the signature list count only once
- Rounds that fail signature validation are marked
invalidand not pushed to the hub - A pubkey qualifies either as a stake key or as a delegated key — see the effective signer set in DELEGATE
Round Rewards (derived on-chain)
- A valid PRICE v0 is the round’s signed participation record: the indexer splits the configured per-round reward (
STAKING.ORACLE_REWARD_PER_ROUND, default 10 XCHAIN) equally across the action’s verified, capability-qualified, deduplicated signer set, floored to 8 decimals - Rewards are written to
validator_rewards(reward_type = oracle_round,round_reference = ROUND) during block processing — a deterministic function of the chain, so any reindex or full-parse recovery reproduces them exactly - A round that finalizes off-chain but never lands a valid PRICE action earns nothing; a duplicate PRICE for an already-rewarded round re-derives the same rows (idempotent)
- Signers credited are exactly the on-chain signature list that passed validation — PBFT participants whose signatures were not included in the published action are not rewarded
Skipped Rounds
- If PBFT fails to reach consensus for a BTC block, no PRICE v0 is published for that round
- The gap in round numbers is a silent skip — no explicit skip marker is published
- Indexers use the most recent valid price when no snapshot exists for a given round
Activation Delay
- A validator’s STAKE, UNSTAKE, or DELEGATE (any version, including revoke) action does not take effect until 6 BTC blocks (~1 hour) after confirmation
- Eliminates BTC reorg edge cases for reorgs of ≤5 blocks
- Applies to every capability and every validator state change (see
activation_block/deactivation_blockon thestakestable)
Supported COIN/FIAT Pairs
- Validators publish all supported COIN × FIAT combinations per round
- Initial COIN set:
BTC,LTC,DOGE(3 coins) - Initial FIAT set:
USD,CAD,AUD,MXN,GBP,JPY,CNY,CHF,BRL,INR,EUR,KRW(12 currencies) - Initial pair count: 3 coins × 12 fiats = 36 pairs per round
- Adding new coins or fiat currencies does not require a protocol change —
PAIR_COUNTis dynamic - Validators fetch all 12 fiat prices per coin in a single API call (CoinGecko
vs_currenciesparameter, CMCconvertparameter)
Publisher Persistent Queue
oracle_publish-capable validators must durably store finalized rounds to a local persistent queue (JSONL with fsync) before acknowledging receipt to the hub- On restart, the publisher replays any unconfirmed rounds from the queue
- Rounds are removed from the queue only after publishing-chain confirmation
- If the queue is unwritable, the publisher refuses new rounds (fail loud, not silent)
Publishing-Chain Balance Monitoring
- Publishers check their own wallet balance on the publishing chain (typically DOGE) before each publish attempt
- WARN logged when balance falls below configurable threshold (default: 10 native units) with estimated rounds remaining at current fee rate
- ERROR logged when a publish tx fails due to insufficient balance
- No protocol-level enforcement — if a publisher runs out of funds, failover kicks in naturally and the next
oracle_publish-capable validator in rotation takes over
Rewards
- An
oracle_publish-capable validator earns 1 XCHAIN per successful PRICE v0 publish (recorded invalidator_rewardsasreward_type='oracle_round'/oracle_publish) - When batch-publishing missed rounds on failover, the publisher earns rewards for all rounds in the batch
- Rewards are gathered via the
COLLECTaction on BTC
Version 1 — User Oracle TOKEN/FIAT Price
Chain
- Publishable on any supported chain (BTC, LTC, DOGE)
- DOGE recommended for low-cost frequent updates
Publisher
- Any address may publish PRICE v1 — no staking requirement
- The
SOURCEaddress becomes the oracle identity - Dispensers and betting systems reference the oracle by
SOURCEaddress
COIN Field
- Identifies which chain’s token the price is for
- A DOGE transaction can publish a price for a BTC token (cross-chain oracle)
- Dispensers/betting on any chain may reference any oracle regardless of publishing chain
Price Lock Window
- Every PRICE v1 broadcast for a
(SOURCE, COIN, TICK, FIAT)combination — the first one included — takes effect 86400 seconds (24 hours) afterblock_time - For updates, the delay prevents oracle front-running attacks on dispensers: without it, an oracle operator could see an incoming dispenser payment and rush a price update to manipulate the exchange rate
- For first publishes, the delay is a consensus requirement: an immediately-effective first publish would be retroactively effective — its
effective_at(the action’sblock_time) precedes the moment the price can exist in any indexer’s hub-DB mirror (source-chain indexing lag plus propagation). A FIAT dispense settled in that window would settle differently on replay, forking the ledger. The uniform delay guarantees every operator holds the row long before any block can read it - 24-hour delay matches the
FIAT_DISPENSER_PRICE_WINDOW— any payment that enters the mempool before a price update will settle at the old price before the new one activates - User TOKEN/FIAT oracles target illiquid markets where prices change infrequently, so the 24-hour delay (including the one-time onboarding delay for a new oracle) is not a practical limitation
- Enforced by the
effective_atcolumn on the hub’soracle_pricestable
FIAT Dispenser Reverse Price Matching
- When a FIAT dispenser referencing a user oracle receives a payment, the system reverse-matches the payment amount against historical oracle prices within a 24-hour window (86400 seconds) before the payment’s
block_time - Cross-conversion combines the user oracle (TOKEN/FIAT) with the validator oracle (COIN/FIAT) for the same currency:
- User oracle: 1 PEPECASH = ¥7.50 JPY
- Validator oracle: 1 BTC = ¥15,000,000 JPY
- Buyer pays 0.001 BTC → receives
floor((0.001 × 15000000) / 7.50)= 2000 PEPECASH
- See
DISPENSERdocumentation for full reverse price matching details and examples
FEE Field
- Decimal value representing the oracle usage fee percentage
0.01= 1%,0.05= 5%, etc.- Dispensers/betting systems that reference this oracle pay the fee to the oracle
SOURCEaddress
Staking gate for oracle_publish
PRICE v0 publishers are auto-qualified by the capability model — no special “Tier 3 STAKE” exists. A pubkey gets the oracle_publish capability iff its aggregate active stake ≥ min_stake[oracle_publish] (governance-configurable). Same model applies to the price capability used by signers; a single pubkey can hold both capabilities simultaneously.
| Property | Value |
|---|---|
| Capability | oracle_publish |
| Role | Broadcasts finalized PRICE v0 rounds on-chain |
| Stake gate | SUM(amount) across the pubkey’s active stake rows ≥ min_stake[oracle_publish] (governance default; see hub ProviderRegistry / capability config) |
| Chain | STAKE happens on BTC; PRICE v0 can be published on any chain (DOGE recommended for fees) |
| Overlap | Allowed — same pubkey may hold both price and oracle_publish (and earn both rewards in the same round) |
| Cooldown | Configurable, default 1000 blocks |
| Activation delay | 6 BTC blocks (~1 hour) |
To become an oracle_publish publisher, stake against a pubkey using the standard STAKE action:
STAKE|1|<AMOUNT>|<SIGNING_PUBKEY> # new stake
STAKE|2|<AMOUNT>|<SIGNING_PUBKEY> # top-up of existing pubkey
See STAKE.md for the full action spec.
Publishing-chain wallet (e.g. the DOGE wallet for broadcasting PRICE v0 to DOGE) is operator-side configuration on the hub — it is not recorded on-chain. Each oracle_publish-capable validator chooses its own publishing-chain address; the protocol simply verifies that the broadcasting SOURCE address owns a stake against a pubkey with the capability at the publishing BLOCK_INDEX.
Architecture
Data Flow — Validator Prices (v0)
`price`-capable validators fetch prices from CoinGecko/CMC
→ PBFT consensus (2/3+ agree on prices per BTC block)
→ Each validator signs the canonical PRICE v0 payload during prepare/commit
→ An `oracle_publish`-capable validator writes PRICE v0 (with collected sigs) to a chain (DOGE recommended)
→ That chain's decoder picks up the action
→ That chain's indexer validates PBFT signatures and writes to local prices table
→ Indexer pushes validated round to hub
→ Hub deduplicates by round_number, writes to unified price_snapshots table
→ Hub broadcasts new row to all connected indexers' local hub DB copies
Data Flow — User Oracle Prices (v1)
User broadcasts PRICE v1 on any chain
→ Chain's decoder extracts PRICE action
→ Chain's indexer validates fields and writes to local prices table
→ Indexer pushes to hub oracle_prices table
→ Hub applies the uniform 24-hour lock window (every publish effective at block_time + 86400)
→ Hub broadcasts new row to all connected indexers' local hub DB copies
→ All indexers query their local hub DB for oracle data — no hub round-trip during block processing
Three-Database Model
Each indexer maintains three database connections:
| Database | Connection | Owner | Contains |
|---|---|---|---|
| Decoder DB | Read | Decoder | Raw blockchain data, decoded txs |
| Indexer DB | Read/Write | Indexer | Chain-specific indexed state — actions, balances, tokens, plus the local prices action log |
| Hub DB (local) | Read | Hub (synced via WebSocket) | Cross-chain infrastructure — price_snapshots, oracle_prices, validator_rewards, etc. |
The indexer’s prices table is the raw on-chain action log (one row per PRICE tx). The hub’s price_snapshots and oracle_prices tables are the deduplicated, cross-chain aggregated views that indexers actually query for price lookups.
DOGE Chain Role
- DOGE is the recommended publishing chain for PRICE v0 due to lowest tx fees
- However the protocol allows publishing on any supported chain —
source_chainis recorded in the hub’sprice_snapshotsfor audit - Indexers do not need to run a DOGE node — they get prices from their local hub DB copy
- A new node syncing from genesis can reconstruct full oracle history from any chain that carried PRICE v0 transactions
Determinism Guarantee
- Two independent nodes reading the same blockchains and running the same validator set arrive at identical price state
- Validator prices are anchored on-chain with full PBFT cryptographic proof (publishable on any chain)
- User oracle prices are on-chain on their publishing chain
- Hub aggregates
price_snapshotsandoracle_pricesfrom all chains — single source of truth - Indexers query their local hub DB copy — no hub round-trip during block processing
- No off-chain data is required to reconstruct the complete oracle history
Notes
- This action replaces the oracle functionality previously available via
BROADCASTversion 1 - Validator price snapshots include all 12 supported FIAT currencies per coin, enabling cross-currency dispenser pricing without double-conversion
- The reverse price matching mechanism for FIAT dispensers is documented in the
DISPENSERaction specification PRICEcan coexist withBROADCAST— existing BROADCAST oracles continue to function
Copyright © 2025–2026 Dankest, LLC
Based on XChain Platform by Dankest, LLC – https://dankest.llc
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) with a commercial license available for proprietary use.
You may use, modify, and distribute this material under the terms of the License. See LICENSE and NOTICE for full terms. See the licensing overview.