Skip to main content
Resolution is the process by which a market’s winning outcome is determined and funds are distributed to the correct recipients. counsel has two resolution paths, automatic oracle evaluation for crypto-price markets and an operator-proposed optimistic process for real-world events, but both end the same way: a committee multisig releases funds from the pool account on-chain.

Family A: Oracle resolution

Family A markets resolve automatically at resolutionTime by reading an XLS-47 price oracle entry on the XRPL. No human input is required for a clean resolution.

What happens at resolution time

1

Read oracle

The settlement engine queries the XLS-47 oracle at oracleAccount / oracleDocumentId for the baseAsset/quoteAsset pair.
2

Check freshness

The oracle value’s lastUpdateTime must satisfy:
The 120-second post-close grace period absorbs publish cadence, a value published just after resolutionTime is still accepted. Freshness is measured against resolutionTime, not the wall clock at the time the engine runs, so settling late cannot use a price that did not exist at close.
3

Evaluate condition

The engine compares the oracle’s reported price against strike using comparison:
  • >= strike, outcome 0 (Yes) wins if price >= strike
  • <= strike, outcome 0 (Yes) wins if price <= strike
If the condition is not met, outcome 1 (No) wins.
4

Publish resolution record

The operator writes a signed ResolutionRecord memo to the pool account with status: "final", the winningOutcome index, the raw oracleValue, and the oracleLastUpdateMs timestamp. This record is the authoritative on-chain proof of resolution.
5

Distribute payouts

The committee multisig sends a Payment from the pool account to each winning bettor, tagged with a payout memo. Settlement is idempotent: the engine reads already-paid accounts from the ledger before each run and skips them.

Freshness void

If the oracle value’s age relative to resolutionTime falls outside the freshness window (accounting for the 120-second grace period), the market voids immediately. All stakes are refunded. See Void policy below.

Family B: Manual (optimistic) resolution

Family B markets use an optimistic resolution model adapted from UMA’s Optimistic Oracle, rebuilt on native XRPL primitives with no smart contract and no token vote. The operator proposes an outcome and posts a bond, a dispute window opens, and the multisig committee finalizes. counsel says plainly where the trust lives: this is custodial-transparent, a disclosed council, not a trustless oracle. The full design is in optimistic-oracle.md.

What happens at resolution time

1

Operator proposes and bonds

After resolutionTime, the proposer posts a signed on-chain ResolutionRecord with status: "proposed" to the pool account, including winningOutcome, an evidence source URL, and an evidence hash. The proposer posts the symmetric bond whose size is pre-committed in the market definition (bondXrp), so the bond is fixed and non-negotiable.
2

Dispute window opens

The window lasts disputeWindowHours (default 48). Any account can open a dispute by posting a matching bond to the pool, anchoring its own evidence (a source URL and a content hash) on-chain, so the dispute references the same canonical record as the proposal. An undisputed proposal is correct by default.
3

No challenge: committee signs

If the window closes with no dispute, the multisig committee cosigns the proposed outcome. Settlement proceeds identically to Family A: a final ResolutionRecord is written on-chain, then payouts are distributed, and the proposer reclaims their bond.
4

Challenged: committee finalizes and resolves bonds

If one or more bonds are posted, the committee reviews the evidence independently and signs the final outcome, which may or may not agree with the proposal. The final status: "final" record supersedes the proposal. The committee then resolves the bonds (see below).
A proposed record is visible in the pool account’s transaction history but does not trigger payout distribution. Only a status: "final" record initiates settlement. A void (the “too early” or ambiguous outcome) is a first-class result that refunds every stake with no fee, the analogue of UMA’s 50-50 answer, so an unanswerable market never mis-resolves.

Bonds and the final fee

Bonds are symmetric and pre-committed: the proposer posts bondXrp and a disputer must match it exactly, so neither side can take a cheaper position. A wrong side forfeits its bond to the right side, which is what turns a wrong proposal into free money for the first honest disputer and is the entire economic security of the model. counsel also implements UMA’s final fee. A configurable slice of the slashed bond, finalFeeBps (basis points), is skimmed to the council treasury before the winner is paid; the winner’s own bond is always returned in full. The fee funds the arbiter and makes a frivolous bond cost real money even when you win. The bond math is integer-only and rounds down, so the fee plus the awards can never exceed the slashed bond, and the whole path is test-driven.

Void policy

The following conditions result in a full refund with no fee deducted: When any condition is met, the settlement engine distributes refunds instead of payouts. Each bettor receives their exact original stake back via a native XRP Payment. Market-maker seeds are excluded from refunds (they are house-neutral) and remain as pool residue.

What happens on void

A void is not an error state, it is a defined contract outcome. On void:
  1. The ResolutionRecord is written on-chain with void: true and winningOutcome: null.
  2. Every non-seed stake is refunded at face value (drops in = drops out).
  3. No fee is deducted from any refund.
  4. The pool account’s remaining balance (seeds + dust) stays under operator control.
Refunds are dispatched in the same idempotent per-recipient Payment loop used for payouts, so a partial failure mid-run is safe to retry.

Trust model

Pool accounts are secured so that no single party, including the operator, can unilaterally move funds:

Master key disabled

After the pool account is created, the master key is disabled on-chain. There is no signing key that can authorize a unilateral Payment.

n-of-m SignerList

A multisig SignerList is set on the pool account. A threshold of committee members must cosign any outgoing transaction before the XRPL will process it.
Every bet, proposal, dispute, and payout is a native on-chain transaction. You can verify the complete history of any pool account independently using any XRPL full history node or block explorer, no API access to counsel is required to audit a market’s lifecycle.