For integrators¶
If you're building a frontend, an indexer, a market-data tool, or any application that reads from or writes to wenrange, this page lists the on-chain and off-chain surfaces you'll interact with and how to use them.
For the formal protocol model, see Protocol reference.
Surface overview¶
Three surfaces are exposed:
| Surface | What it's for | Where to find it |
|---|---|---|
| On-chain contracts | All custody, settlement, and registry state. The source of truth. | OptionsMarket (UUPS proxy) + PythSettlementOracle. ABIs published per release. |
| API service (REST) | Read-only views over indexed chain state — positions, settlement history, solver liquidity. | Hosted at api.wenrange.com. Documented at api.docs.wenrange.com. |
| Orchestrator (REST) | Live quoting. Request a price, get a signed commitment, submit on-chain. | Hosted at the orchestrator's public endpoint. Documented at api.docs.wenrange.com. |
If you only need to read state, use the API service. If you want to trade, you need the orchestrator (for commitments) plus the on-chain contract (to submit them).
Reading on-chain state¶
Contract addresses¶
Published in the project README per network. Both the market and the settlement oracle have stable addresses; the market is upgradeable behind an ERC-1967 proxy, so the proxy address is what you target.
ABI¶
The canonical ABI is checked in to the contracts repo at contracts/abis/ and re-published with every release. Both the proxy's surface and the settlement oracle's surface are exported.
Events you'll want to follow¶
Position lifecycle is best reconstructed from standard ERC-1155 events plus one protocol-specific event for the premium:
TransferSingle/TransferBatch— every mint, burn, and holder-to-holder transfer of a position.PositionBought(buyer, solverId, tokenId, quantity, premium, nonce)— emitted onbuy. Thepremiumfield is the only place to recover what the buyer paid, which is needed for cost-basis reporting.PositionBoughtBack(seller, solverId, tokenId, quantity, amountPaid, isIssuer, nonce)— emitted onbuyback.PositionSettled(tokenId, holder, quantity, userWon, amountPaid)— emitted onsettle.PositionEmergencyCanceled(tokenId, holder, quantity, refund)— emitted onemergencyCancel.
For solver-side state:
SolverRegistered,SolverPaused,SolverUnpaused,SolverRemoved.CollateralDeposited,CollateralWithdrawn.- Frozen-collateral state is not directly emitted — derive it from position lifecycle events (a buy freezes
quantity * 1 USDC; an issuer buyback, settlement, or emergency-cancel releases it).
For governance and parameters:
ParameterUpdated(key, value),AdminTransferred,OracleProposed,OracleUpdated.
For the bounty pool:
BountyPoolFunded,BountyPoolWithdrawn,SettleRewardPaid.
Position token IDs¶
Position NFTs are ERC-1155 with a packed token ID:
| Byte offset | Field | Notes |
|---|---|---|
[0..4) |
lowerBound |
In ticks. 0 means open-below (no lower bound). |
[4..8) |
upperBound |
In ticks. 0xFFFFFFFF means open-above (no upper bound). |
[8..12) |
maturityHour |
Unix timestamp / 3600. |
[12..16) |
solverId |
Index into the solver registry. |
Two buyers of the same range, maturity, and solver get the same token ID — positions are semi-fungible per (range, maturity, solver).
Tick size¶
Per-asset, configured at deployment. For BTC the tick is $100. Multiply lowerBound/upperBound (as integers in ticks) by the tick size to get the price in quote-token units.
Reading via the API service¶
Three read-only endpoints, all served from indexed chain state:
| Endpoint | What it returns |
|---|---|
GET /positions?owner=<address>&limit=&offset= |
Current ERC-1155 holdings: token ID, balance, cost basis, range bounds, maturity, solver ID. |
GET /settlement-prices?limit=&offset= |
Recorded oracle settlement prices, most recent first. |
GET /solver-liquidity |
Pool-wide solver collateral aggregates (total_liquidity, frozen_liquidity). |
Full schemas — request parameters, response shapes, error codes — are on the API docs site.
These endpoints are convenient but not authoritative. The on-chain contract is the source of truth; the indexer can lag by a few seconds, and a reorg could in principle move state out from under you. For anything safety-critical (showing a user their position before they sign a transaction), prefer reading the chain directly.
Submitting transactions¶
Two entry points the user calls:
buy(bytes packed, bytes signature)— opens a position. Requiresmsg.value == openFee(a small ETH amount, see Protocol reference).buyback(bytes packed, bytes signature)— closes a position early (or assigns it to a new solver).
The packed argument is the solver's commitment in a compact 140-byte (buy) or 160-byte (buyback) wire format. The signature is the solver's EIP-712 signature over the canonical struct. The wire format is documented on the API docs site and a reference codec lives in contracts/src/Commitments.sol with round-trip tests.
You don't construct these yourself — you request a quote from the orchestrator, which returns both packed and signature ready to submit. The flow is:
- POST to the orchestrator's
/position/open(or/position/close) with the request parameters and the user's wallet address. - Orchestrator returns
{price, commitment_packed, commitment_signature, solver_id}. - Pass
commitment_packedandcommitment_signaturestraight intobuy/buybackalong with the rightmsg.value.
The smart contract verifies that the transaction sender matches the buyer in the commitment, so the commitment is single-use and not stealable.
Triggering settlement¶
You don't have to wait for the team to settle positions; anyone can.
recordPrice(uint32 maturityHour, bytes[] updateData)on the settlement oracle — submits a Pyth price update VAA for the hour. Requires forwarding Pyth's update fee in ETH. Permissionless; first valid recording is final.settle(uint256 tokenId, address holder)on the market — settles a position whose maturity hour has been recorded. Pays the caller a small ETH bounty from the shared pool.emergencyCancel(uint256 tokenId, address holder)— only callable after the grace period (currently 7 days from maturity) if no price was ever recorded. Refunds the holder's premium and releases the solver's collateral.
A reference relayer (backend/pyth-relayer/) runs recordPrice on the team's behalf, but it's not trusted — anyone can run an equivalent.
EIP-712 domain¶
If you're building anything that verifies commitments off-chain (e.g. a competing orchestrator, a portfolio tracker that wants to display pending commitments), the EIP-712 domain is:
name : "OptionsMarket"
version : "1"
chainId : <pinned to the deployment's chain>
verifyingContract : <market proxy address>
The BuyCommitment and BuybackCommitment type strings are the canonical EIP-712 types and live in contracts/src/Commitments.sol. There is no asset field — single-asset deployments rely on the domain separator's verifyingContract for cross-deployment replay protection.
Next steps
- API endpoint schemas: api.docs.wenrange.com.
- Full protocol model and trust assumptions: Protocol reference.
- If you're writing a solver: For solvers.