Architecture¶
Source-of-truth design document for the intent-based binary options prediction platform. Project name: wenrange (stylized wen[range]). This document supersedes earlier design discussions and is the canonical reference for implementation work.
Overview¶
The platform lets users buy binary options on the future price of crypto assets (BTC at launch; ETH and SOL planned). Each contract is a prediction that the asset's price at a future maturity time will fall within a specified range. A contract costs between $0 and $1 (in a quote token such as USDC) and pays out exactly $1 at maturity if the prediction is correct, $0 otherwise.
Ranges may be:
- Closed:
[a, b](e.g. $50,000–$80,000) - Open below:
[0, b](e.g. ≤ $40,000) - Open above:
[a, +∞)(e.g. ≥ $80,000)
Range boundaries are inclusive. Range bounds are quantized to a per-asset tick (BTC: $100). Maturities are quantized to whole hours (UTC).
Prices are quoted by independent solvers, who compete on price for each user request. Solvers post collateral on-chain; user payouts are guaranteed by that collateral, not by ongoing solver liveness. The orchestrator coordinates quoting but never custodies funds.
Each asset is served by its own smart contract. A solver who supports multiple assets posts collateral separately into each per-asset contract and is registered independently in each. The orchestrator handles quote requests across all supported assets and broadcasts them to the relevant solvers; user transactions are then submitted directly from the UI to the appropriate per-asset contract — the orchestrator itself does not interact with on-chain contracts. The asset is included in user quote requests and in solver commitments, both for solver-side dispatching and as a cross-contract replay-safety check on-chain.
Actors¶
- User: buys and optionally early-sells prediction contracts via the web UI.
- Solver: an off-chain agent that quotes prices and signs commitments to sell/buy contracts at those prices. Solvers post on-chain collateral in the quote token. Anyone vetted by the admin can become a solver. The platform launches with a single reference solver operated by the team.
- Orchestrator: a centralized backend that exposes REST endpoints to the UI, maintains a WebSocket connection to each solver, broadcasts quote requests, and returns the best quote to the user. Holds no funds and cannot sign commitments on behalf of solvers.
- Admin (multisig): registers, pauses, and removes solvers; withdraws accumulated protocol fees. Cannot move user or solver funds beyond accumulated fees.
- Trustless callers: any blockchain actor who can call permissionless functions on the smart contract (record settlement price, settle a matured position, emergency-cancel).
settleandemergencyCancelcallers receive a fixed ETH reward from a shared on-chain bounty pool funded by per-buy()open fees (see Trustless Caller Compensation).
High-Level Flows¶
Purchase¶
- User specifies asset, range, maturity hour, and quantity in the UI.
- UI sends a REST request to the orchestrator, including the user's wallet address so that solvers can bind the commitment to that buyer.
- Orchestrator broadcasts the quote request to all connected solvers over WebSocket with a short timeout (~1s).
- Each willing solver responds with a signed commitment that encodes all trade parameters: asset, buyer address, range, maturity, quantity, price, expiry, and a nonce. The price is part of the commitment, not a separate field; the buyer address binds the commitment to one specific user so that no other actor can submit it on-chain.
- Orchestrator selects the best (lowest) quote and returns it to the UI.
- User submits a transaction to the smart contract including the commitment.
- Smart contract verifies that
msg.senderequals the commitment'sbuyer, verifies the signature against the registered solver's public key, verifies the commitment has not expired, transfers the user's premium into escrow, freezes the matching solver collateral, mints the position NFT, and records the position.
Buyback (Early Close)¶
- User specifies which position they hold and how many units they wish to sell back (partial closes are allowed).
- Orchestrator broadcasts a buyback quote request to all solvers, including the issuer solver. Solvers may quote differently depending on whether they issued the position; issuers typically have an economic incentive to quote tighter because closing releases their frozen collateral.
- Best quote is returned to the user.
- User submits a transaction with the commitment. Behavior depends on the buying solver:
- Original issuer: the units are burned from the user's balance, the user is paid the buyback price, and the corresponding frozen collateral is released back to the issuer.
- Different solver: the units transfer from the user to the new solver. The new solver pays the buyback price out of their own balance directly to the user. The original issuer's collateral remains frozen and unchanged — the new solver is taking a speculative long position backed by that existing collateral, and at settlement (if the position wins) they receive $1 per unit from the issuer's frozen funds.
Only the original issuer has a collateral-release incentive on buyback, which is what lets them quote tighter than a non-issuer solver who is simply taking on directional exposure.
If no solver quotes, the user simply holds the position to maturity.
Settlement¶
- After the maturity hour passes, any trustless caller can invoke
recordSettlementPrice(hour)on the contract. This pulls the 5-minute TWAP ending at the hour boundary from the settlement oracle (see Settlement Oracle) and stores it on-chain. The first valid recording is final. - Once the settlement price is recorded, any trustless caller can invoke
settle(positionId)for any matured position. The position NFT is burned and the escrowed funds plus frozen collateral are routed: $1 per unit to the position holder if the price is within the range, otherwise to the issuing solver. - Settlement callers receive a fixed
settleReward(ETH) from the contract's shared bounty pool (see Trustless Caller Compensation).
Emergency Cancel¶
If a position passes its maturity without a settlement price being recorded for more than 7 days (configurable), any caller can invoke emergencyCancel for that position on behalf of a holder. The holder receives a refund of the premium tracked against their units (see Position Premium Accounting) and the corresponding portion of the issuing solver's collateral is released back to the issuer. This guarantees the graceful-shutdown property: even if the oracle, orchestrator, and admin all fail, funds eventually return to their rightful owners.
On-Chain Components¶
Position NFT (ERC-1155)¶
Positions are represented as ERC-1155 tokens. Two users buying the same range, maturity, and solver get the same token id and their balances aggregate (semi-fungibility). The asset is not part of the token id because each contract serves a single asset.
Token ID encoding (uint256)¶
Packed fields (16 bytes total, room to spare in the uint256):
| Field | Size | Notes |
|---|---|---|
lowerBound |
4 bytes | In ticks. A value of 0 represents the natural floor (open-below range) — asset prices can't go negative, so this is both the literal zero and the open-below sentinel. |
upperBound |
4 bytes | In ticks. 0xFFFFFFFF is a reserved sentinel meaning no upper bound (open-above range). |
maturityHour |
4 bytes | Unix timestamp divided by 3600. Good for ~490,000 years. |
solverId |
4 bytes | Index into the solver registry. Up to ~4B distinct solvers. |
Including the solver in the id keeps collateral accounting simple: every token id corresponds to exactly one backing solver.
Transfers and premium propagation¶
Position tokens implement the full ERC-1155 transfer surface (safeTransferFrom, safeBatchTransferFrom, operator approvals). On every non-mint, non-burn transfer the contract's _update override automatically moves the proportional slice of holderPremium from sender to recipient, so the emergency-cancel refund total is conserved no matter how positions change hands off-protocol.
Concretely, for each (id, amount) in a transfer where amount > 0 and from != to:
delta = floor(holderPremium[from][id] * amount / balanceOf(from, id)) // exact when amount == balanceOf
holderPremium[from][id] -= delta
holderPremium[to][id] += delta
Mint paths (buy) and burn paths (_issuerBuyback, settle, emergencyCancel) keep writing holderPremium directly and the _update override skips premium routing on those legs, so the bookkeeping is never double-counted. Non-issuer buyback (where the protocol pushes units from user to solver without the user having granted operator approval) goes through an internal _protocolTransfer helper that flows through the same _update override — so it benefits from the same premium routing path and never needs separate accounting code.
Position Premium Accounting¶
To support graceful shutdown via emergency cancel, the contract tracks the premium attached to each holder's units of each token id. This lets the contract refund the appropriate amount to whoever currently holds the position at cancel time, even when units have changed hands since the original mint.
State:
holderPremium[holder][tokenId]: total premium currently attached to the units this holder owns of this token id, denominated in the quote token.
Transitions:
- Mint (purchase):
holderPremium[buyer][tokenId] += pricePerUnit × units. - Transfer (non-issuer buyback): premium follows the units proportionally. If a holder owns
Uunits with attached premiumPand transfersNunits, sender's premium decreases byP × N / Uand the recipient's increases by the same amount. - Burn (issuer buyback or settlement): sender's premium decreases proportionally to units burned. No destination — the value is realized by the trade outcome.
- Emergency cancel: holder receives their
holderPremium[holder][tokenId]value in the quote token, and the entry is cleared.
By construction, the sum of holderPremium across all holders for a given token id equals the premium still escrowed for that id, so emergency-cancel refunds total exactly to the funds available.
Worked example. User A buys 5 units at $0.30 and User B buys 3 units at $0.40 of the same token id. holderPremium[A] = $1.50, holderPremium[B] = $1.20, escrowed premium for the id = $2.70. Then User A sells all 5 units to Solver C at $0.40 each via buyback; Solver C pays User A $2.00 from their balance, and the $1.50 of premium follows the units: holderPremium[A] = 0, holderPremium[C] = $1.50. If emergency cancel then occurs, A receives nothing, B receives $1.20, Solver C receives $1.50; the issuer's collateral is released back to them. Outcomes: A profits $0.50 (sold high), B breaks even, Solver C loses $0.50 (the position they bought didn't settle). All flows are conservative and the math closes.
Solver Registry¶
The registry lives in each per-asset contract independently: a solver who operates across multiple assets is registered separately in each contract, with potentially different keys and capital.
Layout: mapping(uint32 solverId => SolverInfo), keyed by solverId (the same id encoded in position NFT token ids).
SolverInfo:
publicKey: used to verify commitment signatures.enabled: boolean flag. When false, the solver cannot sign new positions but can still service buybacks of its own existing positions (which only releases its collateral).removed: boolean flag. When true, the solver is fully retired but can still withdraw any unfrozen balance. Existing positions are held to maturity.- Collateral state (see Collateral and Accounting).
A separate counter nextSolverId assigns the next available id at registration.
Only the admin multisig can call registerSolver, pauseSolver, unpauseSolver, and removeSolver.
Collateral and Accounting¶
Each per-asset contract holds its own collateral and profit accounts; a solver active in multiple assets has separate balances and separate profit accounting in each contract. The structure below applies within a single contract.
Per-solver state in this contract:
balance: total quote tokens currently deposited.frozen: sum of collateral currently frozen against open positions issued by this solver.costBasis: cumulative deposits minus cumulative principal withdrawals. The amount the solver is entitled to withdraw without paying any profit fee.
Profit at any moment is balance - costBasis. Frozen funds are part of balance — they are unrealized P&L until positions settle.
Withdrawal rules¶
Let free = balance - frozen. The solver can withdraw up to free tokens. The split into principal and profit, applied in order:
- Fee-free portion:
min(free, costBasis - cumulativePrincipalWithdrawn). ReducescostBasis1:1. - Profit portion: anything above that. Subject to a 20% protocol fee, with 80% paid to the solver and 20% accumulated in the treasury.
Solvers may withdraw profit even when some funds are frozen — the frozen amount already covers the maximum possible loss to open positions.
Position lifecycle effects on accounting¶
- Issue position: increase
frozenby collateral required, increasebalanceby user's premium. - Buyback (issuer): decrease
frozenby the released collateral, decreasebalanceby the price paid to user. - Buyback (other solver): issuer's
balanceandfrozenare unchanged — the issuer is not a party to this transaction. The new solver'sbalancedecreases by the buyback price paid to the user; theirfrozendoes not change (the position is still backed by the original issuer's frozen collateral). - Settle, user wins: decrease the issuer's
frozenby the payout, decrease the issuer'sbalanceby the same. The payout flows to the current NFT holder, who may be a non-issuer solver if a buyback happened. - Settle, user loses: decrease the issuer's
frozenby the released amount (no balance change — the premium remains as realized P&L for the issuer).
Position premium accounting on the NFT-holder side is tracked separately; see Position Premium Accounting.
Settlement Oracle¶
Settlement uses a 5-minute TWAP ending exactly at the maturity hour boundary. Oracle choice is open (see Open Questions). Two viable candidates:
- Chainlink Functions: off-chain JS computes the TWAP from a CEX (or aggregated) feed and submits on-chain. Highest data quality, off-chain code surface.
- Uniswap V3 TWAP: on-chain
observe()over the 5-minute window on a WBTC/USDC pool (and equivalents per asset). No off-chain dependency, but tracks the wrapped representation rather than native asset price and is subject to DEX depegs and pool depth.
Whichever is chosen, the on-chain interface is the same: recordSettlementPrice(hour) is permissionless on each per-asset contract, validates the source, and stores the first valid value as final.
Trustless Caller Compensation¶
Settlement callers are compensated from a shared on-chain bounty pool, not from per-position escrow. Two governance parameters drive it:
openFee(ETH): the buyer must send this exact amount with everybuy()call. It accumulates into the contract's pool.settleReward(ETH): paid (best-effort) to the caller ofsettleoremergencyCancel. If the pool balance is belowsettleRewardat call time, the caller receivesmin(settleReward, pool)— possibly zero — and the call still succeeds. Settlement is therefore never bricked by an underfunded pool; the worst case is "permissionless but uncompensated".
Setting settleReward ≤ openFee keeps the pool non-decreasing under honest flow: every position that goes buy → settle or buy → emergencyCancel adds at least openFee − settleReward to the pool, and positions that go buy → full issuer buyback → never settled retain the entire openFee. Drain attacks are therefore structurally impossible: any sequence of user-initiated flows leaves the pool ≥ its prior balance.
The admin can withdrawBountyPool(to, amount) to sweep excess ETH (over-sweeping only reduces the next caller's reward, never bricks settlement). Anyone may top the pool up by sending ETH directly to the contract (receive).
recordSettlementPrice is currently unbountied; paying its caller from the same pool is a planned v1.x enhancement. The legacy "Option B" treasury-subsidy fallback is therefore retired — the pool itself plays that role.
Buy Endpoint and Smart Contract Validation¶
Commitments travel on the wire in a tightly-packed form (see "Commitment wire format" below); the contract decodes them on entry and then performs the following checks:
1. msg.sender equals the commitment's buyer field. This binds the commitment to one specific user and eliminates a front-running window where any bot watching the mempool could submit a leaked or broadcast commitment in place of the intended buyer.
2. Signature is valid against the registered public key for the named solverId. Cross-contract / cross-chain replay protection is provided by the EIP-712 domain separator, which pins chainId and verifyingContract = address(market) — no separate asset field in the commitment is needed.
3. Solver is enabled.
4. Commitment has not expired (block.timestamp ≤ commitmentExpiry).
5. Commitment parameters match the transaction (range, maturity, quantity, price).
6. Solver has sufficient balance - frozen to cover the required new collateral.
7. The commitment's nonce has not been used: the contract maintains usedNonces[solverId][nonce] and atomically reads-then-marks it within validation. Reuse reverts.
The same logic applies to buyback commitments, with the additional check that the user holds enough units of the referenced token id. Buyback commitments already bind to a user via their existing user field.
Commitment wire format¶
Solidity's default ABI encoding pads every value-type struct field to 32 bytes regardless of declared width, so a 10-field commitment costs 320 calldata bytes per buy / buyback even when most fields are small. To keep gas low (especially on L2s where L1 data costs dominate), the on-chain entry points take bytes calldata packed plus a signature; the contract decodes the packed bytes into the canonical BuyCommitment / BuybackCommitment struct on entry and proceeds with the standard EIP-712 digest computation. Off-chain signers continue to sign the typed-data digest in the usual way — only the transport representation is compressed. The canonical encoding is therefore:
BuyCommitment (140 bytes total):
[ 0.. 32) quantity (uint256, big-endian)
[ 32.. 64) pricePerUnit (uint256)
[ 64.. 96) nonce (bytes32)
[ 96..100) solverId (uint32)
[100..120) buyer (address)
[120..124) lowerBound (uint32)
[124..128) upperBound (uint32)
[128..132) maturityHour (uint32)
[132..140) commitmentExpiry (uint64)
BuybackCommitment (160 bytes total):
[ 0.. 32) tokenId (uint256)
[ 32.. 64) quantity (uint256)
[ 64.. 96) pricePerUnit (uint256)
[ 96..128) nonce (bytes32)
[128..132) solverId (uint32)
[132..152) user (address)
[152..160) commitmentExpiry (uint64)
Both layouts place 32-byte fields at 32-byte aligned offsets so the decoder can read each with one calldataload, and pack all sub-word fields into the trailing word(s) so they're extracted with shift+mask. The decoder rejects any length mismatch with MalformedPackedCommitment before reading further.
Off-chain reference implementations of encodeBuy / encodeBuyback live in the Commitments library; the round-trip decode(encode(x)) == x and structHash(c) == structHash(decode(encode(c))) invariants are exercised in test/CommitmentsCodec.t.sol. Solver authors who want to confirm their wire encoder is byte-for-byte compatible can drop their candidate bytes into that test's fuzz path.
Off-Chain Components¶
Orchestrator¶
Responsibilities:
- REST API for the UI: quote request (buy), quote request (sell).
- WebSocket server for solvers: maintains persistent connections, broadcasts quote requests, collects responses with a short timeout.
- Quote selection: returns the lowest-priced buy quote or highest-priced sell quote to the user.
- Solver health monitoring.
- Optionally in a later iteration: tracking solver capacity and skipping over-committed solvers when broadcasting.
The orchestrator is intentionally stateless beyond live solver connections. It does not index the chain, store user positions, or track order history — submitted transactions may or may not include a commitment the orchestrator brokered (a user can also let a commitment expire). Position state lives on-chain; user-facing history is maintained client-side in the web UI (locally cached submitted transactions plus on-demand reads of chain logs to reconcile current holdings).
The orchestrator can favor or censor solvers but cannot:
- Forge or modify commitments (signed by solver keys).
- Move user or solver funds (all custody is on-chain).
- Prevent users from interacting with the smart contract directly.
Web UI¶
The web UI is the user-facing surface. Beyond rendering and submitting quote requests, it owns the user's order-history responsibility: locally caching submitted transactions (typically in browser storage) and providing a refresh action that reads on-chain logs to reconcile current positions, settlements, and balances. The orchestrator deliberately does not participate in this flow.
Solver (general)¶
A solver:
- Maintains a WebSocket connection to the orchestrator.
- Responds to quote requests with a signed commitment encoding the trade parameters and price.
- Signs commitments using a private key whose public counterpart is registered on the relevant per-asset contract. A solver active in multiple assets is registered separately in each contract.
- Self-tracks its available (non-frozen, non-pending-commitment) collateral, per asset. The smart contract enforces the hard limit, but a well-behaved solver should never issue commitments it cannot cover. Over-committing only results in users' transactions reverting.
- Decides its own risk parameters: which assets it serves, which ranges and maturities it will quote, spot-distance limits, etc.
Commitment structure¶
Signed message contents (EIP-712 typed-data, see Commitments.sol for exact type strings and Buy Endpoint and Smart Contract Validation above for the on-wire packed layout):
solverIdbuyer(purchase only): the user the commitment is issued to. The smart contract requiresmsg.sender == buyeronbuy, preventing anyone other than the intended user from front-running the transaction and capturing the quoted position.lowerBound,upperBoundmaturityHourquantitypricePerUnit(USDC, 2 decimals)commitmentExpiry(Unix timestamp, ~1 minute from issue)- For buybacks: the position
tokenIdand the user's address (to prevent reuse). - A nonce to prevent replay across multiple matching transactions.
The commitment does not carry an explicit asset field — every OptionsMarket deployment is single-asset and the EIP-712 domain separator (which pins chainId and verifyingContract = address(market)) already prevents replay across deployments.
Reference Solver¶
The team's reference solver is the first solver registered and is intended to provide liquidity while the platform gathers momentum. It uses a pre-generated probability surface, refreshed periodically.
Probability surface¶
Axes:
- Log moneyness:
ln(strike / spot). Covers a configured range of relative price levels. - Maturity time: time from now to maturity.
Construction:
- Source data: ~2 years of historical BTC returns.
- Weighting: exponential decay with 6-month half-life (more recent data more influential).
- Output: probability that the asset's log-return at horizon falls in each surface cell.
Hourly volatility adjustment¶
A separate per-hour-of-week variance series is maintained:
- Source data: same ~2 years of BTC returns, bucketed by hour-of-week.
- Weighting: exponential decay with 1-year half-life.
- Purpose: adjust effective volatility for the maturity window. Sum-of-squared hourly volatilities from now to maturity is used to scale the log-moneyness coordinate before interpolation, so the surface naturally accounts for peak-hour vs. weekend volatility differences.
Pricing a request¶
- Compute log moneyness for each range bound, adjusted by the hourly volatility scaling.
- Compute maturity time.
- Bilinearly interpolate the surface at the adjusted coordinates to get the probability that the price lands in the range.
- Apply a maturity-time adjustment to the probability (longer maturities priced with an additional adjustment).
- Round up to two decimal places.
Self-imposed bounds¶
The reference solver quotes only on:
- Strike bounds within ±15% of spot.
- Maturities between 1 hour and 1 month from now.
These limits are enforced by the solver itself, not the protocol. Other solvers (now or in the future) may quote outside this envelope.
Range Specification¶
- Tick size is per-asset and configured at registration. BTC: $100.
- All bounds (open or closed, lower or upper) are multiples of the tick.
- Closed ranges require
lowerBound < upperBound. - A minimum range width (in ticks) may be enforced to prevent dust positions. TBD.
Fees¶
- No fees on the premium itself. Buyers pay only the price quoted by the solver. Each
buy()does carry a fixed ETHopenFeethat funds the trustless-settlement bounty pool (see Trustless Caller Compensation) — this is settlement infrastructure rather than protocol revenue on the trade. - 20% profit fee charged to solvers on profit withdrawals (see Withdrawal Rules).
- Profit fees accumulate in a treasury controlled by the admin multisig; ETH
openFeecollections accumulate in the bounty pool, also under admin control.
Trust and Decentralization¶
What the admin/orchestrator can do:
- Register, pause, and remove solvers.
- Withdraw accumulated treasury fees.
- Withdraw ETH from the shared settlement bounty pool. Over-sweeping only reduces (or zeroes) the reward future
settle/emergencyCancelcallers receive; it never prevents settlement itself. - Favor or censor specific solvers in the orchestrator (centralization risk).
- Bring the orchestrator offline.
What the admin/orchestrator cannot do:
- Move user funds.
- Move solver collateral beyond fees that have already accrued.
- Forge solver commitments.
- Prevent users from interacting with the smart contract directly.
Graceful shutdown: even if the orchestrator goes permanently offline and the admin goes rogue or disappears, every user holding an unmatured position can: 1. Wait for maturity. 2. Either call settlement themselves (if the oracle still works) or wait for the emergency-cancel grace period and reclaim their premium.
Every solver can withdraw their unfrozen balance at any time, and frozen balances unlock as positions resolve or as emergency-cancel runs.
v1 Scope¶
- BTC contract launches first; ETH and SOL contracts deployed separately when added (each a fresh deployment of the same contract code with asset-specific config).
- Reference solver only at launch; additional solvers onboarded over time via admin multisig.
- One solver per purchase transaction (no split fills).
- No partial fills against a single solver's capacity (a quote is take-it-or-leave-it).
- Full ERC-1155 transfers enabled with automatic proportional premium propagation in
_update(operator approvals included). Off-chain indexers must trackTransferSingle/TransferBatchin addition to the protocol-levelPositionBought*events to reconcile holdings. - Multisig admin (signers TBD).
- Orchestrator centralized.
Open Questions¶
- Settlement oracle: Chainlink Functions vs. Uniswap V3 TWAP vs. Pyth. Pick before mainnet deployment.
- Minimum range width (dust prevention): TBD.
- Bounty pool parameters (
openFee,settleReward): tune per-chain so settlement gas is comfortably covered while keepingopenFeesmall enough not to deter buyers. Adding a record-price reward (paid from the same pool) is the natural next step. - Emergency-cancel grace period: tentatively 7 days from maturity; finalize.
- Tick sizes for ETH and SOL when added.
- Orchestrator quote-request timeout and per-solver response timeout: tentatively ~1 second; tune in testing.
Future Considerations¶
- Additional asset contracts (ETH, SOL). Deploy a new per-asset contract per asset, each with its own tick size, settlement oracle wiring, and solver registry. Solvers operating in multiple assets manage capital and risk independently per contract.
- Split fills across multiple solvers in a single purchase transaction. Improves price for large orders, complicates commitment handling.
- Cross-solver fungibility: dropping
solverIdfrom the token id for maximum ERC-1155 fungibility, at the cost of more complex collateral-backing accounting. - Closed-range to two open-range decomposition: was considered as a way to make positions easier to sell back. Dropped because the mathematically correct decomposition requires the holder to take on a short obligation, which makes the user a mini-solver and significantly complicates the user-side state model.
- LP-token-based profit accounting: an alternative to the high-water-mark cost-basis approach. Considered and deferred; the cost-basis model is cleaner if it stays cheap enough on-chain.
- Orchestrator decentralization: today the orchestrator is a single centralized service. Long-term, multiple competing orchestrators (or a P2P discovery layer between users and solvers) could remove the censorship vector.
Glossary¶
- Binary option: a contract that pays a fixed amount (here, $1) if a condition is true at maturity, $0 otherwise.
- Commitment: a solver's time-limited, signed agreement to sell or buy contracts at a stated price.
- Closed range: a price range with both a lower and upper bound.
- Open range: a price range with one bound only (either lower or upper).
- Cost basis: the sum of a solver's deposits minus principal withdrawals; the amount they can withdraw fee-free.
- Frozen: solver collateral committed to cover possible payouts on open positions, not withdrawable.
- Maturity hour: the UTC hour at which a contract settles. Always whole hours.
- Quote token: the asset used to denominate prices and collateral (USDC at launch).
- Solver: an off-chain market maker that quotes prices and posts on-chain collateral.
- Tick: the smallest allowed increment for range bounds; configured per asset.
- TWAP: time-weighted average price.