diff --git a/docs/assets/js/docsSearchData.js b/docs/assets/js/docsSearchData.js index e3110f94c..ffbda2646 100644 --- a/docs/assets/js/docsSearchData.js +++ b/docs/assets/js/docsSearchData.js @@ -1,2 +1,2 @@ // Generated by tooling/docs/build-docs-index.mts. Loaded on demand; do not edit directly. -window.statoblastDocsSearch = [{"fragment":"","heading":"","keywords":["overview","lifecycle","market","components"],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Start here Zoltar and Statoblast are Ethereum protocols for prediction markets, designed to make outcome manipulation costly. This page assumes you know what Ethereum and an ERC-20 token are, and nothing else. It states the problem, defines the three words you will meet on every other page, introduces the four components, and follows one market from start to finish.","title":"System overview","topic":"Introduction","weight":1},{"fragment":"problem","heading":"The problem","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"A prediction market lets people trade on a question such as “Will the fictional Aurora spacecraft launch before 31 December 2030?” Its shares are worth something only after someone decides what actually happened. That decision is the weak point: whoever controls it controls the money. Zoltar and Statoblast make the decision expensive to corrupt in two ways. First, anyone who reports an outcome must stake REP, the protocol's reputation token, behind it, and the contracts settle in favour of the outcome with the most REP staked. Reporters whose outcome loses forfeit their stake, so backing an answer the rest of the market will not support is costly. Whether that pressure keeps reports honest depends on the participation assumptions in the security model. Second, when reporters cannot agree, the system does not pick a side. Its ledger, called a universe, splits into child universes, one per possible answer, and the market decides which child stays valuable. A dishonest majority of REP cannot stop honest participants from moving their REP into the child that records the honest answer; what that does and does not guarantee is covered with Zoltar.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"vocabulary","heading":"Three words you will see everywhere","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"REP The Reputation token . Holding REP lets you report outcomes and underwrite markets. It is also what you risk: a reporter loses REP when the outcome they supported loses. Universe A ledger that can branch . Markets and REP balances belong to a particular universe. Questions are registered globally, so the same question can have markets in multiple universes. When reporters split irreconcilably, the universe forks into children, one per possible answer, each with its own REP. SecurityPool The Statoblast contract for one question, universe, and pool configuration . It holds the ETH that backs the market's shares and keeps the books on who underwrites the market, who is disputing its outcome, and who is owed what. Vault owners lock REP in a vault , their account inside the pool, and lose REP if that vault is liquidated.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"components","heading":"Four components","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Zoltar The ledger. It records questions, universes, REP, and forks. It never judges which answer is true. Statoblast core The market. It deploys a SecurityPool for a question, universe, and pool configuration, mints and redeems shares, settles ordinary disputes locally, and moves markets into child universes after a fork. Trading An exchange for Statoblast shares. It is one of possibly many; it neither creates nor resolves markets. OpenOracle A price feed. It supplies a contestable REP/ETH exchange rate whenever the protocol must check that REP still covers ETH obligations. It has no say in market outcomes.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"lifecycle","heading":"One market, start to finish","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Alice registers the Aurora question in Zoltar and deploys its SecurityPool. Vault owners lock REP in their vaults to back the market. Traders send ETH to the pool and receive complete sets : one Yes share, one No share, and one Invalid share, the outcome used when the question cannot be validly resolved, for each unit of collateral at the pool's current rate. They trade those shares however they like. When the launch deadline passes, reporting begins. Register question Deploy SecurityPool Deposit vault REP Mint complete sets Trade shares Question ends First REP deposit starts the Escalation Game Local resolution or Zoltar fork Migrate into child pools Repair missing collateral through a Truth Auction Redeem Market lifecycle. The ordinary path resolves locally and skips the migration and repair steps. The fork path creates one child pool per answer and repairs each child's collateral separately. Reporters stake REP behind an answer in the pool's Escalation Game , a dispute round whose deadline moves later as the contested amount grows. When the deadline finally passes, the market resolves if exactly one answer holds more REP than every other, and winning shares redeem the pool's ETH. Usually that is the end of the story. If two answers each attract so much REP that neither can be called the winner, the pool forks : its universe splits into an Invalid, a Yes, and a No child. Vault owners choose a child for their vault. Shareholders can materialize their share claims in multiple children. ETH is not duplicated: each child receives only what migrates to it, and a child that comes up short holds a Truth Auction, selling its own REP for ETH to close the gap. Forks and migration follows both paths in detail, and what a fork does and does not promise is the single most important thing to understand about these protocols. Follow a market through Statoblast · Understand branching universes · Look up a term","title":"System overview","topic":"Introduction","weight":0},{"fragment":"","heading":"","keywords":["contracts","architecture","calls","assets"],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Start here Users call SecurityPools , the Statoblast contracts that hold each market's ETH. Pools rely on Zoltar for universes and REP , on a price coordinator for REP/ETH prices, and on the SecurityPoolForker after a fork. This map shows contract-to-contract calls and asset movement, not every public user entrypoint. Deployment-helper factories, delegate modules (helper contracts whose code a pool, an Escalation Game, or the SecurityPoolForker runs through delegatecall ), the coordinator's VaultOperations executor , event emitters, and external contracts such as WETH are omitted; the contract inventory lists them. Related reading: the generated transaction reference for exact caller and prerequisite rules, How Statoblast works for lifecycle context, and the invariant catalog for cross-contract safety properties.","title":"Contract architecture","topic":"Architecture","weight":1},{"fragment":"product-layers","heading":"Product layers","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Zoltar — questions, universes, REP, forks Statoblast core — pools, collateral, shares, resolution, migration Trading — one implementation of swaps and liquidity around shares OpenOracle — contestable REP/ETH prices augurScan and bots — indexing, evidence, and permissionless operations Product-layer map. These products share protocol data but retain separate responsibilities and deployment boundaries.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"conceptual-model","heading":"What each contract owns","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Statoblast separates identity, market accounting, price-sensitive execution, dispute escrow, and fork repair: ZoltarQuestionData stores question state and answer encoding; Zoltar manages universes, forks, and each universe's REP token. A SecurityPool tracks market collateral, vault accounting, open interest , and lifecycle state. The ShareToken tracks outcome-share balances for one lineage : an origin pool and every child pool forked from it. The OpenOraclePriceCoordinator queues vault operations that need a fresh REP/ETH price and runs them immediately while its cached price is valid, otherwise after OpenOracle settles a new report. An operation waiting for that report is a staged operation . The EscalationGame holds the REP that reporters stake in the pool's local dispute . The SecurityPoolForker creates child pools after a fork and repairs any ETH shortfall through a Truth Auction . Each lineage has at most one pool per universe. The table calls that registered pool the canonical pool. One complete-set path is: a trader calls SecurityPool , the pool accepts ETH collateral, and the pool calls ShareToken to mint one share for every outcome.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"overview","heading":"Primary interaction flow","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Arrows point from the contract initiating an interaction to the contract receiving it. The map has three panels: Deploy & wire , Operate & resolve , and Fork & repair . A contract that takes part in more than one panel is drawn in each. Users and keepers enter through several of these contracts, but are omitted so the plot can focus on contract-to-contract boundaries. Contract interactions are separated into three panels. During deployment, the pool factory validates question and universe data before deploying the pool, share token, and price coordinator. During runtime, the pool manages claims and escalation escrow while guarded actions travel through the price coordinator and OpenOracle, and the coordinator reserves liquidation approvals in the Liquidation Approval Registry. During a fork, the share token enters the pool forker, which snapshots escalation, migrates REP through a proxy, creates and migrates child pools, and repairs backing through the Truth Auction. Contract Interaction Map Repeating a contract in each panel keeps unrelated lifecycle edges from crossing. Blue nodes are Zoltar, REP, price, and approval infrastructure, green nodes hold market state and claims, red nodes with a dashed outline mark local resolution, gold marks deployment or fork coordination, and dashed arrows depend on a price OpenOracle has settled. Short edge labels state the action; the table below supplies its exact contract-level meaning.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"edges","heading":"What each arrow means","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"The Step column names the step within a panel. Deployment and Universe lifecycle belong to Deploy & wire; Share migration , Fork snapshot , Fork migration , and Backing repair belong to Fork & repair; every other step belongs to Operate & resolve. Initiator Receiver Step Interaction SecurityPoolFactory ZoltarQuestionData Deployment Confirms that the question exists and is the required Yes/No categorical shape before reserving the canonical pool identity. SecurityPoolFactory Zoltar Deployment Checks the universe and resolves its REP token for the new pool and price coordinator. SecurityPoolFactory SecurityPool Deployment Deploys and records the canonical origin pool. Forker-requested child deployment copies the lineage and fork state. SecurityPoolFactory ShareToken Deployment Deploys the origin lineage token and authorizes the canonical pool; child pools reuse that same token. SecurityPoolFactory OpenOraclePriceCoordinator Deployment Deploys the REP/WETH price coordinator and wires it to the newly created pool. Zoltar ReputationToken Universe lifecycle Deploys child-universe REP with its theoretical supply , mints it during migration, and burns REP during fork initiation, migration, and burnRep burns. Genesis REP cannot be burned, so Zoltar sends it to a burn address instead. SecurityPool ShareToken Market runtime Mints complete sets, burns complete sets or winning shares, and authorizes canonical child pools to continue the same lineage claims. SecurityPool EscalationGame Resolution Deploys the local game on first use and transfers vault REP into outcome-specific escrow. Settlement returns winning value or carries proofs across a fork. SecurityPool OpenOraclePriceCoordinator Risk operations Reads the coordinator's last valid REP/ETH price. Vault owners and liquidation operators queue withdrawals, underwriting-commitment changes, and liquidations on the coordinator, which executes them on the pool with a valid price. Owners may also set their underwriting commitment directly at the pool: an increase requires the coordinator's cached price to be valid, a reduction does not. REP deposits add backing without changing the commitment. OpenOraclePriceCoordinator OpenOracle Price discovery Funds a REP/WETH report and later withdraws the settled reporter balances that it validates and returns to the report sponsor. OpenOracle OpenOraclePriceCoordinator Price settlement Calls openOracleCallback after settlement so the coordinator can validate the final report, update its cached price, and attempt bounded staged-operation execution. OpenOraclePriceCoordinator SecurityPool Risk execution Once a fresh price is accepted, calls the executor-only liquidation, REP-withdrawal, or underwriting-commitment entrypoint through its VaultOperations executor , the only caller the pool accepts for them. A liquidation proceeds only if the target vault's REP backing and underwriting commitment are unchanged since it was queued, and moves part or all of that commitment with matching REP backing to the receiver vault, the vault that takes over the commitment . A withdrawal keeps the commitment and must leave it fully backed. OpenOraclePriceCoordinator LiquidationApprovalRegistry Risk operations When an operator queues a liquidation into another owner's receiver vault, reserves that owner's approval. After execution it consumes the debt actually moved; a failed, stale, or expired operation releases the reservation. ShareToken SecurityPoolForker Share migration Initiates a source-pool fork when needed and asks the forker to create a missing canonical child before migrating a holder's shares. SecurityPoolForker EscalationGame Fork snapshot Reads the game's Merkle commitments to individual deposits, its outcome balances, timing, and parameters so an unresolved dispute can continue in child pools. SecurityPoolForker SecurityPoolMigrationProxy Fork migration Deploys and controls the pool-specific adapter, transfers parent REP to it, and instructs it to lock, fork, split, and sweep child REP. SecurityPoolMigrationProxy Zoltar Fork migration Acts as the literal Zoltar caller whose stable address holds the migration balance while parent REP is locked and split into child-universe REP. SecurityPoolForker SecurityPoolFactory Fork migration Requests canonical child-pool deployment for selected child universes. SecurityPoolForker SecurityPool Fork migration Copies or recomputes financial state, migrates vaults and collateral, and activates the selected child lifecycle. SecurityPoolForker UniformPriceDualCapBatchAuction Backing repair Starts, finalizes, and settles the child Truth Auction when migrated REP and inherited ETH collateral do not arrive in the required proportions.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"sources","heading":"Source contracts","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"ZoltarQuestionData.sol Zoltar.sol and ReputationToken.sol SecurityPoolFactory.sol SecurityPool.sol and ShareToken.sol EscalationGame.sol and SecurityPoolForker.sol OpenOraclePriceCoordinator.sol , LiquidationApprovalRegistry.sol , and OpenOracle.sol UniformPriceDualCapBatchAuction.sol","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"","heading":"","keywords":["glossary","terms","REP","universe","underwriting commitment","haircut","trading"],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Reference Canonical, plain-language definitions for terms used throughout the documentation.","title":"Protocol glossary","topic":"Introduction","weight":1},{"fragment":"universes-and-rep","heading":"Universes and REP","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Universe A Zoltar ledger and identity for universe-specific REP and application state. Universe 0 is the initialized root; later universes are descendants created through forks. Child universe A deterministic descendant that represents one valid answer to its parent's fork question. In a binary-market example, a Statoblast fork on its own question creates Invalid, Yes, and No children. If an unrelated fork interrupts that market, its children instead follow the unrelated categorical or scalar fork question's valid answers. Question A global Zoltar object that identifies a proposition, its end time, and its answer options. Outcome One possible answer to a question. Statoblast binary markets use Invalid, Yes, and No. Invalid The legitimate third outcome for ambiguous, malformed, or otherwise unanswerable market wording. REP Universe-specific reputation tokens used as reporting, dispute, and security capital. Theoretical REP supply Zoltar's per-universe REP supply figure, from which it derives the fork and non-decision thresholds. Burns reduce it, and each child universe starts from its parent's supply after the fork threshold burn plus the fork initiator's migration balance. Fork threshold The amount of parent-universe REP that a fork initiator supplies and burns to begin a fork, derived by getForkThresholdAttoRep from that universe's theoretical REP supply. See migration accounting . Fork haircut The part of the fork threshold that Zoltar burns without crediting to the initiator's migration balance: ⌊fork threshold ÷ forkBurnDivisor ⌋, at most 20%. Contract comments call it the burn haircut. REP added to a migration balance after the fork starts is credited in full. Migration balance A parent-universe credit ( migrationRepBalanceAttoRep ) created when REP is burned or committed for a fork. The same credited amount can be minted independently in each valid child, while per-child accounting prevents an account from consuming more than that amount in any one child. Child REP REP minted for one child universe. Its ledger and economic value are separate from parent and sibling REP.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"security-pools","heading":"SecurityPools, shares, and vaults","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"SecurityPool The Statoblast contract for one question, universe, and pool configuration (its security multiplier, which sets the REP-to-ETH backing it requires, and the gas priority fee it budgets for oracle price reports); each lineage has at most one pool per universe. It holds settlement collateral and coordinates shares, vaults, resolution, migration, and repair. Lineage An origin SecurityPool and every child pool forked from it. Pools in one lineage share an origin ID and one outcome-share token contract. Origin pool A SecurityPool deployed for a question with no parent pool ( deployOriginSecurityPool ). Child pools created by forks descend from it and form its lineage. Settlement collateral The ETH a SecurityPool records as backing its outcome shares ( settlementCollateralAttoEth ). Complete sets and winning shares redeem against it pro rata, and fees decay out of it into the fee reserve. Open interest The ETH exposure of outstanding complete sets that vaults underwrite. The contracts measure it with settlement collateral: getVaultOpenInterestAttoEth returns a vault's share of settlement collateral in proportion to its underwriting commitment. When a forked child holds less settlement collateral than its inherited shares claim, the gap is a shortfall for a Truth Auction to repair, not open interest. Complete set One matching unit each of Invalid, Yes, and No shares, minted against ETH and redeemable together while the pool is operational. Outcome share An ERC-1155 token representing one outcome claim in one universe-specific SecurityPool. Vault A SecurityPool account that records a participant's REP backing, underwriting commitment, obligations, and fees. Backing units Accounting units that represent a proportional claim on REP held for SecurityPool vaults. Underwriting commitment A vault owner's standing ETH underwriting amount, separate from REP backing. The code field is underwritingLimitAttoEth ; liquidation parameters and events name the same quantity debt or securityBondDebt . Its share of the pool total determines proportional settlement obligations and fee rights. Security multiplier A pool's required ratio, in basis points, of a vault's REP value to its underwriting commitment ( statoblastSecurityMultiplierBps ). It is fixed when the origin pool is deployed and must exceed 10,001 BPS. Vault health Whether a vault's REP backs its whole underwriting commitment at the cached REP-per-ETH price ( isVaultHealthy ). An unhealthy vault can be liquidated; see when a vault is liquidatable for the two constraints. Health factor A multiplier in basis points applied to both vault-health requirements of the receiver in a liquidation. 10,000 BPS is the protocol minimum; a liquidation approval can demand more through minPostLiquidationHealthFactorBps . The targetHealthFactorBps of a REP deposit is a separate value that must be at least the pool's security multiplier. Bad debt An ETH amount recorded against a vault ( vaultBadDebtAttoEth ) and summed for the pool ( totalBadDebtAttoEth ). A vault that carries any can be neither the target nor the receiver of a liquidation. Fork migration moves it to the child pool with its vault, and it is cleared when the pool's last share is redeemed. Liquidation itself records none. Minting capacity The ceiling on a pool's settlement collateral: its total underwriting commitments while no Escalation Game exists, and zero afterwards ( getCurrentMintingCapacityAttoEth ). Utilization Settlement collateral divided by minting capacity. It sets the retention rate. Fee reserve ETH that has decayed out of settlement collateral as fees and is not yet assigned to a vault ( unallocatedAccruedFeesAttoEth ). A vault checkpoint moves the vault's share into its claimable fees. Retention The per-second fraction of a SecurityPool's outstanding complete-set collateral that stays with complete-set holders; the remainder moves continuously into the pool's fee reserve. Because retention is below one, the ETH backing one complete set falls over time; see open-interest fees .","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"escalation","heading":"Escalation Game","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Escalation Game The local Statoblast dispute mechanism in which REP-backed balances accumulate behind Invalid, Yes, and No. Start bond The minimum Escalation Game deposit: the larger of 1 REP and the universe's theoretical REP supply when the pool was deployed ÷ 10 7 . Origin-pool deployment requires it to be below the non-decision threshold; a game started with a bond at or above that threshold is clamped to one atto-REP below that threshold. A smaller deposit is accepted only when it fills an outcome exactly to that threshold. A child pool continuing a forked game keeps its parent's start bond. Binding capital The median of the three outcome balances that determines the Escalation Game's scheduled deadline. Required support The REP an outcome must hold to stay in contention, called attrition cost in the contracts ( totalCostAttoRep ). It is zero for the three-day activation delay, then rises from the start bond to the non-decision threshold over 49 days. The game's deadline is the moment it passes binding capital. Non-decision threshold The balance that two outcomes must each reach for the Escalation Game to enter non-decision: half of the universe's fork threshold, rounded up, read when the game opens and fixed for that game and any game carried from it. Non-decision The Escalation Game state in which two outcomes have each reached the non-decision threshold ( NonDecisionState.Local ). The game picks no winner, and anyone can fork the universe on the pool's own question. Reward-eligible cap One and a half times binding capital. Only the portion of winning Escalation Game deposits up to this cap earns a bonus; deposits beyond it return principal only. See the EscalationGame reference . Escalation haircut Two fifths of binding capital, burned at Escalation Game settlement instead of being paid to winners as a bonus, unless the pool's own fork already paid it through the fork haircut. The contracts call it the winner haircut ( burnEscalationWinnerHaircut ).","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"forks-and-repair","heading":"Forks and repair","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"SecurityPoolForker The shared Statoblast contract that runs a SecurityPool through a fork: it snapshots the parent pool, migrates its REP and vaults into child pools, and runs each child's Truth Auction. Migration window The eight weeks ( MIGRATION_TIME ) after a parent pool enters fork mode, during which its vaults and REP can move into child pools. A child's Truth Auction can start only after it closes. Carried game An Escalation Game that a child pool continues from its parent's unresolved game, with the parent's balances and elapsed time. The game's forkContinuation flag marks it permanently, and it never accepts deposits from a wallet. The reference pages also call it a continuation game. Fork continuation The temporary state of a child pool whose carried game has not yet been resumed ( awaitingForkContinuation ). While it is pending, the pool rejects complete-set minting and Escalation Game deposits. Truth Auction A Statoblast auction that sells child REP to repair a child pool's ETH collateral shortfall. It does not select truth. Clearing tick The price tick at which a Truth Auction clears ( clearingTick ). In a funded auction, bids above it win in full, bids below it lose, and bids at it fill in arrival order, all at its price. Underfunded threshold The ETH-per-REP price at which selling the whole REP sale cap raises exactly the ETH raise cap, rounded up ( underfundedThreshold ). In an underfunded auction, where bids never reach either cap at their own prices, only bids at or above it buy REP, and together they receive the whole REP sale cap.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"liquidation","heading":"Liquidation","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Target vault The unhealthy vault whose underwriting commitment a liquidation reduces ( targetVault ). Receiver vault The vault that accepts the transferred commitment and the REP award ( receiverVault ). It must stay healthy on its whole resulting commitment. Operator The account that stages a liquidation ( operator ). It is the receiver unless the receiver approved it through the LiquidationApprovalRegistry, and it receives no protocol payment.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"prices","heading":"Prices","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"OpenOracle An economically contestable price-reporting contract used by Statoblast for fresh REP-per-ETH prices (written REP/ETH elsewhere in these pages), not market outcomes. Price coordinator The per-pool contract that requests OpenOracle prices, caches accepted reports, and queues solvency-sensitive SecurityPool operations. Sponsor lane The rule that, while a price report is pending, only the account that opened it ( pendingReportSponsor ) can add operations to that settlement. Other callers wait until the report finishes. VaultOperations executor The VaultOperations contract each price coordinator deploys. It stores a vault owner's bundle of up to four actions and is the only caller a SecurityPool accepts for price-checked REP withdrawals and liquidations.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"trading","heading":"Trading","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Trading pool The constant-product pair ( TwoWayConstantProductPair , called the pair in the Trading reference) that trades one SecurityPool's Yes and No shares against each other. The Trading factory creates at most one per SecurityPool. Trading router The TwoWayConstantProductRouter contract that turns ETH into a position and a position back into ETH by combining SecurityPool complete-set calls with trading-pool swaps. Long shares The Yes or No shares a trader holds on the side they expect to win. Entering through the trading router also leaves the trader one Invalid share for each complete set it minted, fewer than the long shares received. Insured exit A trading-router exit that swaps some long shares for the opposite outcome, then redeems them with the trader's Invalid shares as complete sets for ETH.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"","heading":"","keywords":["ABI","transactions","callers","events"],"path":"reference/contracts.html","sectionTitle":"Reference","summary":"Index of the per-contract interaction reference.","text":"Open a contract to see its read surface, any security assumptions or trust boundary, and each state-changing entrypoint with its caller, prerequisites, effects, and primary signals. The entrypoint count is the number of state-changing function signatures a contract answers, counting each overload, each selector its fallback() routes to a delegate, and receive() .","title":"Contract interactions","topic":"Contracts","weight":1},{"fragment":"table-columns","heading":"Table columns","keywords":[],"path":"reference/contracts.html","sectionTitle":"Reference","summary":"Index of the per-contract interaction reference.","text":"Every contract page uses the same five columns. Transaction : the function name with its parameter names in ABI order. Overloads appear as separate signatures. Caller : the addresses the contract accepts as msg.sender . Main prerequisites : the conditions the call requires, quoting a revert string where a caller needs it to tell failures apart. State or asset effect : what a successful call changes. Primary signals : the events a successful call emits, each with the condition under which it is emitted, including events emitted by contracts the call reaches. A row says so when a call can succeed without emitting an event. Contract Purpose State-changing entrypoints ZoltarQuestionData Creates immutable, content-addressed scalar or categorical questions and exposes their display metadata. 1 Zoltar Registers universe forks, charges the fork haircut , and mints branch-specific child REP . 6 ReputationToken Implements universe-specific ERC-20 REP, ERC-2612 permits, and ERC-3009 transfers while enforcing the supply ceiling maintained by Zoltar. 10 SecurityPoolFactory Creates and canonically registers origin and child security pools with their share token, oracle coordinator, and optional Truth Auction. 2 SecurityPool Holds ETH settlement collateral and REP underwriting, accounts for vaults and fees, mints outcome shares , and routes local escalation. 38 SecurityPoolForker Freezes parent pools, creates selected child pools, migrates vault and escalation state, and settles collateral-repair Truth Auctions . Child-game trust boundary 14 EscalationGame Escrows outcome REP, raises the running resolution cost, detects non-decision , and settles local or carried deposits. 22 LiquidationApprovalRegistry Stores coordinator-local, bounded authorization for a receiver vault to accept liquidation debt from an exact operator. 8 OpenOraclePriceCoordinator Obtains a fresh REP-per-ETH price and coordinates withdrawals, delegated liquidation routing, approval reservations, and terminal cleanup. 11 VaultOperations Accepts a wallet bundle of vault actions for one security pool, stores the price-dependent actions, and is the only caller that pool accepts for executor-gated vault entrypoints. 4 ShareToken Stores universe-aware ERC-1155 outcome shares and materializes a holder's persistent source entitlement in selected fork branches. 10 UniformPriceDualCapBatchAuction Collects ETH bids under ETH-raise and REP-sale caps, computes one clearing result, and supports paged settlement. 7","title":"Contract interactions","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["questions","categorical","scalar","encoding"],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Creates immutable, content-addressed scalar or categorical questions and exposes their display metadata. ZoltarQuestionData source contract","title":"ZoltarQuestionData","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Use getQuestionId before submission; questionCreatedTimestamp and questions for direct lookup; getQuestionCount and getQuestions for indexed or paged discovery; and getQuestionEndDate , getOutcomeLabels , splitUint256IntoTwoWithInvalid , hasNonZeroScalarReservedBits , isMalformedAnswerOption , and getAnswerOptionName when validating or displaying answers. In the QuestionData tuple, startTime and endTime are uint48 , while numTicks is uint120 ; clients must use these exact widths because they determine the getQuestionId and createQuestion selectors.","title":"ZoltarQuestionData","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals createQuestion(questionData, outcomeOptions) Anyone Question ID not already created; end time is on or after start time. Scalar questions use no labels, require display maximum greater than minimum, and positive ticks. Categorical questions require nonempty labels whose keccak256(abi.encode(label)) values are strictly descending. Stores the question at its deterministic content hash, records the creation timestamp, appends it to discovery order, and stores categorical labels when supplied. QuestionCreated","title":"ZoltarQuestionData","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["fork","universe","migration","child REP"],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Registers universe forks, charges the fork haircut , and mints branch-specific child REP . Zoltar source contract","title":"Zoltar","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Use universes , forkThresholdDivisor , forkBurnDivisor , zoltarQuestionData , genesisReputationToken , childReputationTokenCount , getForkTime , forkQuestionMatches , getRepToken , getForkThresholdAttoRep , getNonDecisionThresholdAttoRep , getUniverseTheoreticalSupplyAttoRep , getChildUniverseId , getDeployedChildUniverses , getMigrationRepBalanceAttoRep , and getChildMigrationRepAmountsAttoRep to reconstruct universe and migration state. The child migration getter accepts an array of child universe IDs and returns cumulative amounts in the same order, with zero for unused IDs. The fork threshold is the live universe theoretical supply divided by forkThresholdDivisor , rounded up, so every nonzero-supply universe has a positive fork cost. Construction requires a deployed genesis REP token with the REPv2 getTotalTheoreticalSupply() selector, theoretical supply from one attoREP through 11 million REP, forkThresholdDivisor > 1 , and forkBurnDivisor >= 5 , which caps the uncredited fork haircut at 20% of the threshold. The constructor emits UniverseInitialized once, for genesis universe 0 ; deployChild does not emit it, so child universes are discovered through DeployChild and ChildReputationTokenInitialized . Genesis REP uses ordinary ERC-20 approvals because the configured mainnet REPv2 token does not implement ERC-2612 or ERC-3009.","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"These calls depend on A15 intended question selection and A25 safe immutable parameters .","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals forkUniverse(universeId, questionId) Any address able to fund the current fork threshold Initialized and unforked universe; existing ended question; sufficient caller REP. Genesis REP requires allowance; child REP is burned directly without allowance. Records the fork, removes threshold REP from the parent universe, and credits the caller with the threshold minus the uncredited fork haircut. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then UniverseForked burnRep(universeId, amountAttoRep) Any REP holder; the caller can burn only its own balance Initialized universe; positive amount; sufficient caller REP and theoretical supply. Genesis REP requires allowance. Permanently removes REP without creating migration credit; escalation settlement uses this to burn the escalation haircut when its own fork has not already paid it. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then RepBurned deployChild(universeId, outcomeIndex) Anyone Parent forked; outcome is well formed; child is not already deployed. Deploys the deterministic child REP token and initializes the child universe. TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized addRepToMigrationBalance(universeId, amountAttoRep) Parent REP holder Universe forked; sufficient caller REP. Genesis REP requires allowance; child REP is burned directly without allowance. Burns or sinks additional parent REP and increases the caller's reusable migration balance. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then MigrationRepAdded prepareAndSplitMigrationRep(universeId, amountAttoRep, outcomeIndexes, preparationAttoRep) Parent REP holder Forked universe; positive split amount; nonempty valid outcomes; sufficient parent REP for the exact preparationAttoRep supplied and sufficient migration credit for every split. Outcome order is unrestricted. Genesis REP requires allowance for preparation; child REP needs no allowance. Adds the supplied preparation amount to migration credit, then splits the requested REP into the supplied outcomes using the existing migration checks. Both steps revert together on failure. Callers compute any preparation shortfall from cumulative child migration amounts, rather than current child token holdings. The addRepToMigrationBalance signals when preparationAttoRep is positive; TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized when children are deployed; child REP Transfer , Mint , and MigrationRepSplit for each destination splitMigrationRep(universeId, amountAttoRep, outcomeIndexes) Migration-balance holder Universe forked; positive split amount; nonempty list of well-formed outcomes; the cumulative amount per child must not exceed the caller's migration balance. Mints amountAttoRep of child REP into every selected branch, deploying missing children lazily. TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized when children are deployed; child REP Transfer and Mint , then MigrationRepSplit , per selected branch","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["REP","ERC-20","permit","supply"],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Implements universe-specific ERC-20 REP, ERC-2612 permits, and ERC-3009 transfers while enforcing the supply ceiling maintained by Zoltar. ReputationToken source contract","title":"ReputationToken","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Use getTotalTheoreticalSupply , zoltar , universeId , and repNumber to identify the token and its supply ceiling; the standard ERC-20 reads name , symbol , decimals , totalSupply , balanceOf , and allowance for balances; and nonces , DOMAIN_SEPARATOR , and authorizationState to build and check ERC-2612 and ERC-3009 signatures.","title":"ReputationToken","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals initialize(universeId, totalTheoreticalSupplyAttoRep, repNumber) Zoltar only Called once by Zoltar as part of child-universe creation; universe, REP number, and theoretical supply are nonzero; supply does not exceed 11 million REP. Atomically assigns the child universe, global display sequence, name, symbol, and theoretical-supply ceiling used to bound migration mints. TheoreticalSupplySet and ReputationTokenInitialized mint(account, valueAttoRep) Zoltar only account is nonzero; resulting ERC-20 supply does not exceed theoretical supply. Mints branch REP to an account. Mint and ERC-20 Transfer burn(account, valueAttoRep) Zoltar only account is nonzero and has sufficient REP; theoretical supply covers the burn. Burns account REP and reduces both actual and theoretical supply by the same amount. Burn and ERC-20 Transfer transfer(to, value) REP holder Destination is nonzero; caller has sufficient balance. Moves REP from the caller without changing actual or theoretical supply. Transfer approve(spender, value) Any REP account setting its own allowance Spender is nonzero. Replaces the named spender allowance without moving REP. Approval transferFrom(from, to, value) A spender with sufficient allowance from from Source and destination are nonzero; source has sufficient balance; caller has sufficient allowance, including when caller equals source. Moves REP from from ; a finite allowance decreases by value , while an infinite allowance remains unchanged. Neither allowance path emits Approval . Transfer only permit(owner, spender, value, deadline, v, r, s) Anyone presenting the owner's valid ERC-2612 signature Deadline has not passed; signature matches the current chain, token domain, owner, spender, value, and nonce. Sets the signed allowance and advances the owner's permit nonce. Approval transferWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s) Anyone presenting the source's valid ERC-3009 signature The strict validity window is open; the nonce is unused; signature fields and source balance are valid. Consumes the authorization nonce and transfers the exact signed amount to the signed recipient. AuthorizationUsed and Transfer receiveWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s) The signed recipient presenting the source's valid ERC-3009 signature Caller equals the signed recipient; the strict validity window is open; the nonce is unused; signature fields and source balance are valid. Consumes the authorization nonce and transfers the exact signed amount to the caller-bound recipient. AuthorizationUsed and Transfer cancelAuthorization(authorizer, nonce, v, r, s) Anyone presenting the authorizer's valid ERC-3009 cancellation signature The nonce is unused and the cancellation signature matches the authorizer. Marks the authorization nonce as consumed without transferring tokens. AuthorizationCanceled","title":"ReputationToken","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["factory","deployment","registration","CREATE2"],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Creates and canonically registers origin and child security pools with their share token, oracle coordinator, and optional Truth Auction. SecurityPoolFactory source contract","title":"SecurityPoolFactory","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Use minimumSecurityBondDebtAttoEth and minimumVaultRepDepositAttoRep for immutable deployment floors. Each pool derives its start bond at construction from Zoltar’s universe theoretical REP supply ( getUniverseTheoreticalSupplyAttoRep ) as max(1 REP, theoretical REP supply / 10,000,000) . A zero configured vault REP floor selects the default theoretical REP supply / 100,000 ; a nonzero constructor value is the exact override. The security-bond debt floor is the exact nonzero constructor value; the repository deployment configuration uses 1 ETH. Construction rejects a zero or code-less operations delegate. Use securityPoolDeploymentCount with the strict securityPoolDeploymentsRange(startIndex, count) pager, which reverts rather than truncating when the requested range exceeds the array. Use getOriginId , getPoolId , getSecurityPool , getSecurityPoolOriginId , and getSecurityPoolHasInheritedForkOutcome for canonical lookup.","title":"SecurityPoolFactory","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals deployOriginSecurityPool(universeId, questionId, statoblastSecurityMultiplierBps, initialReportPriorityFeeAttoEthPerGas) Anyone statoblastSecurityMultiplierBps > 10_001 , which makes the halfway migration component strictly greater than one; the effective pool-held vault REP backing multiplier separately floors that component at the 10,500-BPS liquidation-award reserve described by the liquidation design . initialReportPriorityFeeAttoEthPerGas > 0 and remains within the coordinator-computed OpenOracle uint128 report/escalation-halt capacity bound; question exists, the transaction timestamp is strictly before its end time, and it has exactly the categorical labels Yes , then No ; universe is unforked and has a REP token; the non-decision threshold exceeds the construction-time start bond max(1 REP, theoretical REP supply / 10,000,000) ; no pool has already been claimed for this question, multiplier, priority fee, and universe ( Security pool origin and universe already claimed ). Creates the canonical origin pool, its lineage-wide share token, and its price coordinator with the configured initial-report priority fee, then wires and registers them atomically. SecurityPoolRegistered , then DeploySecurityPool deployChildSecurityPool(parent, shareToken, universeId, questionId, statoblastSecurityMultiplierBps, currentRetentionRate, settlementCollateralAttoEth) SecurityPoolForker only ( Only security pool forker ) Parent is the canonical pool for its lineage; supplied share token equals the parent share token; no pool has already been claimed for the parent origin in the target universe; deployment arguments satisfy downstream constructors and wiring. Creates and registers a canonical child pool with a coordinator that inherits initialReportPriorityFeeAttoEthPerGas from the parent coordinator and a forker-owned Truth Auction, while retaining the parent lineage share token. SecurityPoolRegistered , then DeploySecurityPool","title":"SecurityPoolFactory","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["collateral","vault","complete set","fees","liquidation"],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Holds ETH settlement collateral and REP underwriting, accounts for vaults and fees, mints outcome shares , and routes local escalation. SecurityPool source contract","title":"SecurityPool","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Relationship and configuration getters, all set at construction, are questionId , universeId , initialEscalationGameDepositAttoRep , zoltar , parent , shareToken , repToken , openOraclePriceCoordinator , openOracle , escalationGameFactory , eventEmitter , questionData , securityPoolForker , truthAuction , securityPoolFactory , and statoblastSecurityMultiplierBps ; the current game is escalationGame . The start bond is derived at construction from live universe theoretical REP supply rather than copied from factory configuration. Accounting getters include totalUnderwritingLimitAttoEth , settlementCollateralAttoEth , totalRepBackingUnits , shareTokenSupplyAttoShares , securityVaults , minimumSecurityBondDebtAttoEth , minimumVaultRepDepositAttoRep , totalBadDebtAttoEth , and vaultBadDebtAttoEth . Aggregate and per-vault bad debt describe only the current collateral-claim generation; getPoolAccountingSnapshot exposes its badDebtGeneration . Exhausting the remaining claim supply clears aggregate debt and advances the generation before later collateral can be minted. Use getVaultUnderwritingLimitAttoEth for the standing owner-authorized ETH commitment, separate from REP deposits. Use getVaultCapacityBackingFactorsBps for current associated and pool-held REP-per-capacity ratios, getCurrentMintingCapacityAttoEth for total standing commitments (zero once an escalation game exists), and getVaultOpenInterestAttoEth for a vault’s live proportional obligation. Other derived and paged reads are getVaultCount , getVaults , attoSharesToAttoEth , attoEthToAttoShares , attoRepToBackingUnits , backingUnitsToAttoRep , getTotalPoolHeldAttoRep , totalAccruedFeesAttoEth , getPoolAccountingSnapshot , getFeeEpochEndTime , getVaultFeeRemainder , and isEscalationResolved . The backing-factor ratios are not current vault health: associated REP includes dispute-staked principal as at-risk security, while current health also depends on the full underwriting commitment, REP-per-ETH price, the security multiplier, and both protocol constraints. The vault registry is append-only and newest-registered first. Registration requires only a nonzero address and can occur without economic state; consumers filter current positions from securityVaults , escalation stake, and bad debt. isEscalationResolved() is true when the pool inherits a fixed fork outcome, or when a local escalation game is configured and the forker routes a non- None outcome. An operational fixed-outcome child remains available for settlement and redemption but rejects new collateralized operations. getFeeEpochEndTime() returns the effective fee cutoff, or type(uint256).max for an open child epoch. A resolved child without a continuation game fixes its cutoff at activation. Lifecycle and fee getters are totalClaimableVaultFeesAttoEth , lastUpdatedFeeAccumulator , feeIndex , currentRetentionRate , awaitingForkContinuation , and systemState .","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Price-sensitive withdrawal, commitment-increase, and liquidation calls depend on A16 timely inclusion , A21 genesis REP and WETH behavior , A19 observable correctable price , and A06 lifecycle executors . User-initiated pool calls additionally depend on A28 account authority .","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Rows marked \"through fallback() \" are not in the compiled ABI: the pool forwards exactly those four selectors to SecurityPoolOperationsDelegate by delegatecall and rejects every other unknown selector with Unsupported pool operation . Transaction Caller Main prerequisites State or asset effect Primary signals burnEscalationWinnerHaircut(amountAttoRep) This pool's EscalationGame only Caller is the configured escalation game; amount is positive and the game has already transferred enough REP to the pool. Burns REP the game has just transferred to the pool: a winning deposit's escalation haircut, or a fork-continuation game's terminal residual. RepBurned and ERC-20 Transfer ; child REP also emits Burn setUnderwritingLimit(limitAttoEth) Vault owner Operational pool ( Pool inactive ) in an unforked universe ( Forked ); a resolved operational pool may still reduce a commitment after an unrelated late fork. Increases require open admission, a fresh price ( Stale price ), and both full-commitment backing checks ( Vault backing insufficient ). Reductions, including a zero exit, must leave total commitments at least equal to tracked settlement collateral ( Commitments below collateral ). Checkpoints the vault fees, then changes the underwriting commitment independently of REP ownership and recalculates retention. A call that repeats the current value returns before the checkpoint and changes nothing. Fee-accrual and retention-change PoolAccountingCheckpoint events when due; then UnderwritingLimitSet , VaultAccountingCheckpoint , and PoolAccountingCheckpoint ; no event for a call that repeats the current value setVaultUnderwritingLimit(vault, limitAttoEth) through fallback() This pool's VaultOperations executor only ( Unauthorized ) The setUnderwritingLimit prerequisites, evaluated for vault . Applies the setUnderwritingLimit change to vault . The executor calls it for a coordinator SetVaultUnderwritingLimit operation and for the commitment change in a vault bundle. The setUnderwritingLimit signals, with UnderwritingLimitSet naming vault depositRepToVault(amountAttoRep, targetHealthFactorBps) Vault owner Operational and unforked; isEscalationResolved() is false; the transaction timestamp is strictly before the question end time unless the pool has an inherited fork-continuation game; amountAttoRep is positive ( Zero REP ); targetHealthFactorBps is at least statoblastSecurityMultiplierBps ( Target below pool minimum ); resulting vault REP is at least minimumVaultRepDepositAttoRep ( Vault REP below minimum ). targetHealthFactorBps is only checked against that floor; it neither is stored nor authorizes a commitment. Checkpoints the vault fees, prices proportional REP backing units before receiving the transfer, pulls amountAttoRep from the caller through the caller's allowance to this pool, then credits only those units. Depositing REP never changes the underwriting commitment. Fee-accrual checkpoints when due; REP Transfer ; RepDepositedToVault , VaultAccountingCheckpoint , then PoolAccountingCheckpoint depositRepToVaultWithPermit(amountAttoRep, targetHealthFactorBps, deadline, v, r, s) through fallback() Vault owner The pool universe is not genesis ( Genesis REP does not support permit ); the permit succeeds or the caller allowance to this pool is at least amountAttoRep ( Vault permit and allowance insufficient ); the depositRepToVault prerequisites. Calls the REP token permit for amountAttoRep from the caller to this pool, ignores a failed permit when the existing allowance already covers the amount, then performs the depositRepToVault deposit. REP Approval when the permit succeeds, then the depositRepToVault signals depositRepToVaultWithAuthorization(owner, amountAttoRep, targetHealthFactorBps, validAfter, validBefore, nonce, v, r, s) through fallback() Anyone relaying the owner's ERC-3009 signature The pool universe is not genesis ( Genesis REP does not support authorization ); the depositRepToVault prerequisites for owner ; the signature authorizes the token nonce keccak256(abi.encode(nonce, operationHash, owner)) , where operationHash is keccak256(abi.encode(depositRepToVaultWithAuthorization.selector, owner, universeId, questionId, amountAttoRep, targetHealthFactorBps)) . Runs the depositRepToVault checks for owner , pulls amountAttoRep from owner to this pool through the REP token receiveWithAuthorization , then credits owner 's vault. Fee-accrual checkpoints when due; REP AuthorizationUsed and Transfer ; RepDepositedToVault , VaultAccountingCheckpoint , then PoolAccountingCheckpoint depositRepToVaultFromExecutor(owner, amountAttoRep) through fallback() This pool's VaultOperations executor only ( Only vault operations executor ) The depositRepToVault prerequisites for owner , other than the target check, which always passes. Performs the depositRepToVault deposit for owner , pulling REP through owner 's allowance to this pool, with the target fixed at statoblastSecurityMultiplierBps . The depositRepToVault signals redeemFees(vault) Anyone; any nonzero ETH payment is always sent to vault A nonzero payment path requires vault to accept ETH. First accrues the vault's fees. If resulting claimable fees are zero, returns without payment; otherwise clears and pays the full amount. Accrual checkpoints only when accrual state changes; both VaultAccountingCheckpoint and PoolAccountingCheckpoint for a nonzero redemption; no event when fees and accrual state are unchanged createCompleteSet() with ETH Trader Operational and unforked; no escalation game, pending continuation, or inherited fixed outcome; positive ETH converts to at least one complete-set unit. Resulting tracked collateral must not exceed total commitments; no oracle price or REP backing is checked. A contract trader must accept onERC1155BatchReceived under A22 asset-recipient compatibility . Adds collateral and mints one Invalid , Yes , and No share per complete-set unit, then invokes the ERC-1155 batch-receiver callback for a contract trader. Callback rejection rolls back the ETH, pool accounting, events, and share mint. Accrual PoolAccountingCheckpoint when due; CompleteSetCreated , PoolAccountingCheckpoint , then ERC-1155 TransferBatch on a successful callback; retention PoolAccountingCheckpoint when the rate changes redeemCompleteSet(amountAttoShares) Anyone; positive redemption requires the caller to hold the complete set Operational and unforked; caller holds every outcome amount requested; caller accepts the resulting ETH call, including zero value. Zero is accepted without a token balance. Burns equal balances of all three outcomes and pays amountAttoShares * settlementCollateralAttoEth / shareTokenSupplyAttoShares using the pool's remaining economic claim supply as its collateral denominator. Complete-set issuance adds to that denominator, while complete-set and winning-share redemption consume it; fork-time source entitlements materialize without changing it because their claims are already reserved. When the remaining supply reaches zero, aggregate bad debt is cleared and per-vault bad-debt reads advance to an empty collateral generation. Zero passes the token and accounting checks and follows the normal zero-value event, checkpoint, and ETH-send path; rejection of that ETH call reverts the transaction. CompleteSetRedeemed and PoolAccountingCheckpoint redeemShares() Anyone; a positive payout requires the caller to hold winning shares Operational pool with a final outcome; caller accepts the resulting ETH call, including zero value. Burns the caller's full winning balance and pays its pro-rata remaining collateral. When the remaining supply reaches zero, aggregate bad debt is cleared and per-vault bad-debt reads advance to an empty collateral generation. A zero winning balance passes token and accounting checks and follows the normal zero-value event, checkpoint, and ETH-send path; rejection of that ETH call reverts the transaction. SharesRedeemed and PoolAccountingCheckpoint redeemRepFromVault(vault) Vault owner; caller must equal vault , and REP is sent to vault Operational pool with a final outcome; the specified vault has no escalation escrow, has redeemable REP, and has exited its underwriting commitment by setting it to zero ( Exit commitment before REP redemption ) under the limit-reduction rules . Burns the vault's REP backing units and returns its proportional vault REP backing. Fee-accrual checkpoints when due; REP Transfer , RepRedeemedFromVault , then VaultAccountingCheckpoint depositWalletRepToEscalationGame(outcome, maximumDepositAttoRep) REP holder with a token allowance for the pool Question end time reached ( block.timestamp >= endTime ) before starting a game; pool operational in an unforked universe, without an inherited fixed outcome or pending fork continuation; game is not a fork continuation; outcome and amount accepted; sufficient wallet REP and pool allowance. No existing vault or oracle price is required. Starts an ordinary game if needed and transfers the accepted REP directly from the caller into game escrow. Records the caller as depositor without minting vault backing units or underwriting commitments. Also accepts deposits if another reporter has already started the ordinary game. GameStarted , then EscalationGameSet , when the call deploys the game; REP Transfer ; game LocalDepositAppended and DepositOnOutcome ; game NonDecisionReached when the deposit reaches non-decision depositToEscalationGame(outcome, maximumDepositAttoRep) Vault owner Question end time reached ( block.timestamp >= endTime ); pool operational in an unforked universe, without an inherited fixed outcome, and not awaiting continuation. On the first deposit, the live non-decision threshold must exceed one attoREP; outcome and amount accepted; the remaining vault and aggregate pool totals each preserve both full-commitment backing requirements; the vault keeps either no REP or at least minimumVaultRepDepositAttoRep ( Vault REP below minimum ); a fresh price is required when total underwriting commitment is nonzero. Deploys the local game on the first deposit. The game factory uses the configured start bond while it is below the live non-decision threshold; if tracked REP supply later makes it too large, the factory uses nonDecisionThresholdAttoRep - 1 instead. Repeat deposits use the existing game's stored startBondAttoRep and nonDecisionThresholdAttoRep . Every accepted deposit removes enough REP backing units and escrows dispute-staked REP on the selected outcome. GameStarted , then EscalationGameSet , when the call deploys the game; REP Transfer ; game LocalDepositAppended and DepositOnOutcome ; game NonDecisionReached when the deposit reaches non-decision; then DepositToEscalationGame and VaultAccountingCheckpoint withdrawFromEscalationGame(outcome, depositIndexes) Anyone; a nonempty list must select deposits belonging to one original depositor Game configured; operational pool; valid final outcome. If an external fork interrupted the game, parent withdrawal stays unavailable ( Migrate deposits first ): winners settle in the child by carried proof, inherited losers require no transaction, and unresolved parent escalation-deposit accounting cleanup is optional. A nonempty list additionally requires valid local indexes and one common depositor. A nonempty list settles local deposits and pays winning REP to the immutable depositor recorded by each deposit. Liquidation cannot change that payout address. An empty list returns after the outer lifecycle checks without settlement, state change, or event. Per processed deposit, escalation-game CarryDepositConsumed and VaultEscrowUpdated ; additionally ClaimDeposit for a winning deposit. No event for an empty list withdrawForkedEscalationDeposits(outcome, proofs) Anyone; a nonempty list must name one original depositor across all proofs Game configured; operational child pool; valid final outcome. A nonempty list additionally requires an initialized and fully resumed continuation game, valid unconsumed winning proofs, and one common depositor. A nonempty list verifies and consumes carried proofs, then pays winning child REP to the immutable depositor committed in each leaf. Stable continuation identities retain the creating game. Allocations follow the source-game chain and apply each auction REP removal through cumulative interval rounding; read cost grows with fork depth. An empty list returns after the outer lifecycle checks without proof verification, state change, or event. Per processed proof, escalation-game CarryDepositConsumed and ClaimDeposit . No event for an empty list updateSettlementCollateral() Anyone No caller or lifecycle restriction. When the accumulator is already at or beyond the clamped timestamp, it leaves the accumulator unchanged and emits no event, though it still caches the current fee-epoch cutoff. For an initial pool, accrues elapsed fees through question end while its universe remains unforked; if its question remains unresolved when the universe forks, the fork timestamp replaces question end as the cutoff, including a later question-end-to-fork interval. A question finalized before the fork retains its question-end cutoff. Finalizing an activated child starts a separate epoch at that finalization timestamp, which runs until the child game resolves or the child universe subsequently forks. An inherited fixed-outcome child without a continuation game fixes its cutoff at finalization and accrues no later fees. Accumulator timestamps prevent charging an interval twice. It moves whole credited fees from settlement collateral into the unallocated accrued-fee reserve and advances the accumulator. With positive elapsed time but zero fee-eligible underwriting commitment it clears denominator-specific remainder and advances the timestamp without charging fees. PoolAccountingCheckpoint whenever positive elapsed time is processed, including the zero-commitment branch; no event for an unchanged timestamp updateRetentionRate() Anyone No caller restriction. It returns unchanged when the pool is not Operational ; otherwise it first accrues fees, then stores the rate only if it differs. Zero minting capacity (no standing commitments or an escalation game) selects the maximum retention rate. Recalculates the retention rate from current collateral and total underwriting commitment. Accrual PoolAccountingCheckpoint when due; an additional PoolAccountingCheckpoint only when the stored retention rate changes updateVaultFees(vault) Anyone for any address No caller, nonzero-vault, or lifecycle restriction. A vault accounting checkpoint: first updates pool accrual, then advances the vault fee index and fractional remainder, moves whole assigned fees from reserve to the vault, registers any previously unseen nonzero vault address regardless of economic state, and returns leftover reserve to settlement collateral once a forked pool has checkpointed all fee-eligible underwriting commitment. It never changes an underwriting commitment, including in an empty pool. Accrual PoolAccountingCheckpoint when due; VaultAccountingCheckpoint when the vault index, remainder, or claimable fee balance changes; an additional PoolAccountingCheckpoint when pool accounting changes; no event when neither accrual nor vault or pool accounting changes withdrawRepFromVault(vault, amountAttoRep) This pool's VaultOperations executor only ( Unauthorized ) Fresh coordinator price; operational pool in an unforked universe; isEscalationResolved() is false; no vault REP escrow. The remaining vault backing must meet both upward-rounded associated-REP and pool-held-REP requirements for its full underwriting commitment, with equality healthy. The remaining aggregate backing must also cover the entire total underwriting commitment under both backing constraints. A withdrawal cannot implicitly exit a commitment. Removes the requested proportional REP backing units, or all backing units when the requested remainder would fall below the REP minimum; preserves the vault and aggregate underwriting commitments; recalculates retention; and transfers the resulting withdrawable REP to vault . REP Transfer ; RepWithdrawnFromVault ; VaultAccountingCheckpoint ; and applicable fee-accrual or retention PoolAccountingCheckpoint events performLiquidation(request) This pool's VaultOperations executor only ( Unauthorized ) In ABI order, request contains operationId , operator , receiverVault , targetVault , requestedDebtAttoEth , snapshot , minimumReceiverHealthFactorBps , and minLiquidationPriceDistanceBps . The nested snapshot contains only targetBackingUnits and targetUnderwritingLimitAttoEth . Fresh settled coordinator price; operational pool in an unforked universe; isEscalationResolved() is false; receiver differs from target; neither participant has current-generation bad debt. A bad-debt-bearing vault becomes eligible again after the current collateral claims are exhausted, which clears aggregate debt and advances the bad-debt generation. The two target snapshot fields must match, while execution reads current pool totals. After target and receiver fee checkpoints, the liquidation delegate requires live target backing, dispute-staked REP, and full underwriting commitment to remain at least minLiquidationPriceDistanceBps beyond the liquidation threshold and requires the live target state to remain unhealthy. When debt moves, the receiver must satisfy the protocol backing checks multiplied by its approved minimum health factor, using live post-liquidation state and upward-rounded requirements; its resulting commitment must meet the configured debt floor and its REP must meet the vault floor. The target resulting commitment must be zero or meet the commitment floor; partial awards reserve the target REP floor when available. Transfers up to the requested ETH commitment from target to authorized receiver, conserving total commitments. REP awards are capped by available target backing. A sufficiently backed receiver can accept the full commitment even when the nominal award is underfunded. Fees checkpoint first and remain with their earners; escalation claims remain with their owners. Residual commitments remain visible and continue earning fees. Liquidation creates no write-off. Fee-accrual checkpoints when due; VaultLiquidated only when a positive commitment moves, identifying operation, operator, receiver, and target, with the moved commitment in both securityBondDebtMovedAttoEth and underwritingLimitMovedAttoEth and zero badDebtAttoEth ; target VaultAccountingCheckpoint always; receiver VaultAccountingCheckpoint only when a positive commitment moves; then PoolAccountingCheckpoint setStartingParams(currentRetentionRate, settlementCollateralAttoEth) SecurityPoolFactory only Caller is the factory ( Only factory ). The pool has no internal one-shot or lifecycle guard; the factory exposes it only through atomic deployment wiring. Sets the fee timestamp and initial question-end epoch cutoff, retention, and collateral, seeds the coordinator with zero for an origin or the parent's last price for a child, then checkpoints initialization. Coordinator RepEthPriceSet and CoordinatorStateCheckpoint , then pool PoolAccountingCheckpoint , even for zero or repeated values if the factory were to call again activateForkMode() SecurityPoolForker only The pool has no inherited fixed outcome, so a fixed child cannot reopen for a later universe fork. There is no current-state guard otherwise. A configured game's drain must succeed or the entire activation reverts with the game's reason. Sets PoolForked , accrues through the fork clamp, transfers the pool's entire REP balance to the forker, then makes the pool drain its configured escalation game's entire REP balance to the forker. Repeated calls are not lifecycle-guarded and transfer any balances replenished since the prior call before repeating the checkpoints. Pool-held REP Transfer always, including at zero; configured-game REP Transfer only for a positive game balance; accrual checkpoint when due; always PoolForkModeActivated and fork-activation PoolAccountingCheckpoint initializeForkedEscalationGame(startBondAttoRep, nonDecisionThresholdAttoRep, elapsedAtFork, fixedQuestionOutcome) SecurityPoolForker only No game is configured (otherwise it reverts without reason data); downstream startFromFork parameters are valid. Deploys and starts the pool's paused fork-continuation game with inherited timing and optional fixed outcome, and reopens vault admission after question end. Escalation GameContinuedFromFork , then pool EscalationGameSet initializeForkCarrySnapshotWithResolutionBalances(sourceGame, snapshotId, inheritedCarryPeaks, inheritedCarryLeafCounts, inheritedCarryTotals, inheritedResolutionBalances, inheritedNullifierRoots) SecurityPoolForker only A game is configured; it is a fork continuation with no prior snapshot; leaf counts fit the MMR; supplied or computed snapshot ID matches the data. Installs the continuation game's immutable carry peaks, counts, totals, resolution balances, and normalized nullifier roots. ForkCarryCheckpoint resumeForkedEscalationGame() Anyone Pool is operational, awaiting a configured fork continuation, and the game has not resumed. Checks aggregate REP funding of the carry commitment installed during child initialization, clears the pool wait flag, records the resume timestamp, and starts the continuation's remaining escalation clock in one bounded call. ForkContinuationResumed and AwaitingForkContinuationSet(false) setAwaitingForkContinuation(shouldAwait) SecurityPoolForker only No lifecycle or value-change guard. Stores whether complete-set minting must wait for continuation initialization. AwaitingForkContinuationSet , including for a repeated value setSystemState(newState) SecurityPoolForker only No transition or value-change guard. Replaces the pool lifecycle state directly. SystemStateSet , including for a repeated state configureVault(vault, repBackingUnits, underwritingLimitAttoEth, vaultFeeIndex, newVaultBadDebtAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only vault is nonzero; no lifecycle or value-change guard. Replaces the vault REP backing units, price-independent underwriting commitment, fee index, vault bad debt, and aggregate pool bad debt, clears pooled fee-index remainder when underwriting commitment changes, and registers the nonzero vault address regardless of the supplied state. Always VaultAccountingCheckpoint and PoolAccountingCheckpoint , including when all supplied values repeat current state activateRecoveredCommitment(vault, commitmentAttoEth) SecurityPoolForker only Operational, unforked pool, fresh price and both backing checks on the receiver’s entire resulting underwriting commitment. Activates prospective fee eligibility for an orphaned commitment after the forker checkpoints and assigns its backing and commitment. Total commitments remain unchanged. PoolAccountingCheckpoint configureFinalizedAuctionVault(vault, repBackingUnits, underwritingLimitAttoEth, vaultFeeIndex, newVaultBadDebtAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only vault is nonzero; the forker has already included the sold underwriting commitment in the pool fee denominator at auction finalization. Assigns finalized-auction REP backing and already-fee-eligible underwriting commitment to the winning vault without clearing the pool-wide fee-index remainder, then replaces the vault fee index, bad debt, and aggregate pool bad debt and registers the vault. Always VaultAccountingCheckpoint and PoolAccountingCheckpoint , including when all supplied values repeat current state setTotalRepBackingUnits(newTotalRepBackingUnits) SecurityPoolForker only No lifecycle or value-change guard. Replaces the REP backing units denominator. TotalRepBackingUnitsSet , including for zero or a repeated value setShareTokenSupplyAttoShares(newShareTokenSupplyAttoShares) SecurityPoolForker only No lifecycle or value-change guard. Replaces stored shareTokenSupplyAttoShares , the denominator used by attoSharesToAttoEth and complete-set redemption. ShareTokenSupplySet , including for zero or a repeated value setPoolFinancials(newSettlementCollateralAttoEth, newTotalUnderwritingLimitAttoEth, newFeeEligibleUnderwritingLimitAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only Fee-eligible underwriting commitment does not exceed total underwriting commitment. Actual ETH covers the supplied collateral plus all accrued fee liabilities. Installing inherited liabilities does not require current REP solvency. Replaces settlement collateral, both price-independent underwriting-commitment totals, and aggregate pool bad debt, resets the fee timestamp to the current block, opens the finalized child fee epoch unless the child has a fixed outcome and no continuation game, and clears fee-index rounding carry. PoolAccountingCheckpoint , including for repeated financial values authorizeChildPool(pool) SecurityPoolForker only This parent pool is already authorized; candidate reports this share token; candidate universe has no different canonical pool. No pool-lifecycle guard. Asks the lineage share token to establish pool as the canonical authorized pool for its universe; reauthorizing the same pool is a no-op. AuthorizationUpdated only on first authorization; no event when already authorized transferEth(receiver, amountAttoEth) SecurityPoolForker only Fee liabilities are covered; amountAttoEth fits both unreserved pool ETH and tracked settlement collateral; receiver accepts the ETH call, including zero value. Reduces tracked settlement collateral by amountAttoEth , checkpoints the reconciliation, and calls receiver with that ETH. At zero amount it reduces no settlement collateral but still emits the checkpoint and performs a zero-value call; callback rejection rolls back the transaction and checkpoint. PoolAccountingCheckpoint , including at zero amount; no dedicated ETH-transfer event assignFinalizedAuctionFees(vault, amountAttoRep, auctionFeeIndexAtFinalization) SecurityPoolForker only Despite its name, amountAttoRep is the claimed underwriting commitment in attoETH: the pool uses it as the fee weight and subtracts it from its uncheckpointed fee-eligible commitment. The supplied finalization index does not exceed the current fee index ( Fee index ); the forker credit workflow has already checkpointed the vault and added the claimed underwriting commitment. Assigns to the claiming vault the fees its auctioned underwriting commitment accrued from Truth Auction finalization through the current fee index, combines fractional carry with the vault remainder, and removes whole assigned fees from the unallocated reserve. The ownership was already included in the fee denominator and total ownership at finalization. This call preserves aggregate fees and settlement collateral; after every eligible ownership is reconciled on a forked pool, a subsequent permissionless updateVaultFees checkpoint returns any reserve that no vault can individually claim to settlement collateral. VaultAccountingCheckpoint and auction-claim PoolAccountingCheckpoint ; the calling forker emits ClaimAuctionProceeds only after the broader credit workflow completes Direct ETH transfer to receive() Forker, this pool's Truth Auction, or parent pool only ( Bad ETH sender ) Sender is one of the three authorized protocol addresses. Forced ETH bypasses this ordinary-call guard. Accepts protocol-routed ETH used by migration and auction settlement. Forced ETH remains raw, unaccounted surplus rather than settlement collateral or fees. EthReceived identifies the authorized sender and amount received; forced ETH bypasses receive() and emits no such event","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"retention-rate-and-annualized-fee","heading":"Retention rate and annualized fee","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"SecurityPoolUtils.calculateRetentionRate returns a per-second retention factor scaled by PRICE_PRECISION ( 1e18 ). It equals MAX_RETENTION_RATE at zero utilization, declines linearly until utilization reaches RETENTION_RATE_DIP (80% of minting capacity, which is total underwriting commitments outside an escalation game), and stays at MIN_RETENTION_RATE above that. Zero minting capacity selects MAX_RETENTION_RATE . MAX_RETENTION_RATE = 999_999_996_848_000_000 , about a 9.5% yearly fee. MIN_RETENTION_RATE = 999_999_977_880_000_000 , about a 50.2% yearly fee. Clients annualize a retention rate for display as follows; the contract never computes this value. annualFee = 1 − ( retentionRate PRICE_PRECISION ) SECONDS_PER_YEAR","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"liquidation-transfer-rounding","heading":"Liquidation transfer rounding","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"A liquidation request bounds the underwriting commitment transferred, capped by the target’s underwriting commitment. The nominal REP award includes LIQUIDATION_REP_BONUS_BPS = 500 (5%). REP and backing units round upward before the award is capped at available units. The receiver is checked against its entire resulting underwriting commitment and backing-unit position. Total underwriting commitments remain constant, including at zero settlement collateral. Target claims and earned fees remain with their owners. No liquidation writes off a commitment. An untransferred residual stays visible and continues earning fees. A fully backed receiver can accept the target’s entire underwriting commitment even when the nominal REP award is not fully funded. Partial transfers reserve available target REP for the minimum balance, and the remaining commitment must be zero or meet the commitment floor.","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["fork","migration","child pool","auction"],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Freezes parent pools, creates selected child pools, migrates vault and escalation state, and settles collateral-repair Truth Auctions . SecurityPoolForker source contract","title":"SecurityPoolForker","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Use zoltar , forkData , getUnassignedPosition , isEscalationDepositClaimedDirectly , getEscalationDepositId , getDirectlyClaimedEscalationPrincipal , isEscalationWinnerHaircutPaidByFork , getEscalationMigrationEntitlementStatus , getOwnForkRepBuckets , getOwnForkMigrationStatus , getMigrationProxyAddress , getQuestionOutcome , attoRepToBackingUnits , and backingUnitsToAttoRep to reconstruct fork progress and preview migration conversions. forkData includes cumulative migrated REP and the fork-activation timestamp. getUnassignedPosition returns pending REP backing units, underwriting commitment, raw auction bad debt, that debt’s generation, and the auction-finalization fee index; consumers count the debt only while its generation equals the pool snapshot’s current badDebtGeneration .","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"child-game-trust-boundary","heading":"Child-game trust boundary","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Fork entrypoints and child setup may receive contracts through unauthenticated pool lineages. External-universe initiation requires the supplied pool to be authorized by its declared share token, but that relationship alone does not prove factory registration; own-game initiation does not perform that authorization check. Canonicality comes from the configured SecurityPoolFactory registry. A game relationship check is point-in-time: the reported nonzero game address must return the supplied pool or child from securityPool() when validated. This does not prove that an arbitrary game getter is immutable or that the address was factory-deployed. Child setup captures one reported game address, validates it before privileged use, and reuses that exact address for continuation backing and escrow work. When unresolved escalation requires a continuation and setup initially reports no game, initialization creates one; the forker then captures and validates it before continuation use. Combined vault migration passes the captured child/game pair into unresolved cleanup without reading the child getter again. Truth Auction completion performs a fresh point-in-time validation of the game reported then before checking continuation readiness. Genuine factory-deployed EscalationGame instances store their pool immutably, but safety on unauthenticated paths does not assume arbitrary contracts do.","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. claimForkedEscalationDeposits and migrateVaultWithUnresolvedEscalation revert without reason data when one of the prerequisites marked \"no reason data\" fails; the forker omits those reason strings to stay within the contract code-size limits. Transaction Caller Main prerequisites State or asset effect Primary signals initiateSecurityPoolFork(securityPool) Anyone Pool operational with no inherited fixed outcome; the pool is authorized by its declared share token; its universe already forked; pool not already PoolForked ; if an escalation game exists, it reports the supplied pool from securityPool() when validated and the universe fork occurred before that game settled. Declared-token authorization is not configured-factory registration; see the child-game trust boundary . Freezes the supplied pool after an external universe fork, drains its pool and game REP, and records a migration snapshot keyed by that address. The snapshot is canonical only when the supplied pool is already registered by the configured SecurityPoolFactory . SecurityPoolForkSnapshot and ParentRepLocked ; additionally DisputeStakedRepDrainedAtFork when unresolved escalation exists forkZoltarWithOwnEscalationGame(securityPool) Anyone Pool operational with no inherited fixed outcome; its escalation game reports the supplied pool from securityPool() when validated and canTriggerOwnFork() is true because it recorded a local non-decision or inherited a threshold tie without a game-level fixed outcome ( Need game ); pool not already PoolForked ( Forked ) and Operational ( Inactive ); universe not already forked; the pool and game REP released to the forker reaches the Zoltar fork threshold ( Fork threshold not reached ). The game-local predicate does not bypass the pool guard. Unlike external-universe initiation, this entrypoint does not require declared-share-token authorization; neither path authenticates the supplied address against the configured pool factory. See the child-game trust boundary . Uses the supplied pool game's non-decision to fork Zoltar, freezes that pool, and records own-fork REP buckets and snapshot state keyed by its address. The snapshot is canonical only when the supplied pool is already registered by the configured SecurityPoolFactory . SecurityPoolForkSnapshot , ParentRepLocked , and Zoltar fork events; additionally DisputeStakedRepDrainedAtFork when unresolved escalation exists migrateRepToZoltar(securityPool, outcomeIndices) Anyone Migration proxy exists and the pool is PoolForked . Only a positive migration amount with at least one selected outcome checks the eight-week window, existing child ForkMigration state, outcome validity, and cumulative split bound. A zero amount skips those checks even when outcome values are supplied. For a positive migration amount and nonempty list, ensures that the forker's recorded pool migration amount has been split into each selected child REP branch. A zero migration amount or empty list returns after the proxy and pool-state guards without per-outcome validation or events. MigrationRepSplit and ChildRepSplit when a selected branch requires a new split; no event for a zero amount, empty list, or already-satisfied branch createChildUniverse(securityPool, outcomeIndex) Anyone Parent in migration window; selected fork outcome is well formed; child pool is not already deployed. The returned auction is nonzero, deployed, and has never been trusted by this forker; the child's fork-data slot is unused; and the child reports the expected parent, universe, source factory, forker, and auction. The selected child's reported nonzero escalation game passes the child-game trust boundary . These relationship checks do not independently prove configured-factory registration. Loads an already deployed child universe and REP token or deploys them when absent, then lazily deploys the selected child pool, coordinator, and auction; authorizes and links the child; captures and validates the child's escalation game; and initializes any continuation snapshot and materializes or sweeps child backing through that validated game. DeployChild only when child REP was absent; always SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , ChildPoolLinked , and TotalRepBackingUnitsSet ; AwaitingForkContinuationSet , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , MigrationRepSplit , ChildDisputeStakedRepMaterialized , and PoolHeldRepSweptToChild as continuation and backing state requires migrateVault(securityPool, outcomeIndex) Vault owner for their non-escrowed position Migration window open; the selected child's reported nonzero escalation game passes the child-game trust boundary . The optional unresolved parent escalation-deposit accounting cleanup wrapper calls this function first to migrate transferable vault state. Converts the caller's parent REP backing-unit claim to REP at the fork snapshot and credits that REP amount as child-local backing units; transfers the underwriting commitment and any tracked vault bad debt into one child pool; checkpoints but retains claimable fees in the parent vault; and separately routes proportional pool-level settlement collateral while preserving aggregate bad debt. The underwriting commitment migrates separately from REP backing. Repeat calls can have no additional REP backing units, underwriting commitment, or vault bad debt to move. VaultBadDebtMigrated and VaultMigrationCheckpoint migrateVaultWithUnresolvedEscalation(securityPool, vault, childOutcomeIndex) The named vault owner The migrateVault prerequisites. No reason data: caller equals vault ; migration window open; the fork recorded unresolved escalation ( unresolvedEscalationAtFork ); selected child not already recorded for this vault's cleanup; the selected child has an escalation game. First runs migrateVault(securityPool, childOutcomeIndex) for the caller, with that row's effects, and keeps the child and the validated escalation game that call captured, without reading the child's game again. It then clears that vault's unresolved parent escalation-deposit accounting in constant-size work and records it; the cleanup neither funds dispute-staked REP backing nor authorizes carried proofs. The migrateVault signals; EscalationMigrationEntitlementInitialized on the first cleanup for the vault; EscalationMigrationEntitlementMaterialized for the selected child claimForkedEscalationDeposits(securityPool, vault, outcomeIndex, depositIndexes) The named vault owner ( Vault ) Caller equals vault . No reason data: unresolved escalation existed when the pool initiated its own fork and the parent game still satisfies canTriggerOwnFork() by having either a local non-decision or an inherited threshold tie without a fixed outcome; the selected child remains in ForkMigration , is inside the eight-week claim window, and has a continuation game; every listed deposit commits vault as its immutable depositor. The selected child can be created or loaded and its game passes the child-game trust boundary . A nonempty list additionally requires the matching winning outcome and unclaimed deposit identities. First gets or lazily deploys the selected child universe, REP token, pool, coordinator, and auction, then captures and validates the child's escalation game and uses that same game for continuation backing and escrow payment. A nonempty list claims winning own-fork parent deposits and records their stable identities against descendant replay. An empty list still performs child setup and emits a zero-valued claim summary. DeployChild , SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , ChildPoolLinked , TotalRepBackingUnitsSet , AwaitingForkContinuationSet , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , MigrationRepSplit , ChildDisputeStakedRepMaterialized , and PoolHeldRepSweptToChild as setup requires; per claimed deposit, CarryDepositConsumed and ClaimDeposit ; escrow record/export events when REP is paid; always ClaimForkedEscalationDepositsToWallet , including for an empty list startTruthAuction(securityPool) Anyone Child migration window ended; pool is in fork migration; required child REP is available. If unresolved escalation existed at fork, any game reported during immediate completion passes the child-game trust boundary . Copies the frozen parent's remaining economic claim supply into the child, closes migration accounting, and either reopens a fully backed child or starts its repair auction. ShareTokenSupplySet , then TruthAuctionStarted when an auction starts; immediate no-auction completion instead emits TruthAuctionFinalized , pool accounting checkpoints, and ForkContinuationResumed for an unresolved continuation finalizeTruthAuction(securityPool) Anyone msg.value is zero ( No repair ETH ); the Truth Auction started and its one-week window has passed ( Auction open ). Actual child ETH covers the installed settlement collateral plus accrued fee liabilities. Installing these inherited liabilities does not require current REP backing. If unresolved escalation existed at fork, the game reported at completion passes the child-game trust boundary . Finalizes the ended auction, accounts migration-routed settlement collateral plus accepted bid ETH, and records every unmigrated REP backing unit, commitment unit, and the unmigrated remainder of the parent’s fork-time bad debt in an explicit nonwithdrawable unassigned position. It activates the child and saves the fee index. For positive existing-owner REP residue, total backing units are P × H / (H − Q), rounded up to a whole unit, where P is fork-time pool-held REP for all existing owners including unmigrated vault owners, H is finalization pool-held REP including sold escrow REP, and Q is purchased REP. The bidder backing-unit budget is total units minus P. If H − Q is zero, bidder units use H × PRICE_PRECISION (1e18) while migrated units remain in the total. Underwriting commitment has a separate budget. Positive-purchase auction ownership becomes fee eligible immediately; after a zero-purchase auction, the unassigned underwriting commitment remains outside fee eligibility. TruthAuctionFinalized , auction AuctionFinalized , and pool accounting checkpoints; TruthAuctionHaircutApplied when purchased REP removes a positive escalation allocation; ForkContinuationResumed for an unresolved continuation settleAuctionBids(securityPool, vault, claimTickIndices, refundTickIndices) Anyone on behalf of the named bidder vault At least one index ( Need action ). Before finalization the claim list must be empty ( Not final ) and the refund indexes must satisfy the refundLosingBidsFor prerequisites. After finalization, the claimAuctionProceeds prerequisites apply to the combined list. Before finalization, refunds the listed provably losing bids through the auction refundLosingBidsFor . After finalization, appends the refund list to the claim list and performs the claimAuctionProceeds settlement on the combined list. Before finalization, auction BidSettled per refunded bid and one aggregate EthRefundCredited when total credited ETH is positive. After finalization, the claimAuctionProceeds signals takeOverUnassignedCommitment(securityPool, maximumCommitmentAttoEth) Receiving vault owner Positive residual commitment within the caller’s explicit maximum; no auction purchases; fresh price; operational, unforked pool; receiver fully backs its entire resulting underwriting commitment. Sold entitlements are never available for takeover. Assigns all residual ETH commitment, unassigned REP backing, and unclaimed auctioned bad debt from a finalized zero-purchase auction to the caller; the bad debt is assigned only while the recorded auction bad-debt generation is current. Conserves total commitments and backing units. Preserves earned fees and starts recovered fee rights at the takeover checkpoint. UnassignedCommitmentTakenOver and vault/pool accounting checkpoints claimAuctionProceeds(securityPool, vault, tickIndices) Anyone on behalf of the named bidder vault Auction finalized ( Not final ). A nonempty list additionally requires every index to belong to the named vault owner and remain unsettled. For a nonempty list, withdraws finalized bid settlements and transfers each claim's proportional REP backing units, underwriting commitment, and finalization-to-claim fees from the unassigned position to the bidder vault. Its bad-debt share transfers only while the auction's recorded debt generation is still current; after those collateral claims are exhausted, the old debt expires while raw claimed-auction counters continue to settle deterministically. Commitment and bad-debt division dust follows each bid's deterministic cumulative ETH position, so claim order cannot change individual or aggregate settlement. The transfer does not change total underwriting commitment, fee eligibility, active open interest, total bad debt, retention, or aggregate accrued fees. A winning dust bid can receive underwriting commitment when its REP allocation rounds to zero. The call's aggregate positive refund is credited to the named bidder's pull-payment balance without calling recipient code. For an empty list, the wrapper exits after the finalization guard without validating bids or the named beneficiary, changing state, or emitting events. For processed bids, underlying auction BidSettled ; one aggregate EthRefundCredited per call when total credited ETH is positive; ClaimAuctionProceeds when REP backing, underwriting commitment, or raw auction bad-debt settlement advances. Its cumulative claimed and total auctioned bad-debt fields are raw counters; effective vault debt still requires the recorded auction generation to match the pool’s current generation; no event for an empty list initializeChildForkedEscalationGameIfNeeded(parent, child, childEscalationGame) This SecurityPoolForker contract only ( Only self ), through its migration delegate callback External caller is the forker itself, so parent and child come from its own migration path; a supplied nonzero game passes the child-game trust boundary . Allows delegated migration code to initialize a child continuation while preserving the forker as the authoritative caller and the already captured child-game identity. When unresolved escalation requires a continuation and no game existed, it captures and validates the game created by initialization before any continuation use. EscalationGameSet and GameContinuedFromFork when a continuation game is created; ForkCarryCheckpoint when the carry snapshot is installed; ForkContinuationResumed and AwaitingForkContinuationSet only when the child is already operational Direct ETH transfer to receive() A child-pool Truth Auction trusted by this forker during ChildPoolLinked ( Only trusted auction ) trustedAuctionAddresses[msg.sender] was set when the forker linked the child and emitted ChildPoolLinked ; configured-factory registration determines whether that lineage is canonical. Accepts auction ETH during forker-controlled auction finalization. No dedicated receive event; auction AuctionFinalized is followed by forker TruthAuctionFinalized and pool accounting checkpoints","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["escalation","dispute","deposit","non-decision"],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Escrows outcome REP, raises the running resolution cost, detects non-decision , and settles local or carried deposits. EscalationGame source contract","title":"EscalationGame","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Base getters are securityPool , repToken , activationTime , nonDecisionThresholdAttoRep , startBondAttoRep , nonDecisionTimestamp , nonDecisionState , forkContinuation , forkElapsedAtStart , forkResumedAt , fixedQuestionOutcome , nodes , disputeStakedRepByVaultAttoRep , totalDisputeStakedAttoRep , truthAuctionRepBeforeAttoRep , and truthAuctionRepRemainingAttoRep . The fallback forwards every selector other than the two signed deposits to EscalationGameClaimDelegate , which provides the reads rootClaimSourceGame , getInheritedClaimAllocation , and getUnresolvedClaimInterval . The allocation read returns source principal, retained principal, reward-interval length, and the cumulative reward endpoint after per-generation auction rounding. The reward interval is the deposit’s range within its outcome’s cumulative deposits: its start is the returned endpoint minus the returned length. It determines which portion enters the reward calculation; the length is not a payable reward. Exported principal intervals compact consumed prefixes, while reward positions remain unshifted by prior claims. Allocations within a game stay fixed in every claim order. disputeStakedRepByVaultAttoRep is locally attributed current-game escrow used for health; inherited carry remains aggregate commitment state until proof settlement. Use previewDepositOnOutcome , computeIterativeAttritionCostAttoRep , computeTimeSinceStartFromAttritionCostAttoRep , totalCostAttoRep , getEscalationGameEndDate , getQuestionResolution , getFinalQuestionResolution , hasReachedNonDecision , canTriggerOwnFork , getBindingCapitalAttoRep , getOutcomeBalancesAttoRep , getDepositsByOutcome , getDepositsByOutcomeLength , forkCarrySnapshotInitialized , getOutcomeState , getForkCarrySnapshot , getForkCarryRoots , isForkCarryFundingComplete , getCarryLeafPageByOutcome , getProofConsumedCarriedDepositIndexesByOutcome , getLocalUnresolvedPrincipalByVaultAndOutcome , and getForkedEscrowByVaultAndOutcome for calculations, lifecycle authorization, pages, carry state, and escrow. Vault-funded deposits and ordinary withdrawals route through SecurityPool , while own-fork direct claims route through SecurityPoolForker ; after an ordinary game starts, wallet-funded deposits use depositRepOnOutcome , depositRepOnOutcomeWithPermit , or depositRepOnOutcomeWithAuthorization and mint no pool backing units.","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Rows marked \"through fallback() \" are not in the compiled ABI: the fallback forwards the two signed deposit selectors to EscalationGameDepositDelegate and every other unknown selector to EscalationGameClaimDelegate by delegatecall , and returns or reverts with the delegate output. A call restricted to the owning pool or its forker reverts without reason data for any other caller. Transaction Caller Main prerequisites State or asset effect Primary signals start(startBondAttoRep, nonDecisionThresholdAttoRep) Immutable owner, the EscalationGameFactory , only ( Only owner ), during atomic deployment Game not already started, and nonDecisionThresholdAttoRep > startBondAttoRep > 0 ( Invalid game start ). Initializes a local game and sets activation three days after deployment. For ordinary pool games, the factory lowers an oversized configured bond to nonDecisionThresholdAttoRep - 1 before this call. GameStarted startFromFork(startBondAttoRep, nonDecisionThresholdAttoRep, elapsedAtFork, fixedQuestionOutcome, winnerHaircutPaidByFork, forkCarryInitialBackingAttoRep) Immutable owner, the EscalationGameFactory , only ( Only owner ), during atomic continuation deployment Game not already started, and nonDecisionThresholdAttoRep > startBondAttoRep > 0 ( Invalid game start ); elapsedAtFork is at most seven weeks ( Invalid fork elapsed time ). Initializes a paused continuation with inherited elapsed time, an optional fixed matching child outcome, and immutable fork-time escalation-haircut and backing accounting. It does not start the remaining clock until resumeFromFork . GameContinuedFromFork resumeFromFork() Owning SecurityPool only ( Only pool ) Fork-continuation mode; not previously resumed; aggregate REP funding complete ( isForkCarryFundingComplete ). The game does not itself require an installed snapshot; the forker installs it during child initialization. An unrelated fork requires one-to-one backing of effective unresolved principal. For an own-fork continuation, recorded initial backing must be at least R - ⌊R / 5⌋ , where R is the sum of inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep across all three outcomes before direct-claim deductions, and 5 is the fixed Constants.MINIMUM_FORK_BURN_DIVISOR rather than the configured fork burn divisor. The live balance must cover that initial backing minus child REP already exported by valid direct pre-resume claims, scaled down by any REP applyTruthAuctionHaircut removed. Records the resume timestamp once carry funding is complete. The new deadline is max(rebasedCurveEnd, forkResumedAt + 3 days) , so even an exhausted inherited clock receives a fresh response period. After that deadline, getFinalQuestionResolution returns the fixed outcome when the continuation has one. ForkContinuationResumed applyTruthAuctionHaircut(repToRemoveAttoRep) The child pool's SecurityPoolForker only ( Only forker ) Paused fork continuation; no prior auction haircut; the requested amount is below the game's live REP balance. Transfers sold REP to the pool, proportionally reduces escrow and outcome balances, and rebases curve time. If an unfixed continuation inherited two threshold-full outcome balances and the auction REP removal leaves them below the current game threshold, ordinary pool-mediated deposit checks apply after the pool resumes the game. Fixed outcomes and local non-decisions retain their state. The game stays paused until the pool resumes it. TruthAuctionHaircutApplied and REP Transfer ; InheritedThresholdTieReopened when an unfixed inherited tie reopens depositRepOnOutcome(outcome, maximumDepositAttoRep) Any REP holder Current game is the pool's ordinary unresolved game; pool operational; universe unforked; outcome non- None ; caller allowance to this game covers the accepted REP; preview accepts a positive amount within the remaining threshold room. Transfers the accepted REP directly from the caller into dispute escrow, appends a local deposit, and records its carry leaf without minting pool backing units. REP Transfer , LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision depositRepOnOutcomeWithPermit(outcome, maximumDepositAttoRep, deadline, v, r, s) through fallback() Any child-universe REP holder The depositRepOnOutcome game, pool, and preview prerequisites; the pool universe is not genesis ( Genesis REP does not support permit ); the permit succeeds or the caller allowance to this game covers the previewed amount ( Game permit and allowance insufficient ). Calls the REP token permit for the previewed amount from the caller to this game, ignores a failed permit when the existing allowance already covers that amount, then performs the depositRepOnOutcome deposit. REP Approval when the permit succeeds, then the depositRepOnOutcome signals depositRepOnOutcomeWithAuthorization(owner, outcome, maximumDepositAttoRep, validAfter, validBefore, nonce, v, r, s) through fallback() Anyone relaying the owner's ERC-3009 signature The depositRepOnOutcome game, pool, and preview prerequisites; the pool universe is not genesis ( Genesis REP does not support authorization ); the signature authorizes the token nonce keccak256(abi.encode(nonce, operationHash, owner)) , where operationHash is keccak256(abi.encode(depositRepOnOutcomeWithAuthorization.selector, owner, securityPool, universeId, questionId, outcome, maximumDepositAttoRep, previewedAmount)) . Pulls the previewed amount from owner to this game through the REP token receiveWithAuthorization and records the deposit for owner . REP AuthorizationUsed and Transfer , LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision recordDepositFromSecurityPool(depositor, outcome, amountAttoRep, expectedCumulativeAttoRep) Owning SecurityPool only ( Only pool ) Explicit non-decision state is None ; game unresolved; valid outcome; preview and accepted cumulative amount match; room remains below threshold. Appends an accepted local deposit, updates outcome and vault escrow, and records its carry leaf. LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision withdrawDeposit(depositIndex, outcome) , the uint256 overload Owning SecurityPool only ( Only pool ) Explicit non-decision state is None ; non- None supplied outcome; game final; game and pool final outcomes match; valid unsettled local deposit index. Consumes one local deposit after resolution. A winner pays the deposit's immutable depositor after its escalation haircut; a loser only retires its escrow accounting. CarryDepositConsumed and VaultEscrowUpdated ; for a winner, ClaimDeposit , positive REP payout Transfer , and escalation-haircut burn signals when nonzero initializeForkCarrySnapshotWithResolutionBalances(sourceGame, snapshotId, snapshotPeaksInput, snapshotLeafCountsInput, snapshotCarryTotalsAttoRep, snapshotResolutionBalancesAttoRep, snapshotNullifierRoots) Owning SecurityPool only Fork-continuation mode; no prior snapshot; each leaf count fits the MMR; supplied nonzero snapshot ID equals the hash of the normalized data. Installs the immutable inherited peaks, leaf counts, carry totals, resolution balances, and normalized nullifier roots; zero snapshot ID selects the computed ID. Two or more threshold-full inherited balances set nonDecisionState to InheritedThresholdTie without creating a local timestamp. ForkCarryCheckpoint ; additionally InheritedThresholdTie when the installed balances meet the non-decision threshold initializeForkClaimCheckpoint(sourceGame) through fallback() Owning SecurityPool only ( Only pool ) sourceGame equals the source game recorded by the installed carry snapshot ( Claim source ); no Truth Auction haircut has been applied ( Haircut applied ). Records the root claim source game: the value sourceGame reports from rootClaimSourceGame() , or sourceGame itself when that value is zero. The game runs the same step internally while installing a carry snapshot with a nonzero source game, and no pool function calls this selector. No event claimDepositForWinning(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Non- None supplied outcome and valid unsettled local deposit with sufficient escrow. This entrypoint itself does not check final resolution or that the supplied outcome won; its trusted caller selects that path. Consumes a selected local deposit as a winner, consumes its vault escrow, burns the computed escalation haircut when nonzero, and transfers the remaining positive REP payout to the deposit's immutable depositor. CarryDepositConsumed , VaultEscrowUpdated , ClaimDeposit with transferredRep = true ; REP payout Transfer and escalation-haircut burn signals only when their amounts are positive claimDepositForWinningWithoutTransfer(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Valid in-range supplied outcome and unsettled local deposit with sufficient escrow. Unlike the transferring form, it has no explicit non- None guard; neither form checks final resolution or that the outcome won. Consumes a selected local deposit and its vault escrow. The depositor's raw escrow backing decreases by the inverse-retention claim units corresponding to the deposit's original principal: the principal itself with no local auction checkpoint, or ⌈originalPrincipal × truthAuctionRepBeforeAttoRep / truthAuctionRepRemainingAttoRep⌉ after a local auction REP removal. Other unconsumed deposits by the same depositor remain backed. The game returns the computed winner amount to the trusted caller but deliberately neither transfers REP nor burns the computed escalation haircut. CarryDepositConsumed , VaultEscrowUpdated , and ClaimDeposit with transferredRep = false ; no REP transfer or escalation-haircut burn exportUnresolvedDeposit(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Non- None outcome and a valid unsettled local deposit. Final resolution is not required. Returns deposit identity and amount to the trusted caller while consuming the local deposit from unresolved/escrow accounting without transferring REP. CarryDepositConsumed and VaultEscrowUpdated ; no ClaimDeposit or REP transfer withdrawDeposit(proof, outcome) , the CarriedDepositProof overload Owning SecurityPool or its SecurityPoolForker Non- None supplied outcome; game final and matching the pool final outcome; supplied outcome is the winner; parent deposit was not directly claimed; valid unconsumed Merkle/nullifier proof. Consumes an inherited proof, transfers any positive winning payout, and burns the positive escalation haircut unless the fork already paid it. CarryDepositConsumed and ClaimDeposit with transferredRep = true ; REP payout Transfer and escalation-haircut burn signals only when positive exportVaultUnresolvedTotals(vault, repReceiver) Owning SecurityPool or its SecurityPoolForker vault is nonzero and has not exported before. There is no explicit nonzero-receiver guard: a zero receiver succeeds when the total is zero but the token rejects it when a positive transfer is attempted. Marks the vault's local unresolved totals exported exactly once, clears each outcome amount, consumes aggregate unresolved and escrow accounting when positive, and transfers the positive total to repReceiver . Always VaultUnresolvedTotalsExported , including when every amount is zero; VaultEscrowUpdated and REP Transfer only for a positive total exportVaultUnresolvedTotalsWithoutTransfer(vault) Owning SecurityPool or its SecurityPoolForker vault is nonzero and has not exported before. Marks the vault's local unresolved totals exported exactly once, clears each outcome amount, and consumes aggregate unresolved and escrow accounting when positive, but leaves token movement to its caller. Always VaultUnresolvedTotalsExported with transferredRep = false , including when every amount is zero; VaultEscrowUpdated only for a positive total; no REP transfer drainAllRep(receiver) Owning SecurityPool only ( Only pool ) receiver is nonzero; no positive-balance requirement. The protocol reaches this call from the owning pool after activateForkMode enters PoolForked . Transfers the game's full REP balance to receiver . A zero balance returns zero without a transfer or event. REP Transfer for a positive balance; no event at zero balance recordForkedEscrowForOutcome(depositor, outcome, sourcePrincipalAttoRep, childRepAmountAttoRep) Owning SecurityPool or its SecurityPoolForker Outcome is not None ; depositor is nonzero. Source principal and child REP may independently be zero; when both are zero, the call is a no-op. Accumulates source principal and child REP escrow for the depositor and outcome. The depositor remains the immutable payout owner; inherited claims remain in the carry commitment and are not copied into child-local ownership state. When both amounts are zero, returns without changing state or emitting an event. ForkedEscrowRecorded for a nonzero record; no event when both amounts are zero exportForkedEscrowByOutcome(vault, repReceiver) Owning SecurityPool or its SecurityPoolForker vault and repReceiver are nonzero. Marks every remaining per-outcome escrow amount exported and transfers its positive child REP. When all outcomes were already empty or exported, returns zero arrays without state change, token transfer, or event. ForkedEscrowExported when any source principal or child REP remains; VaultEscrowUpdated and REP Transfer when positive child REP is transferred; no event for an already-empty export exportForkedEscrowByOutcomeWithoutTransfer(vault) Owning SecurityPool or its SecurityPoolForker vault is nonzero. Marks every remaining per-outcome escrow amount exported without transferring child REP. When all outcomes were already empty or exported, returns zero arrays without state change or event. ForkedEscrowExported with transferredRep = false when any source principal or child REP remains; VaultEscrowUpdated when positive child REP remains; no REP transfer; no event for an already-empty export sweepResidualRepToSecurityPool() Anyone Final outcome; no unresolved principal; no vault escrow; positive residual balance. Returns ordinary-game residual REP to the owning pool. Burns fork-continuation residual so pre-child capital cannot accrue to late or nonexistent child owners. ResidualRepSweptToSecurityPool for an ordinary game; ForkContinuationResidualRepBurned for a fork continuation","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"required-support-threshold","heading":"Required support threshold","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"The contract waits ACTIVATION_DELAY (3 days) after start() before the escalation clock begins. From day 3 the cumulative binding-capital requirement rises from the configured start bond S to the non-decision threshold T over the 49-day ESCALATION_TIME_LENGTH , reaching T on day 52. The contract evaluates a fixed-point curve; this expression is its readable idealization. A ( d ) = 0 for 0 ≤ d ≤ 3 = S × exp ( ln ( T S ) × d − 3 49 ) for 3 < d < 52 = T for d ≥ 52","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"winning-deposit-payout","heading":"Winning-deposit payout","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Binding capital is the median outcome balance at settlement; no outcome balance can exceed the non-decision threshold. The reward-eligible cap is binding capital plus binding capital divided by EXCESS_REWARD_WINDOW_DIVISOR (2), so only the portion of winning deposits up to 1.5 × binding capital participates in the bonus. Of the binding capital, 3 / 5 funds the reward pool and 2 / 5 funds the escalation-haircut pool; both are shared pro rata across the reward-eligible principal, which is the smaller of the winning outcome balance and that cap. Let binding capital be 10 REP , so the reward-eligible cap is 15 REP , the reward pool is 6 REP , and the escalation-haircut pool is 4 REP . If the winning outcome holds 15 REP and one deposit contributed 5 REP inside the eligible range: Principal returned: 5 REP . Bonus: 5 × 6 / 15 = 2 REP . Winning payout: 5 + 2 = 7 REP . Haircut burned: 5 × 4 / 15 = 1.333333333333333333 REP at attoREP precision. A winning deposit position above 15 REP returns its principal without a bonus. When Zoltar's fork threshold at settlement is below the game's non-decision threshold, the whole withdrawal is scaled by their ratio. If this game's non-decision threshold were 20 REP and the fork threshold 16 REP , the 7 REP payout becomes 7 × 16 / 20 = 5.6 REP , rounded down to attoREP. Fork scaling can therefore reduce the final transfer below principal.","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["liquidation","approval","receiver","operator"],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Stores coordinator-local, bounded authorization for a receiver vault to accept liquidation debt from an exact operator. LiquidationApprovalRegistry source contract","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Use coordinator to identify the validating coordinator and implied security pool. LIQUIDATION_APPROVAL_TYPEHASH , DOMAIN_SEPARATOR , and liquidationApprovalDigest define the chain- and registry-bound EIP-712 message. getLiquidationApproval reports parameters plus available, reserved, consumed, and revoked state; minimumLiquidationApprovalNonce reports receiver invalidation state; liquidationReservations and minimumHealthFactorBps expose operation reservation state and its execution-time health floor.","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals initialize(coordinator) Anyone while the registry remains uninitialized; normal factory deployment initializes the clone atomically Coordinator is nonzero and the registry has not been initialized. Binds this registry clone to one coordinator and therefore one security pool. RegistryInitialized identifies the configured coordinator. setLiquidationApproval(params) The receiver vault named by params Correct local pool; nonzero receiver and operator; positive cumulative and per-operation limits with per-operation no greater than cumulative; health factor at least 10,000 BPS; live ordered validity window; unused, non-invalidated nonce. Installs explicit onchain bounded approval state and consumes the receiver-scoped nonce. LiquidationApprovalSet permitLiquidationApproval(params, signature) Anyone relaying the receiver vault signature Signature is valid for params.receiverVault ; the chain ID, registry address, stable name/version, pool, receiver, operator, target scope, limits, health factor, window, and nonce are bound by the digest; direct-install validation rules also pass. Validates an EIP-712 EOA or ERC-1271 signature immediately, installs explicit approval state, and consumes the receiver-scoped nonce. LiquidationApprovalSet revokeLiquidationApproval(approvalId) Approval receiver vault only Approval exists and is not already revoked. Prevents new reservations while leaving reservations already attached to staged operations intact. LiquidationApprovalRevoked with available, reserved, and consumed totals invalidateLiquidationApprovalNonce(newNonce) Receiver vault invalidating its own older nonce range New nonce is greater than the receiver current minimum. Raises the minimum nonce accepted for new approval installation or reservation. LiquidationApprovalNonceInvalidated reserve(operationId, approvalId, receiverVault, targetVault, operator, requestedDebtAttoEth, snapshotTargetDebtAttoEth, latestExecutionTimestamp) Bound coordinator only ( Only coordinator ) Approval matches local pool, receiver, exact operator, and exact or wildcard target; it is active, unrevoked, non-invalidated, valid through latest execution, and has positive reservable quota. Moves quota from available to pending reserved at staging, bounded by requested debt, target snapshot debt, per-operation limit, and available cumulative quota. LiquidationApprovalReserved release(operationId) Bound coordinator only ( Only coordinator ) Coordinator terminal cleanup path. Returns an unsettled delegated reservation to available quota. A missing, self-route, or already settled reservation is a no-op. LiquidationApprovalReleased when quota is returned consume(operationId, debtMovedAttoEth) Bound coordinator only ( Only coordinator ) For a delegated reservation, it is unsettled and moved debt does not exceed reserved debt. A self route is a no-op. Permanently consumes exactly moved debt, releases unused reservation, and settles the reservation once. LiquidationApprovalConsumed","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"minimum-post-liquidation-health-factor","heading":"Minimum post-liquidation health factor","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"minPostLiquidationHealthFactorBps is applied to both vault-health branches at execution. 10,000 ( BPS_DENOMINATOR ) means exactly the protocol minimum; a larger value multiplies both REP requirements by that ratio, so 12,000 requires 1.2 times each requirement, rounded up, after the receiver accepts the position. The factor is checked against live post-liquidation state, not the queue-time preview.","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","price","coordinator","staged operation"],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Obtains a fresh REP-per-ETH price and coordinates withdrawals, delegated liquidation routing, approval reservations, and terminal cleanup. OpenOraclePriceCoordinator source contract","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Configuration getters are MAX_PENDING_SETTLEMENT_OPERATIONS , SETTLEMENT_GAS_OVERHEAD , OPEN_INTEREST_DIVIDER , reputationToken , securityPool , openOracle , weth , liquidationApprovalRegistry , vaultOperations (the VaultOperations executor this coordinator deploys in its constructor), gasConsumedOpenOracleReportPrice , gasConsumedSettlement , gasUnitsForOneDispute , initialReportPriorityFeeAttoEthPerGas , targetPriceErrorForDispute , openOracleSecurityMultiplierBps , settlementTime , disputeDelay , protocolFee , feePercentage , multiplier , timeType , trackDisputes , protocolFeeRecipient , escalationHaltMultiplierBps , maxSettlementBaseFeeMultiplierBps , and minLiquidationPriceDistanceBps . Current report and operation getters are pendingReportId , pendingReportSponsor , pendingOperationSlotId , lastSettlementTimestamp , lastPrice , pendingReportMaxSettlementBaseFeeAttoEthPerGas , stagedOperationCounter , and stagedOperations . lastSettlementTimestamp records when the accepted final report reached settlement eligibility (report timestamp plus settlementTime ), not when settle was called, and isPriceValid measures freshness from it: it is true while lastPrice > 0 , lastSettlementTimestamp is nonzero, and lastSettlementTimestamp + 5 minutes > block.timestamp . On chain ID 11155111 (Sepolia) the window is 1 hour instead of 5 minutes. Use isPriceValid , minimumToken1ReportAttoEth , getRequestPriceCostAttoEth , getQueuedOperationCostAttoEth , getSettlementCallbackGasLimit , getPendingOperationSlot , getActiveStagedOperationCount , getActiveStagedOperations , getPendingSettlementWork , getPendingSettlementOperationCount , and getPendingSettlementOperationIds for derived or paged state.","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Report and staged-operation liveness depends on A16 timely inclusion , A17 corrector capability , A18 independent correction incentive , A19 observable correctable price , and A06 lifecycle executors . When lastPrice is zero, the official client currently needs an offchain market quote to propose the first report; quote availability is a client limitation rather than a protocol security assumption. Proposals copied from a nonzero cached price do not use that quote path.","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals requestPriceIfNeededAndStageLiquidation(targetVault, receiverVault, requestedDebtAttoEth, approvalId, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) Liquidation operator; a delegated receiver must have approved this exact operator Receiver differs from target; delegated approval matches pool, receiver, operator, and target scope, has available cumulative and per-operation quota, and remains valid through latest execution. Stages explicit operator, receiver, target backing, and target underwriting commitment and reserves bounded receiver quota before any oracle work. The queue event retains the full historical observation for indexing, while live execution inputs are not duplicated in persistent operation storage. The self-receiving operator path uses a zero approval ID. LiquidationRouteStaged ; LiquidationApprovalReserved on a delegated route; staged-operation lifecycle events requestPriceIfNeededAndStageOperation(operation, targetVault, operationValue, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with funding when stale Vault owner for self withdrawal or a target change; self-receiving liquidation callers are also supported. While a report is pending, only that report sponsor may stage more operations. securityPool.isEscalationResolved() is false; valid self-target for withdrawal or underwriting-commitment change; liquidation and withdrawal require positive amounts, and a withdrawal whose previewed REP is zero reverts with Withdraw amount has no effect , while an absolute underwriting commitment may be zero to request an exit; and validForSeconds is from 1 second through 5 minutes. A committed bounty of at least getRequestPriceCostAttoEth() covered by msg.value , buffered report funding, matching REP, and token approvals are required only when this call opens a new report. The caller must accept any positive unused-ETH refund. Records the operation with operationValue in the unit of its OperationType ( 0 Liquidation , transferred commitment in attoETH; 1 WithdrawRep , withdrawal in attoREP; 2 SetVaultUnderwritingLimit , absolute underwriting commitment in attoETH), executes immediately with a fresh price; otherwise it attaches it to the pending settlement batch while that batch has room, opening a report when none is pending and the batch was empty, or leaves it active outside the batch for a later executeStagedOperation . A target change cannot supersede an active dependent bundle. Otherwise, a newly accepted target change consumes any older active target change for the same vault with success=false and Backing target superseded , freeing its settlement slot. When a report opens, the whole committed bountyAttoEth is retained as the settler reward regardless of the inclusion-block cost. If unused ETH is positive, the final caller refund uses a low-level callback; rejection rolls back the entire transaction, including any queueing, immediate execution, or newly opened report. StagedOperationQueued ; PriceRequested when this call opens a report; ExecutedStagedOperation for immediate fresh-price execution or a superseded target change; LiquidationRouteStaged for operation 0 ; authoritative CoordinatorStateCheckpoint records stageVaultOperations(owner, changeCommitment, actionCount, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) The VaultOperations executor only ( Only vault operations executor ); wallets enter through its submitVaultOperations function validForSeconds is from 1 second through 5 minutes; escalation is unresolved; a pending report belongs to the owner; a commitment change has no active preceding commitment operation. Stale-price bundles must fit the remaining weighted callback capacity and satisfy report funding when opening a report. Targets are distinct, nonzero other vaults with a positive commitment; liquidation bundles require a receiver health factor of at least 10,000 BPS. All liquidation snapshots and pool safety checks must still pass at execution, and a withdrawal whose resulting REP is zero fails with Withdraw amount has no effect . Records OperationType 3 ( VaultOperations ) with the submitting wallet as owner and report sponsor. A fresh-price bundle executes commitment changes, other-vault liquidations, and withdrawal atomically; a failure reverts the submission and its deposit. With a stale price, deposits complete immediately and dependent actions queue together. Any change to a queued liquidation target's backing units or underwriting commitment fails the whole bundle, rolling back the owner's commitment change and withdrawal. The failed bundle is consumed while its earlier deposit remains. Each action uses one of four settlement slots; the deposit uses none. StagedOperationQueued , PriceRequested when opening a report, ExecutedStagedOperation , and CoordinatorStateCheckpoint ; the executor emits VaultLiquidationStaged per target and VaultOperationsStaged before this call requestPrice(proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with report funding Anyone when no fresh price or report is pending Cached price stale; no pending report; nonzero proposed REP-per-ETH price, a committed bounty of at least getRequestPriceCostAttoEth() covered by msg.value , and funding and approvals for at least the configured priority report plus the larger of the base-fee and open-interest WETH reports, plus matching REP. Zero requested WETH uses the minimum; a larger request voluntarily increases the initial report. The caller must accept any positive excess-ETH refund. Opens and atomically funds a fresh WETH/REP report without staging a new operation, retains the whole committed bounty as the settler reward, then refunds any ETH above the bounty through a low-level caller callback. Callback rejection rolls back the report and initial position. PriceRequested and CoordinatorStateCheckpoint executeStagedOperation(operationId) Anyone Operation exists ( Staged operation unavailable ). Expired cleanup requires no valid price; a non-expired operation requires a fresh coordinator price ( Valid oracle price required ). Lifecycle failures are emitted rather than retried. Consumes an expired operation and releases its delegated reservation without requiring a valid price. Otherwise, consumes and attempts the active operation using the current fresh price. Price-report funding is independent of the operation's notional; the downstream operation applies its own protocol bounds. ExecutedStagedOperation , either LiquidationApprovalConsumed or LiquidationApprovalReleased for a delegated liquidation, and CoordinatorStateCheckpoint expireStagedOperation(operationId) Anyone Operation exists ( Staged operation unavailable ) and block.timestamp is after queuedAt + settlementTime + validForSeconds ( Staged operation active ). Permissionlessly consumes an expired operation and releases its liquidation reservation without requiring a valid oracle price. ExecutedStagedOperation , LiquidationApprovalReleased for a delegated liquidation, and CoordinatorStateCheckpoint recoverSettledPendingReport() Anyone A pending report ID exists and its stored OpenOracle storedGame(reportId).settlementTimestamp is nonzero. Clears a pending report whose normal callback path did not clear coordinator state, consumes every live operation attached to that report, and releases each delegated-liquidation reservation. Operations that were active but outside the bounded pending callback batch remain active. PendingReportRecovered , failed ExecutedStagedOperation for each live attached operation, LiquidationApprovalReleased for each attached delegated liquidation, and CoordinatorStateCheckpoint openOracleCallback(reportId, amount1, amount2, uint256, address, address) ; the last three parameters are unnamed and ignored Configured OpenOracle only ( Only OpenOracle ) Callback report matches the pending report; excessive settlement basefee, a saturated uint24 report counter, an uneconomic final history record at its recorded base fee plus configured priority fee, a stale report, or zero values reject the price after clearing pending report state. A valid settlement updates the price and auto-executes the bounded pending batch. A terminally rejected settlement consumes the pending batch and releases every liquidation reservation. PriceReported or PriceReportRejected ; operation execution events; authoritative CoordinatorStateCheckpoint records setLiquidationApprovalRegistry(registry) The PriceCoordinatorDeploymentWorker that deployed the coordinator only, invoked by OpenOraclePriceCoordinatorFactory during deployment Registry is nonzero and no registry was previously installed ( Registry setup invalid for any failed condition, including the caller). Binds the coordinator-local approval registry once. LiquidationApprovalRegistrySet identifies the configured registry. setSecurityPool(securityPool) Anyone while securityPool remains zero; normal factory deployment calls atomically Current securityPool is zero ( Security pool already set ); the argument itself is not required to be nonzero. A nonzero value binds the pool permanently. A zero value emits and checkpoints zero but leaves the setter callable. SecurityPoolFactory supplies the nonzero canonical pool in the same deployment transaction, immediately after deploying the pool. SecurityPoolSet and CoordinatorStateCheckpoint setRepEthPrice(lastPrice) Configured nonzero SecurityPool only ( Only pool ) Caller equals the configured pool. Seeds the coordinator's price value, including zero, for inherited child state. RepEthPriceSet and CoordinatorStateCheckpoint","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["vault","bundle","executor","submitVaultOperations"],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Accepts a wallet bundle of vault actions for one security pool, stores the price-dependent actions, and is the only caller that pool accepts for executor-gated vault entrypoints. VaultOperations source contract","title":"VaultOperations","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Use MAX_ACTIONS (4) for the limit on price-dependent actions in one bundle. getBundle(operationId) returns a stored bundle: owner , changeCommitment , commitmentAttoEth , withdrawAttoRep , minimumReceiverHealthFactorBps , and each liquidation targetVault and requestedDebtAttoEth with its queue-time targetBackingUnits and targetUnderwritingLimitAttoEth snapshot. previewWithdrawRep(pool, vault, amountAttoRep) returns the REP a withdrawal would send: zero for a zero request, otherwise the requested backing or the whole vault backing when the remainder would fall below minimumVaultRepDepositAttoRep . The coordinator address is a private immutable set to the deployer; each OpenOraclePriceCoordinator deploys one instance in its constructor and exposes it as vaultOperations .","title":"VaultOperations","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. The input of submitVaultOperations contains, in ABI order, depositAttoRep , changeCommitment , commitmentAttoEth , liquidations (each a targetVault and a requestedDebtAttoEth ), withdrawAttoRep , minimumReceiverHealthFactorBps , and validForSeconds . Transaction Caller Main prerequisites State or asset effect Primary signals submitVaultOperations(input, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with ETH Vault owner; the caller becomes the bundle owner No submission is already in progress ( Vault submission already active ). The bundle contains a deposit or a price-dependent action ( Choose a vault action ); a commitment change, each liquidation, and a positive withdrawal are price-dependent actions, at most four in total ( Choose one to four price actions ). With liquidations, minimumReceiverHealthFactorBps is at least 10,000 BPS ( Receiver health factor below one ); each target is nonzero and differs from the caller ( Choose another vault ), requests a positive amount ( Liquidation amount zero ), is listed once ( Duplicate liquidation target ), and has positive backing units and underwriting commitment ( Target vault has no commitment ). A deposit requires the pool depositRepToVaultFromExecutor prerequisites; price-dependent actions require the coordinator stageVaultOperations prerequisites; a deposit-only caller accepts the ETH refund ( Vault operation refund failed ). Deposits a positive depositAttoRep immediately through the pool depositRepToVaultFromExecutor . When price-dependent actions exist, stores the bundle under the next coordinator operation ID with a snapshot of each target's backing units and underwriting commitment, then forwards msg.value and the three price arguments to the coordinator stageVaultOperations , which executes the bundle at a fresh price or queues it. A deposit-only call returns operation ID zero and refunds msg.value to the caller. The pool depositRepToVault signals for a positive deposit; VaultLiquidationStaged per liquidation, then VaultOperationsStaged , when price-dependent actions exist; then the coordinator stageVaultOperations signals. A deposit-only call emits only the deposit signals execute(operationId) Bound coordinator only ( Only coordinator ) A bundle is stored for operationId ( Bundle unavailable ); a positive withdrawal previews to a positive amount ( Withdraw amount has no effect ); each pool call meets its own prerequisites. Runs the stored bundle in order: sets the owner's underwriting commitment through the pool setVaultUnderwritingLimit when the bundle changes it; performs each liquidation through the pool performLiquidation with the owner as operator and receiver and the stored target snapshot; then withdraws through the pool withdrawRepFromVault . A failed step reverts the whole call. The bundle stays stored until release . The signals of each pool call it makes; no event of its own executeSingle(operationId, operation) Bound coordinator only ( Only coordinator ) The operation type is Liquidation , WithdrawRep , SetVaultUnderwritingLimit , or VaultOperations ( Unsupported single operation ); the pool call meets its own prerequisites. Dispatches one staged coordinator operation by its OperationType . VaultOperations runs execute(operationId) and returns zero. Liquidation calls the pool performLiquidation and returns the moved commitment: a self route uses operationValue and a 10,000 BPS minimum receiver health factor, while a delegated route uses the reserved debt and the approval registry minimumHealthFactorBps(operationId) . WithdrawRep calls the pool withdrawRepFromVault and SetVaultUnderwritingLimit calls the pool setVaultUnderwritingLimit , each for the operator with operationValue . The signals of the pool call it makes; no event of its own release(operationId) Bound coordinator only ( Only coordinator ) No prerequisite beyond the caller. Deletes the stored bundle for operationId . Releasing an ID without a bundle changes nothing. No event","title":"VaultOperations","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["shares","ERC-1155","migrate","outcome"],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Stores universe-aware ERC-1155 outcome shares and materializes a holder's persistent source entitlement in selected fork branches. ShareToken source contract","title":"ShareToken","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Base and relationship getters are name , symbol , zoltar , canonicalPoolByUniverse , _balances , _supplies , and _operatorApprovals . Standard ERC-1155 reads are supportsInterface , balanceOf , totalSupply , balanceOfBatch , and isApprovedForAll ; protocol-specific reads are isAuthorized , totalSupplyForOutcome , maximumOutcomeSupply , balanceOfOutcome , balanceOfShares , getMigratedShareAmountAttoShares , getTokenId , getTokenIds , and unpackTokenId .","title":"ShareToken","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals setApprovalForAll(operator, approved) Any token account setting its own operator approval The operator differs from the caller. Sets or clears the operator's authority over all of the caller's outcome-token balances. ApprovalForAll safeTransferFrom(from, to, id, value) and safeTransferFrom(from, to, id, value, data) Share holder or approved ERC-1155 operator Caller holds the source balance or has operator approval; the source account has not materialized that token into any child branch; destination is nonzero; the source balance is sufficient; under A22 asset-recipient compatibility , a contract recipient accepts the ERC-1155 callback. Transfers one outcome-token balance without changing supply. TransferSingle safeBatchTransferFrom(from, to, ids, values) and safeBatchTransferFrom(from, to, ids, values, data) Share holder or approved ERC-1155 operator for a nonempty batch; any caller for an empty batch ID and value array lengths match. A nonempty batch also requires holder or operator authority, no listed source token that the source account has already materialized into a child branch, a nonzero destination, sufficient source balances, and, under A22 asset-recipient compatibility , an accepting ERC-1155 callback from a contract recipient; the empty-batch no-op performs none of those checks. A nonempty batch transfers each listed outcome-token balance without changing supply. Equal empty ID and value arrays return as a no-op without an event. TransferBatch for a nonempty batch; no event for an empty batch migrate(fromId, targetOutcomeIndexes) Holder of the source token ID Source universe forked; canonical source pool is Operational or PoolForked , and an Operational source has no inherited fixed outcome because auto-fork activation rejects one; positive source balance; nonempty, strictly increasing, well-formed outcomes; every target in a multi-target call already has a canonical child pool; after the branch-creation window, a single target must also already exist; at least one selected child has an unmaterialized balance; under A22 asset-recipient compatibility , a contract holder accepts onERC1155Received for every target mint. If needed, first freezes the operational source pool and records its fork snapshot. A single-target call may lazily create that child while the branch-creation window is open. It keeps and locks the holder's source entitlement, then mints each selected child-universe token ID up to the current source balance. Later source additions materialize only the unminted delta. A contract holder receives the ERC-1155 single-receiver callback for each mint; rejection rolls back the mint and preceding fork or child setup. PoolForkModeActivated , PoolAccountingCheckpoint , SecurityPoolForkSnapshot , ParentRepLocked , and optionally DisputeStakedRepDrainedAtFork when auto-forking; SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , and ChildPoolLinked when lazily deploying, plus DeployChild , ChildRepSplit , PoolHeldRepSweptToChild , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , and ChildDisputeStakedRepMaterialized as applicable; then one ERC-1155 mint TransferSingle and Migrate per materialized target on successful callbacks authorize(securityPoolCandidate) Initially authorized SecurityPoolFactory for an origin pool; an authorized parent SecurityPool for a child pool Caller is already authorized; the candidate reports this exact share token; its universe has no different canonical pool. Establishes the candidate as canonicalPoolByUniverse for its universe and adds it to the set allowed to mint, burn, and authorize descendants. Reauthorizing the same candidate is a no-op. AuthorizationUpdated on first authorization; no event when the same candidate is already authorized mintCompleteSets(universeId, account, amountAttoShares) An authorized SecurityPool Caller is authorized; account is nonzero; amountAttoShares is positive; under A22 asset-recipient compatibility , a contract account accepts onERC1155BatchReceived . Mints amountAttoShares each of Invalid, Yes, and No to account , then invokes its ERC-1155 batch-receiver callback when it is a contract. Rejection rolls back the mint and the authorized pool's surrounding transaction. TransferBatch on a successful callback burnCompleteSets(universeId, owner, amountAttoShares) An authorized SecurityPool Caller is authorized; owner is nonzero and has at least amountAttoShares of every outcome. Burns amountAttoShares each of Invalid, Yes, and No from owner ; global outcome supplies may differ. TransferBatch burnTokenIdAndGetRemainingSupply(tokenId, owner) An authorized SecurityPool owner is nonzero; caller is authorized. Burns owner 's full balance of tokenId and returns the burned amount and that token ID's remaining supply. TransferSingle , including when the burned balance is zero","title":"ShareToken","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["truth auction","bids","clearing","settlement"],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Collects ETH bids under ETH-raise and REP-sale caps, computes one clearing result, and supports paged settlement. AVL, cumulative-allocation, and refund-prefix mechanics live in UniformPriceDualCapBatchAuctionStorage , an internal storage library. UniformPriceDualCapBatchAuction source contract","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Auction summary getters are maxAttoRepBeingSold , attoEthRaiseCap , finalized , clearingTick , ethFilledAtClearingAttoEth , attoEthRaised , totalAttoRepPurchased , auctionStarted , minBidSizeAttoEth , owner , underfunded , underfundedThreshold , underfundedWinningAttoEth , and activeTickCount . pendingEthRefundsAttoEth reports ETH credited during settlement and available for the bidder to pull. Use computeClearing , previewFinalization , tickToPrice , getTickSummary , getTickCount , getTickPage , getActiveTickPage , getBidCountAtTick , getBidPageAtTick , getBidderBidCount , and getBidderBidPage before finalizing or submitting settlement indexes.","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals startAuction(attoEthRaiseCap, maxAttoRepBeingSold) Auction owner ( SecurityPoolForker ) only Auction not previously started; both caps are positive; the REP cap does not exceed 11 million REP; the ETH cap fits in uint128 ; the block timestamp fits in uint48 . Starts the one-week auction and fixes its two caps and minimum bid. AuctionStarted submitBid(tick) with ETH Any bidder Auction active and unfinalized; before one-week deadline; bid meets minBidSizeAttoEth ; tick maps to nonzero price; the individual bid and the resulting cumulative ETH at that tick each fit in uint128 . Adds ETH demand at the selected positive-price tick while extending that tick's append-only cumulative bid and refund history, including when a fully refunded tick becomes active again. BidSubmitted refundLosingBids(tickIndices) Bidder for its own bids Auction started and unfinalized; auction has reached a clearing price. Nonempty indexes additionally belong to the caller and are strictly losing and unrefunded. A nonempty list marks the caller's bids already provably below the current clearing tick and credits their ETH to pendingEthRefundsAttoEth without calling the bidder. An empty list changes no bids. BidSettled per refunded bid; one aggregate EthRefundCredited per call when total credited ETH is positive refundLosingBidsFor(bidder, tickIndices) Auction owner ( SecurityPoolForker ) only; public callers use settleAuctionBids bidder is nonzero; the refundLosingBids prerequisites, with the indexes belonging to bidder . Performs the refundLosingBids refund for the bids of bidder instead of the caller. The refundLosingBids signals finalize() Auction owner ( SecurityPoolForker ) only; users reach it through finalizeTruthAuction Auction started, not finalized, and one-week deadline reached; owner accepts the proceeds ETH call, including zero value. Fixes the clearing mode, clearing tick, ETH totals, and aggregate REP allocation, then calls the owner with the resulting proceeds, including when zero. A rejected call reverts finalization and its event. AuctionFinalized withdrawBids(withdrawFor, tickIndices, proRataTotal, secondaryProRataTotal, repBackingUnitsTotal) Auction owner ( SecurityPoolForker ) only; public callers use claimAuctionProceeds or settleAuctionBids Auction finalized; caller is owner. Nonempty indexes belong to withdrawFor and remain unsettled. Returns five uint256 values in ABI order: totalFilledAttoRep (filled REP), totalRefundAttoEth (ETH refund), totalProRataAllocation (underwriting commitment), totalSecondaryProRataAllocation (bad debt), and totalRepBackingUnitsAllocation (REP backing units). The forker credits backing and underwriting commitment to the bidder vault and credits bad debt only while the recorded auction debt generation is current; the auction credits refunds to the beneficiary pull-payment balance without calling recipient code. Underwriting commitment and bad debt use fixed cumulative ETH positions. Backing units use the corresponding cumulative filled-REP positions to exhaust repBackingUnitsTotal without claim-order dependence. An empty list returns five zeros without changing bids or emitting events. BidSettled per processed bid; one EthRefundCredited for the call when aggregate totalRefundAttoEth is positive withdrawPendingEthRefund() Bidder with credited ETH Caller has a positive pendingEthRefundsAttoEth balance and currently accepts ETH. Clears the caller's complete credited refund and emits its withdrawal before transferring. A rejected pull reverts the transfer, clear, and event, preserving the credit. Checks-effects-interactions makes callback reentry observe a zero balance. PendingEthRefundWithdrawn","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"tick-pricing","heading":"Tick pricing","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Bids are placed at integer ticks between MIN_TICK ( -524288 ) and MAX_TICK ( 524288 ). tickToPrice(0) is PRICE_PRECISION , one ETH per REP. Each tick above zero multiplies the price by 1.0001 through a binary-exponentiation table of _powerOf1Point0001 ; negative ticks take the reciprocal. The price at tick t is therefore approximately: price ( t ) ≈ 1.0001 t ETH per REP A tick whose price rounds to zero is rejected. Within one tick, the uniform-clearing branch fills bids first in, first out, so earlier same-tick bids are consumed before later ones.","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["invariants","safety","liveness","properties"],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"An invariant is a statement that must remain true at every successful external-call boundary, across every legal lifecycle transition, or under the economic assumptions named beside it. Reverts may interrupt a transition, but they must roll back all of its state and asset effects. The catalog separates local contract guards, automated release-tooling guards, cross-contract properties, and economic assumptions. Each entry names the strongest enforcement and evidence currently present; a documented implementation choice is not automatically a safe invariant. See the Statoblast security model for assumptions A01–A28. Funded and underfunded clearing are explained in the Truth Auction clearing guide . Four connected layers run from local authority guards through cross-contract conservation and lifecycle liveness to economic security. A failure in an earlier layer invalidates the safety claims built above it. Invariant Dependency Correct callers are necessary but insufficient. Their actions must conserve assets, every mandatory state transition must remain reachable, and the named participation and inclusion assumptions must hold where the protocol deliberately relies on economic incentives. Matches All invariants listed below Filter invariants Type Any type Enforcement status Any status Subsystem Any subsystem Expand visible Collapse all Reset filters No invariants match the selected filters.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":1},{"fragment":"standing","heading":"Classification and scope","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Each entry separates the kind of property from its current enforcement status. A status describes the strongest claim supported by the local implementation and tests; it is not a formal proof. Type Meaning Safety A forbidden caller, state, transition, or replay cannot succeed. Conservation Assets, liabilities, supplies, and claims reconcile without duplication or loss. Liveness A required permissionless action remains executable under the stated conditions. Enforcement status Meaning Contract guard A direct authorization, bound, or state check enforces the property locally. Reviewed preservation Several contracts cooperate to preserve the property in reviewed flows and tests. External assumption Solidity cannot guarantee the property without honest participation, liquidity, transaction inclusion, or external token behavior. Automated tooling guard Release, deployment, or CI tooling rejects a mismatched artifact, address, or runtime-code identity before it is accepted. Invariant identifiers are stable review labels. The prefix names the boundary rather than a Solidity file: UNI universes, QST questions, AUTH authority, BAL pool balances, SHARE shares, VAULT vaults, FORK forks, ESC escalation, ORA the oracle, AUC auctions, LIFE lifecycle, OBS observability, and EXT external tokens, callbacks, block ordering, and lineage lookups. The index and the explorer's subsystem filter group entries by the nine page sections: BAL , SHARE , and VAULT share one section, as do LIFE , OBS , and EXT .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"standing","heading":"Terms used in the catalog","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Pool question The question whose outcome determines the SecurityPool 's winning outcome shares and Escalation Game payouts. Fork question The ended question recorded by the universe fork. It may differ from the pool question. Child branch A well-formed answer encoding for the fork question, used to derive one child universe from its parent. SecurityPool's binary pool-question paths specifically use Invalid, Yes, and No. Continuation game A child Escalation Game initialized from an unresolved parent game's fork snapshot. Its child pool is in fork continuation until the game is fully resumed; the game itself remains the continuation game afterward. Carry The unresolved parent escalation deposits exported into a fork snapshot and paid out by continuation games against Merkle Mountain Range proofs . Nullifier A continuation game's record that one carried deposit identity has been consumed, so its proof cannot be replayed. Fixed payout outcome The pool-question outcome a continuation game must use after its deadline, regardless of its copied balance leader. Direct fork A caller invokes Zoltar's universe-fork entrypoint directly rather than through a pool's own non-decision path. Recursive fork A fork of a child universe created by an earlier fork. Tracked balance An amount recorded by protocol accounting; it excludes unsolicited assets unless a named transition explicitly credits them. Consumed claim A deposit, bid, or proof that has already been settled, refunded, exported, or otherwise made unusable.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Invariant index","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Each identifier links to its full statement.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Universes, REP supply, and migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status UNI-01 One fork per universe Safety Contract guard UNI-02 Valid fork questions Safety Contract guard UNI-03 Fork threshold burn and credit Conservation Contract guard UNI-04 Deterministic child universe IDs Safety Contract guard UNI-05 Well-formed child outcomes Safety Contract guard UNI-06 Per-child migration mint limit Safety Contract guard UNI-07 Branch-specific child REP Conservation Reviewed preservation UNI-08 Child theoretical supply snapshot Conservation Reviewed preservation UNI-09 Child REP supply coherence Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Questions and answer classification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status QST-01 Question registry and classifier coherence Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Authority and deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status AUTH-01 Coordinator and forker-only operations Safety Contract guard AUTH-02 Atomic pool and coordinator binding Safety Reviewed preservation AUTH-03 Immutable protocol logic Safety Reviewed preservation AUTH-04 Deterministic deployment identity Safety Reviewed preservation AUTH-05 Delegate storage compatibility Safety Reviewed preservation AUTH-06 Permissionless settlement beneficiaries Safety Contract guard AUTH-07 Published deployment verification Safety Automated tooling guard AUTH-08 Factory registry and lineage bijection Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Pool assets, shares, and vaults","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status BAL-01 ETH conservation Conservation Reviewed preservation BAL-02 Unsolicited ETH isolation Conservation Reviewed preservation BAL-03 Collateral capacity and backing Conservation Reviewed preservation BAL-04 REP coverage boundaries Safety Contract guard BAL-05 REP backing units conversion consistency Conservation Reviewed preservation BAL-06 Fee liability accounting Conservation Reviewed preservation BAL-07 Fee reserve protection Conservation Contract guard BAL-08 Aggregate pool-ledger coherence Conservation Reviewed preservation SHARE-01 Complete-set symmetry Conservation Contract guard SHARE-02 Complete-set redemption Conservation Reviewed preservation SHARE-03 Positive-output minting Safety Contract guard SHARE-04 Child supply denominators Conservation Reviewed preservation SHARE-05 Winning-share payout cap Conservation Contract guard SHARE-06 Share supply conservation Conservation Reviewed preservation VAULT-01 Dispute-staked REP isolation Conservation Reviewed preservation VAULT-02 Liquidation conservation and freshness Conservation Reviewed preservation VAULT-03 Vault registry coherence Safety Reviewed preservation VAULT-04 Escalation claims are non-transferable and migration-neutral Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Forks and child isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status FORK-01 Parent pool finality Safety Contract guard FORK-02 Immutable fork snapshot Safety Reviewed preservation FORK-03 Isolated migration proxy Safety Reviewed preservation FORK-04 Prefunded proxy isolation Liveness Reviewed preservation FORK-05 Eight-week migration boundary Safety Reviewed preservation FORK-06 Child deployment identity Safety Reviewed preservation FORK-07 Single-use non-escrowed vault migration Conservation Reviewed preservation FORK-08 One-time aggregate continuation backing Conservation Contract guard FORK-09 Cumulative child collateral Conservation Contract guard FORK-10 Share migration integrity Conservation Contract guard FORK-11 Unequal child share supplies Conservation Reviewed preservation FORK-12 Child activation after settlement Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Escalation Games and carried claims","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status ESC-01 Total escrow reconciliation Conservation Reviewed preservation ESC-02 Local unresolved REP reconciliation Conservation Reviewed preservation ESC-03 Outcome carry reconciliation Conservation Reviewed preservation ESC-04 Stable deposit identifiers Safety Reviewed preservation ESC-05 Single-use claims per branch Safety Reviewed preservation ESC-06 Aggregate export accounting Conservation Reviewed preservation ESC-07 Authenticated carried winner payout Conservation Contract guard ESC-08 Game REP settlement conservation Conservation Reviewed preservation ESC-09 Terminal game outcomes Safety Contract guard ESC-10 Ancestor claim replay protection Safety Reviewed preservation ESC-11 Residual sweep preconditions Conservation Contract guard ESC-12 Pool and continuation payout agreement Safety Reviewed preservation ESC-13 Non-decision threshold and live start-bond arithmetic Safety Contract guard ESC-14 Carry commitment structural integrity Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status ORA-01 Authorized settlement callbacks Safety Contract guard ORA-02 REP-per-ETH price direction Safety Contract guard ORA-03 Oracle price validity Safety Contract guard ORA-04 Single-use staged operations Safety Contract guard ORA-05 Staged operation targets Safety Contract guard ORA-06 Consumed execution failures Liveness Contract guard ORA-07 Staged-operation queue and index bijection Safety Reviewed preservation ORA-08 Dispute and settlement boundary Safety Contract guard ORA-09 Oracle balance-domain boundary Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Truth Auctions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status AUC-01 Bid admission Safety Contract guard AUC-02 Auction caps Conservation Contract guard AUC-03 Single-use bid settlement Safety Contract guard AUC-04 Claim-order independence Conservation Reviewed preservation AUC-05 Allocation and refund reconciliation Conservation Reviewed preservation AUC-06 Bidder-vault credits Conservation Reviewed preservation AUC-07 Uniform weak-demand allocation Conservation Reviewed preservation AUC-08 Forced-ETH-resistant finalization Liveness Reviewed preservation AUC-09 Value-free finalization liveness Liveness Contract guard AUC-10 Persistent tick bid history Conservation Reviewed preservation AUC-11 Auction tree and public-model equivalence Safety Reviewed preservation AUC-12 Auction ETH liability conservation Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Lifecycle, liveness, observability, and external calls","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status LIFE-01 Pool state transitions Safety Reviewed preservation LIFE-02 Permissionless transition liveness Liveness Reviewed preservation LIFE-03 Atomic failure behavior Safety Reviewed preservation LIFE-04 Deadline equality rules Safety Contract guard LIFE-05 Bounded transition work Liveness Reviewed preservation OBS-01 Event-state replay equivalence Safety Reviewed preservation EXT-01 Genesis token behavior boundary Conservation External assumption EXT-02 Callback-safe accounting Safety Reviewed preservation EXT-03 ERC-1155 callback safety Safety Reviewed preservation EXT-04 Same-block deadline ordering Safety Contract guard EXT-05 Depth-independent lineage lookups Liveness Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"zoltar-invariants","heading":"Zoltar invariants","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"These properties govern core universe creation, REP supply, universe forks, deterministic child identities, and branch-specific REP migration.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"universes","heading":"Universes, REP supply, and migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-01","heading":"UNI-01 One fork per universe","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An initialized universe records at most one fork time and one fork question. Example: After a universe forks on question 17, a second call attempting to fork it on question 22 reverts. Type Safety Enforcement status Contract guard Primary evidence Zoltar.forkUniverse","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-02","heading":"UNI-02 Valid fork questions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property forkUniverse accepts only a question that exists in ZoltarQuestionData and whose end time has been reached ( block.timestamp >= endTime ). A pool may separately require the fork question to equal its pool question. Zoltar intentionally imposes no question-creation age, universe registration, or pool-relevance condition. Example: At exactly a known question's end time, a caller may fork a universe even when that question came from another universe or was created with an already-past end time; an unknown or still-open question is rejected. Requiring a universe-relevant or sufficiently aged question is not a Zoltar invariant. Type Safety Enforcement status Contract guard Primary evidence forkUniverse , question model , question-end fork boundary test Related assumption A15 intended question selection","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-03","heading":"UNI-03 Fork threshold burn and credit","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The fork threshold is ⌈parent theoretical supply / forkThresholdDivisor⌉ for nonzero supply, and zero only when supply is zero. Starting a fork burns that amount of the initiator's parent REP, reduces the parent theoretical supply by the same amount, and credits the threshold minus ⌊threshold / forkBurnDivisor⌋ for migration. The configured forkBurnDivisor is at least 5 , so the uncredited fork haircut cannot exceed 20%. Example: With a 1,000 REP theoretical supply, threshold divisor 20, and burn divisor 5, the initiator commits 50 parent REP, pays a 10 REP fork haircut, and receives 40 REP of migration credit. Type Conservation Enforcement status Contract guard Primary evidence getForkThresholdAttoRep and forkUniverse , fork-threshold rounding test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-04","heading":"UNI-04 Deterministic child universe IDs","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A child universe identity is exactly the truncated hash of its parent universe and fork outcome; one parent-outcome pair maps to one child. Example: Repeatedly deriving the Yes child of the same parent returns the same universe ID, while deriving its No child returns a different ID. Type Safety Enforcement status Contract guard Primary evidence getChildUniverseId , deterministic child-ID test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-05","heading":"UNI-05 Well-formed child outcomes","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only well-formed outcomes of the recorded fork question can deploy child universes or receive migrated REP. Example: For a binary categorical fork question whose valid indexes are 0, 1, and 2, passing index 3 cannot deploy a child or receive child REP. Type Safety Enforcement status Contract guard Primary evidence deployChild and _splitRep , malformed-outcome rejection tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-06","heading":"UNI-06 Per-child migration mint limit","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For one migrator and one child, cumulative child REP minted never exceeds that migrator's parent migration balance. Example: A migrator with 40 REP of migration credit cannot mint 25 REP and later mint another 20 REP into the same child. Type Safety Enforcement status Contract guard Primary evidence childMigrationRepAmountsAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-07","heading":"UNI-07 Branch-specific child REP","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property One burned parent migration balance may mint the same credited amount into several selected children. Each minted balance belongs to a different child REP token, and migration never restores the burned parent REP. Example: A 40 REP migration credit may mint 40 Yes-child REP and 40 No-child REP, but neither balance is parent REP and the burned parent balance remains zero. Type Conservation Enforcement status Reviewed preservation Primary evidence _splitRep , ReputationToken","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-08","heading":"UNI-08 Child theoretical supply snapshot","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The child theoretical-supply snapshot equals the parent's theoretical supply after the threshold burn plus the initiator's migration credit net of the fork haircut. Each child therefore excludes the uncredited fork haircut. Example: If a fork removes 50 parent REP and credits 40 migration REP, each child's theoretical snapshot is 10 REP below the pre-fork supply. Type Conservation Enforcement status Reviewed preservation Primary evidence childUniverseTheoreticalSupplySnapshotsAttoRep , common child supply snapshot test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-09","heading":"UNI-09 Child REP supply coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For each child REP token, total minted supply equals the sum of holder balances, never exceeds the child's theoretical-supply snapshot, and uses the same theoretical maximum recorded by the child universe. Example: If two migrators mint 12 and 7 child REP, the child token supply is 19 REP, both balances sum to 19 REP, and minting does not change the child's theoretical maximum. Type Conservation Enforcement status Reviewed preservation Primary evidence splitMigrationRep and child universe accounting , ReputationToken supply , aggregate child-supply invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"questions","heading":"Questions and answer classification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"qst-01","heading":"QST-01 Question registry and classifier coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every successful question creation appends its deterministic ID exactly once and leaves prior question data and labels immutable. For every stored question and answer, the malformed classifier is true exactly when the public answer name is Malformed , except that a categorical question may use the literal label Malformed for a well-formed outcome. Example: Appending a scalar question after two categorical questions preserves the first two records and their order; a scalar answer with reserved bits is both classified and named malformed. Type Safety Enforcement status Reviewed preservation Primary evidence createQuestion , getQuestions , and answer classification , registry and classifier invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"statoblast-invariants","heading":"Statoblast invariants","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"These properties govern Statoblast deployment, SecurityPool accounting, fork migration, escalation, oracle operations, Truth Auctions , and the cross-contract lifecycle built on Zoltar universes.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"authority","heading":"Authority and deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A23 verified deployments and A27 cryptographic security .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-01","heading":"AUTH-01 Coordinator and forker-only operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only the price coordinator 's immutable VaultOperations executor may call the pool's REP withdrawal, liquidation, and executor-side underwriting-commitment entry points, and withdrawRepFromVault and performLiquidation also require a currently valid coordinator price. A vault sets its own commitment directly with setUnderwritingLimit ; an increase requires a currently valid coordinator price. Only the immutable forker may mutate fork accounting or transfer migration assets. Example: A wallet calling withdrawRepFromVault directly is rejected with Unauthorized because it is not the coordinator's VaultOperations executor. Type Safety Enforcement status Contract guard Primary evidence SecurityPool.onlyValidOracle and onlyForker , SecurityPoolOperationsDelegate.setVaultUnderwritingLimit , OpenOraclePriceCoordinator.vaultOperations , VaultOperations , unauthorized-caller rejection tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-02","heading":"AUTH-02 Atomic pool and coordinator binding","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The pool and its coordinator bind once during atomic factory deployment; no external caller gets a transaction boundary in which it can install a substitute pool. Example: A caller cannot front-run factory deployment and make the coordinator point to an attacker-controlled pool. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory , setSecurityPool","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-03","heading":"AUTH-03 Immutable protocol logic","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property No mutable owner, governance address, upgrade implementation, or emergency operator can replace protocol logic after deployment. Example: After deployment, no administrator can point a pool proxy at different bytecode because the pool has no upgrade slot. Type Safety Enforcement status Reviewed preservation Primary evidence Immutable release posture","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-04","heading":"AUTH-04 Deterministic deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every canonical CREATE2 address commits to the correct factory, salt, constructor arguments, parent identity, universe, question, and multiplier. Example: Changing a child's question ID changes its derived address instead of deploying different semantics at the expected address. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory , securityPoolAddressDerivation.ts","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-05","heading":"AUTH-05 Delegate storage compatibility","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Delegatecall targets are constructor-installed protocol modules, and every target interprets the forker's storage with the same layout. Example: The vault-migration delegate reads forkDataByPool from the same slot used by the forker rather than corrupting adjacent state. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolForker , forker delegate storage-layout test , Escalation Game storage-layout test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-06","heading":"AUTH-06 Permissionless settlement beneficiaries","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Anyone may trigger permissionless settlement, but the caller cannot choose its beneficiary. Each transfer or REP-backing-unit credit goes only to the vault, bidder, depositor, or share holder recorded for that claim. Example: Alice may settle Bob's auction bid, but the purchased REP remains pool-held while the corresponding REP backing units and underwriting commitment are credited to Bob's vault . Type Safety Enforcement status Contract guard Primary evidence SecurityPool.redeemFees and withdrawForkedEscalationDeposits , UniformPriceDualCapBatchAuction.withdrawBids , contract interaction reference","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-07","heading":"AUTH-07 Published deployment verification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The release manifest must match the deterministic address calculation, and deployment tooling must reject installed planned contracts or bootstrap descendants whose runtime-code hash differs from the pinned release artifact. Example: Testnet deployment stops instead of treating the price-coordinator factory address as installed when its runtime bytecode differs from the expected hash. Type Safety Enforcement status Automated tooling guard Primary evidence runtime-code verification in the deployment plan , runtime-hash regression tests , deterministic manifest freshness check , mainnet manifest , and Sepolia manifest","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-08","heading":"AUTH-08 Factory registry and lineage bijection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every factory deployment record names one unique pool whose runtime parent, share token, universe, and question match the record. Its pool-to-origin reverse lookup and origin/universe forward lookup are mutual inverses, and its recorded share token authorizes that pool. Example: Looking up a child pool's origin and then resolving that origin with the child's universe returns the same child, not a pool from an independent origin lineage in that universe. Type Safety Enforcement status Reviewed preservation Primary evidence factory registry and canonical lookups , share-token authorization , stateful registry-bijection test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"pool-accounting","heading":"Pool assets, shares, and vaults","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the security pool guardrails . The raw ETH balance needs a surplus term. Without it, forced ETH is indistinguishable from collateral and can change an exchange rate or lifecycle precondition. rawEthBalanceAttoEth = settlementCollateralAttoEth + unallocatedAccruedFeesAttoEth + totalClaimableVaultFeesAttoEth + derivedSurplusAttoEth All terms are in attoETH. The first three are stored by the pool; derived surplus is the remainder and has no storage variable. BAL-01 states the invariant.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-01","heading":"BAL-01 ETH conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property At every successful external-call boundary, raw ETH = tracked collateral + unallocated fee reserve + total claimable vault fees + derived surplus . Derived surplus is the remainder; it has no storage variable and is never a protocol liability. Example: If the pool holds 12 ETH, owes 2 ETH in fees, and tracks 9 ETH of collateral, the remaining 1 ETH is surplus rather than additional collateral. Type Conservation Enforcement status Reviewed preservation Primary evidence Pool ETH accounting , stateful exact-accounting invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-02","heading":"BAL-02 Unsolicited ETH isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Unsolicited ETH cannot change collateral, initialize an exchange rate, or increase liabilities. Transition liveness under forced balances is owned by LIFE-02 . Example: ETH forced into an empty pool does not let the first complete-set mint use that ETH as its collateral base. Type Conservation Enforcement status Reviewed preservation Primary evidence receive , tracked collateral, and fee redemption , auction finalization , receive sender tests , mint fuzzing with forced ETH surplus","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-03","heading":"BAL-03 Collateral capacity and backing","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each vault's underwriting commitment X ( underwritingLimitAttoEth ) is separate from its REP backing. The pool maintains the total commitment T incrementally; L is tracked settlement collateral . Obligation. With positive T , a vault's obligation is L × X / T , rounded upward to the next atomic unit with full-precision arithmetic. For L ≤ T , each rounded obligation is at most X ; independently rounded obligations need not sum exactly to L . Authorization. REP deposits do not increase X . Redemptions and fees reduce L without reducing X , empty settlement epochs do not revoke it, and price or backing changes leave it unchanged. Minting. Minting requires L + deposit ≤ T and no escalation or fork-continuation game. It reads no oracle price and checks no REP backing: every vault already answers for its full commitment, so collateral within T adds no REP exposure. Minters therefore accept the current backing of the pool's commitments; minting is not blocked when that backing is insufficient. The usable collateral ceiling equals T . Withdrawal. A REP withdrawal must preserve aggregate backing for all of T and the withdrawing vault's full-commitment backing. Individual health. Each vault remains subject to full-commitment backing requirements and liquidation; aggregate health does not imply that every vault is healthy. Liquidation transfers commitment and backing to an authorized, sufficiently backed receiver without writing off collateral or changing T , so recovery depends on an eligible receiver. Example: A has a 10 ETH underwriting commitment and the pool holds 10 ETH settlement collateral. B separately deposits sufficient REP and commits 5 ETH. Their obligations become 6.666666666666666667 ETH and 3.333333333333333334 ETH. At 15 ETH settlement collateral, both obligations equal their commitments. Changing REP prices leaves the commitments and the 15 ETH collateral ceiling unchanged but can make a vault liquidatable. Type Conservation Enforcement status Reviewed preservation Primary evidence createCompleteSet , setPoolFinancials , redeemCompleteSet , and redeemShares , redeemCompleteSet and redeemShares claim-exhaustion generation transitions , createCompleteSet , finalizeTruthAuctionRepair , _creditAuctionProceeds , creditForkAuctionVault , commitment, minting, and withdrawal tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-04","heading":"BAL-04 REP coverage boundaries","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For a commitment X at REP/ETH price p , with pool multiplier m in BPS and health factor h in BPS ( 10,000 unless a delegated receiver approved more), each product rounding upward: Associated-REP branch. Pool-held vault REP plus the vault's locally dispute-staked REP is at least X × p × m / 10,000 × h / 10,000 . Pool-held-REP branch. Pool-held vault REP alone is at least X × p × max(10,500, 10,000 + (m − 10,000) / 2) / 10,000 × h / 10,000 . 10,500 BPS is the liquidation-award reserve: 10,000 plus the 500-BPS liquidation bonus. Where both apply. A REP withdrawal or vault-funded escalation deposit must leave the affected vault passing both branches, and both operations apply the same two branches to the pool aggregate against the total underwriting commitment . A liquidation receiver must pass both after accepting the transferred commitment; liquidation does not require the unhealthy target to become healthy. A wallet-funded escalation deposit moves no vault backing and runs neither check. Repricing. A later price change can make an existing position fail a branch without reducing its commitment; that enables liquidation and reverts nothing retroactively. Example: With m = 20,000 , the pool-held-REP multiplier is 15,000 BPS; with m = 10,500 it is the 10,500 -BPS floor. A receiver approved at h = 12,000 must hold 1.2× both upward-rounded requirements after accepting the transferred commitment; passing only one branch is insufficient. Type Safety Enforcement status Contract guard Primary evidence SecurityPoolUtils.isVaultHealthyAtFactor , SecurityPool._requireVaultCoverage and _requirePoolCoverage , multiplier-coverage regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-05","heading":"BAL-05 REP backing units conversion consistency","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property After deposits, withdrawals, liquidations, escalation transfers, migration, and auction claims, the same current pool-held REP balance and total REP backing units govern both REP-to-backing-unit and backing-units-to-REP conversion. Both proportional directions use full-precision multiplication and division so a representable claim cannot fail only because its intermediate product exceeds uint256 . Example: Depositing REP and immediately converting the resulting REP backing units back to REP uses the same denominator rather than a stale pre-deposit balance. Type Conservation Enforcement status Reviewed preservation Primary evidence attoRepToBackingUnits and backingUnitsToAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-06","heading":"BAL-06 Fee liability accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every attoETH of accrued fees is represented once as unallocated reserve or claimable vault fees, and redemption clears the claimable fee balance before ETH is sent. Example: Assigning 3 attoETH of reserve to a vault decreases unallocated reserve by 3 and increases that vault's claimable fees by 3, without creating a second claim. Type Conservation Enforcement status Reviewed preservation Primary evidence Fee accumulator and redeemFees","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-07","heading":"BAL-07 Fee reserve protection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Fork transfers and redemptions cannot spend ETH reserved for unpaid or unallocated fees. Example: A fork transfer may move 8 ETH of collateral from a 10 ETH balance that also contains 2 ETH of fee liabilities, but may not move all 10 ETH. Type Conservation Enforcement status Contract guard Primary evidence transferEth","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-08","heading":"BAL-08 Aggregate pool-ledger coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Fee ledger. totalClaimableVaultFeesAttoEth equals summed unpaid vault fees. Operational fee eligibility. In Operational , feeEligibleUnderwritingLimitAttoEth equals summed live vault underwriting commitments plus sold Truth Auction commitment awaiting claim. uncheckpointedFeeEligibleUnderwritingLimitAttoEth covers fee-eligible commitment not yet reconciled to the current global index, including an unclaimed auction allocation after the index advances. Fork migration. During ForkMigration , configured migrated commitments remain pending outside those pool aggregates. A PoolForked parent retains its fork-time total and fee-eligible snapshots as individual vaults migrate. Auction activation. After a positive-purchase Truth Auction activation, total commitment equals fee-eligible commitment, with the outstanding unclaimed auction allocation in both aggregates. If the auction purchases zero REP, the unmigrated remainder stays an explicit unassigned commitment outside fee eligibility, as the auction settlement specification defines. Commitment ownership. At finalization and after every claim, every commitment unit the child counts belongs either to a real vault or to the nonwithdrawable unassigned position. Fee remainders. Per-vault remainder carries make ordinary fee claims independent of checkpoint frequency and claim order. Terminal residue. At a terminal fork, after all commitment behind the final index has been checkpointed, the only unreconciled whole-attoETH reserve is cumulative division residue, strictly less than N attoETH. N counts each vault entitlement ledger, any separately checkpointed unassigned auction entitlement, and each denominator epoch whose global remainder is cleared when fee-eligible commitment changes; repeated checkpoints within the same ledger and epoch carry their remainder and do not increase N . Terminal recovery. Because the configurable vault floor and auction settlement give N no small protocol-wide bound, the retained terminal recovery path releases that reserve only after uncheckpointedFeeEligibleUnderwritingLimitAttoEth reaches zero. Example: Migrating one of two vaults that each hold a 3 ETH underwriting commitment leaves the parent's frozen 6 ETH total unchanged and records 3 ETH of commitment as unassigned in the child. With purchased REP, finalization adds those 3 ETH of sold commitment to fee eligibility immediately, and later claims only transfer the position to bidder vaults. With zero purchased REP, the same 3 ETH remains unassigned and fee-ineligible until an authorized, fully backed takeover. Type Conservation Enforcement status Reviewed preservation Primary evidence getPoolAccountingSnapshot and vault checkpointing , truth-auction claim accounting , stateful ledger and claim-order invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-01","heading":"SHARE-01 Complete-set symmetry","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A complete-set mint or burn changes Invalid, Yes, and No balances by the same amount in the same universe. Example: Minting five complete sets creates five Invalid, five Yes, and five No shares for that universe. Type Conservation Enforcement status Contract guard Primary evidence mintCompleteSets and burnCompleteSets","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-02","heading":"SHARE-02 Complete-set redemption","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before outcome finalization, burning B complete sets returns ⌊B × tracked collateral / complete-set supply⌋ after the fee checkpoint, then reduces supply by B and collateral by the ETH returned. Example: With 100 sets and 10 ETH of tracked collateral, burning 10 sets returns 1 ETH before integer-rounding residue. Type Conservation Enforcement status Reviewed preservation Primary evidence redeemCompleteSet","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-03","heading":"SHARE-03 Positive-output minting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A successful positive-value complete-set mint returns a positive share amount. Example: A 1 attoETH mint that rounds to zero shares reverts instead of accepting the ETH. Type Safety Enforcement status Contract guard Primary evidence attoEthToAttoShares and the createCompleteSet wrapper , createCompleteSet settlement accounting , positive-value mint fuzzing","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-04","heading":"SHARE-04 Child supply denominators","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Child setup copies the frozen parent's remaining economic claim supply as its collateral denominator. That supply includes both materialized child ERC-1155 balances and source entitlements that can materialize later. Complete-set minting adds claims, while complete-set and winning-share redemption consume them. Example: If a parent freezes with 10 claims per outcome and a child has no materialized shares yet, setup still records 10. A new minter receives only the shares purchased at that established rate, while all 10 source claims retain their reserved collateral. Type Conservation Enforcement status Reviewed preservation Primary evidence attoEthToAttoShares and redeemShares and ShareToken.migrate","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-05","heading":"SHARE-05 Winning-share payout cap","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Total ETH paid to winning shares never exceeds the collateral available when redemption begins; rounding residue remains for later winning holders. Example: When two winners redeem sequentially, the second receives its fraction of the collateral left after the first rather than a fraction of the original balance paid twice. Type Conservation Enforcement status Contract guard Primary evidence redeemShares","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-06","heading":"SHARE-06 Share supply conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For every ERC-1155 share ID, total supply equals the sum of holder balances through mint, transfer, and burn operations. Per-child materialization and duplicate prevention are owned by FORK-10 . Example: Moving two Yes shares between wallets leaves Yes supply unchanged; burning one Yes share reduces both the holder-balance sum and Yes supply by one. Type Conservation Enforcement status Reviewed preservation Primary evidence ERC-1155 supply accounting , modeled holder-supply invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-01","heading":"VAULT-01 Dispute-staked REP isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property REP that a vault moved into an escalation game cannot also be withdrawn, liquidated as pool-held vault REP backing, or migrated through the ordinary non-escrowed vault path. REP deposited straight from a wallet with depositWalletRepToEscalationGame enters the game without ever becoming vault backing. Example: A vault initially attributed 20 REP that dispute-stakes 5 REP is left with 15 REP of vault backing plus a separate 5 REP claim. It cannot make an ordinary withdrawal while that escrow remains; ordinary vault migration moves only the 15 REP backing, while the dispute-staked REP claim follows its separate migration path. Type Conservation Enforcement status Reviewed preservation Primary evidence Escrow checks , EscalationGame , wallet-funded deposit regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-02","heading":"VAULT-02 Liquidation conservation and freshness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Eligibility. Liquidation eligibility and receiver authorization use full underwriting commitments , including when settlement collateral is zero. Transfer. A successful liquidation transfers underwriting commitment and REP backing units from target to receiver without changing the total commitment. Unrelated vaults retain their proportional weights. Award. The nominal REP award includes the fixed 5% liquidation bonus and is capped by available target backing; a sufficiently backed receiver can take the full commitment even when that award is not fully funded. Receiver backing. Both backing constraints apply to the receiver's entire resulting commitment. Residual commitment. Residual target commitment remains visible and can be taken over later; liquidation does not write it off. Fees and stake. Earned fees and dispute stake stay with their owners, with fees checkpointed before the transfer. Underbacked commitments continue earning fees; backing health affects liquidation eligibility, not fee entitlement. Delegated route. A delegated route bounds the transferred commitment by the receiver's signed reservation and consumes or releases that reservation exactly once. Example: If the target or receiver changes after staging, execution may fail safely and release the full reservation. The operator receives no ownership merely for submitting the transaction. Type Conservation Enforcement status Reviewed preservation Primary evidence Liquidation design , performLiquidation , executeStagedOperation , liquidation commitment-transfer tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-03","heading":"VAULT-03 Vault registry coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The vault registry is append-only and contains each nonzero address at most once. Registration does not require economic state: any vault path that registers through _registerVault or the operations delegate's equivalent inline registration, including a public fee checkpoint for an empty address, can append it. Pagination is newest-registered first; later activity and full exit do not reorder or remove an entry. Consumers read current vault and escalation state to decide which registered vaults to display. Example: After a vault has fully exited and its REP backing, underwriting commitment, claimable fees, escalation stake, bad debt , and open interest are all zero, its address remains in registry pagination. A UI can filter the empty position without losing historical discovery. Type Safety Enforcement status Reviewed preservation Primary evidence _registerVault , registry pagination and direct-claim boundary tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-04","heading":"VAULT-04 Escalation claims are non-transferable and migration-neutral","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An escalation claim is permanently bound to the depositor committed in its carry leaf and has no transfer path and no power over parent open-interest migration. Liquidation cannot read, move, or acquire it. Payout to the committed depositor is owned by ESC-07 . Example: Moving half a vault's underwriting commitment leaves every escalation claim unchanged, and locking that claim cannot increase the open interest routed to any child. Type Safety Enforcement status Reviewed preservation Primary evidence withdrawDeposit , liquidation design , child-liquidation claim-retention test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"forks","heading":"Forks and child isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the share migration and fork migration guardrails.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-01","heading":"FORK-01 Parent pool finality","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once a pool's universe forks, the pool's operational flows are frozen by the fork-time check in isOperational , whatever its stored state. A pool that enters PoolForked never returns to Operational . A pool with an inherited fixed outcome never enters PoolForked ; ESC-12 owns that case. Example: After fork activation, the parent cannot accept another REP deposit or later return from PoolForked to Operational . Type Safety Enforcement status Contract guard Primary evidence isOperational , activateForkMode","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-02","heading":"FORK-02 Immutable fork snapshot","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property When the parent first enters fork mode, it captures fork time, collateral, REP buckets, total REP backing units, escalation state, and underwriting commitments exactly once. Those immutable values are the common basis for every child of that fork. Example: REP sent unsolicited to the parent after fork mode begins cannot change the REP snapshot used to initialize a later-created No child. Type Safety Enforcement status Reviewed preservation Primary evidence Fork snapshot preparation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-03","heading":"FORK-03 Isolated migration proxy","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each parent pool maps to exactly one deterministic migration-proxy address, and that address is the pool's isolated identity in the Zoltar migration ledger. Example: Two parent pools using the same forker derive different proxy addresses and therefore cannot spend each other's migration credit. Type Safety Enforcement status Reviewed preservation Primary evidence getMigrationProxyAddress","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-04","heading":"FORK-04 Prefunded proxy isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Preexisting or unsolicited REP at the deterministic proxy cannot block initiation or become unclassified migration principal. Example: An attacker sending 1 REP to the future proxy address cannot make fork initiation revert or count that REP as pool migration principal. Type Liveness Enforcement status Reviewed preservation Primary evidence initiateSecurityPoolFork","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-05","heading":"FORK-05 Eight-week migration boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Statoblast child-pool creation, pool-local vault migration, public pool-proxy REP splitting through migrateRepToZoltar , and own-fork claims are allowed through forkActivationTime + 8 weeks , inclusive, and are closed after that timestamp. Starting a child's Truth Auction after the deadline still completes that child's remaining pool-proxy REP split. forkActivationTime is recorded when the parent pool enters PoolForked ; post-migration activation begins only after its window ends. Share materialization has no expiry, but after the deadline it can target only an already-created child. This pool-local boundary does not limit Zoltar.deployChild , addRepToMigrationBalance , or splitMigrationRep ; those Zoltar operations follow their own fork identity and balance guards without this timestamp check. Example: Vault migration succeeds exactly at the eight-week deadline and reverts one second later. Type Safety Enforcement status Reviewed preservation Primary evidence forkActivationTime recording and child guards , MIGRATION_TIME , deployChild , addRepToMigrationBalance , and splitMigrationRep , migration and auction-start deadline tests , nested-fork migration-window regression test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-06","heading":"FORK-06 Child deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A deployed child must name the requesting pool as its parent and must use the child universe derived from that parent's selected branch. Its factory, forker, auction, share token, pool question, and security multiplier must equal the values supplied or inherited by the parent factory path. External-universe fork initiation requires the source pool to be authorized by its declared share token; own-game initiation does not. That relationship is not proof of configured-factory registration. The auction must have deployed code and must not already be trusted for another child. Example: On the external-universe path, the forker first requires the source to be authorized by its declared share token without treating that check as factory registration. The configured canonical factory installs the parent's share token, pool question, and multiplier in the child; the post-deployment guard then checks deployed and unique auction assignment plus parent, universe, factory, forker, and auction relationships before linking it. Type Safety Enforcement status Reviewed preservation Primary evidence _prepareForkState external-fork authorization guard , _validateChildPoolDeployment and deployChildSecurityPool","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-07","heading":"FORK-07 Single-use non-escrowed vault migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Vault migration converts the parent's backing-unit claim to REP, credits that REP amount as child-local backing units, and clears the corresponding parent REP backing units and underwriting commitment before reuse. A positive parent claim that maps to zero child REP receives zero child backing units, so rounding cannot preserve a stale claim that later regains value. Claimable fees remain in the parent vault while proportional settlement collateral routes separately at pool level. Example: After Alice migrates her non-escrowed vault accounting to the Yes child, a second migration call cannot credit the same parent REP backing units to the No child. Type Conservation Enforcement status Reviewed preservation Primary evidence _migrateNonEscrowedVaultAccounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-08","heading":"FORK-08 One-time aggregate continuation backing","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once per child. Each selected child initializes the canonical carry snapshot and receives the complete aggregate continuation backing at most once. Optional cleanup. Vault cleanup, callable only by the vault owner within the migration window, first migrates that vault's non-escrowed position and then clears its unresolved parent escalation-deposit accounting. It creates no child escrow and cannot change carried-proof eligibility. Unrelated fork. The continuation cannot resume until its game balance covers all effective unresolved principal. Own fork. Let R be the snapshot's raw unresolved principal: the sum of inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep across all three outcomes, before direct-claim deductions. Initial backing must be at least R - ⌊R / 5⌋ , where 5 is the fixed Constants.MINIMUM_FORK_BURN_DIVISOR , not the universe's configured fork burn divisor. The live balance must cover the initial backing not yet exported by valid direct pre-resume claims, scaled down by any REP a Truth Auction removed from the game. Example: Creating the Yes child installs its snapshot and aggregate backing before Alice acts. Alice may later clear her unresolved parent escalation-deposit accounting, but that cleanup neither funds the child nor enables or disables her winning proof. Type Conservation Enforcement status Contract guard Primary evidence _ensureChildEscalationBacking , resumeFromFork , isForkCarryFundingComplete , _exportForkedEscrowByOutcome , and fork-backing regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-09","heading":"FORK-09 Cumulative child collateral","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Cumulative parent ETH transferred to children never exceeds the fork collateral snapshot and is derived from cumulative migrated REP, not per-call rounding. Example: If several calls collectively migrate R child REP, their collateral target is ⌈fork collateral × R / denominator⌉ , independent of how that same R is partitioned. The denominator is vaultRepAtForkAttoRep for an own fork and auctionableAttoRepAtFork otherwise. Type Conservation Enforcement status Contract guard Primary evidence _transferForkMigratedCollateralToChild","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-10","heading":"FORK-10 Share migration integrity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Share migration preserves the holder's parent token-ID balance as a persistent entitlement, rejects duplicate or malformed target outcomes, and mints only the unmaterialized balance into each selected child. A used source balance cannot transfer. Example: Materializing seven parent Yes shares in one child leaves all seven parent entitlements visible and locked. A later call can mint seven into another existing child, but cannot mint the first child twice. Type Conservation Enforcement status Contract guard Primary evidence ShareToken.migrate","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-11","heading":"FORK-11 Unequal child share supplies","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Child pricing uses the fork-time economic claim supply rather than currently materialized outcome supplies. Unequal ERC-1155 supplies therefore do not block complete-set minting or proportional complete-set redemption. The denominator lifecycle and payout mechanics are owned by SHARE-04 . Example: If the economic supply is 12 while materialized supplies are 10, 8, and 6, a new complete set is priced against 12 and adds the same newly purchased balance to all three materialized supplies. Type Conservation Enforcement status Reviewed preservation Primary evidence setShareTokenSupplyAttoShares during auction preparation , attoSharesToAttoEth , redeemCompleteSet , and redeemShares , mintCompleteSets and persistent migration accounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-12","heading":"FORK-12 Child activation after settlement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Value-free truth-auction settlement activates a child with its tracked migrated collateral plus retained auction ETH, which cannot exceed the parent fork snapshot. Fork-time economic claim accounting keeps later minting and proportional burns independent from materialization order. Example: A child with 9 ETH against a 10 ETH fork snapshot activates after value-free finalization with 9 ETH of tracked collateral; its later operations remain subject to the ordinary share-supply and minting guards. Type Safety Enforcement status Reviewed preservation Primary evidence Truth-auction start and finalization","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"escalation","heading":"Escalation Games and carried claims","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the escalation guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-01","heading":"ESC-01 Total escrow reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property totalDisputeStakedAttoRep equals effective live vault-denominated escrow plus effective aggregate continuation backing in forkCarryDisputeStakedAttoRep . Continuation backing is not assigned to child-vault health or migration power, but it must enter the aggregate before the Truth Auction so physically held REP cannot escape the Truth Auction's REP removal. Auction retention, the fraction of game REP left after that removal, floors the aggregate total and the continuation bucket independently; do not reconstruct either aggregate by summing independently rounded vault views. Example: If vault-denominated escrow contributes 4 and 6 REP and an external-fork continuation carries 12 REP of aggregate proof backing, the total is 22 REP, represented as 22 × 10^18 attoREP in totalDisputeStakedAttoRep , before the auction. A 75% retention records ⌊22 × 10^18 × 75%⌋ attoREP, or 16.5 total effective REP, and ⌊12 × 10^18 × 75%⌋ attoREP, or 9 aggregate continuation REP. This makes the carried claims absorb the same repair loss without pretending that their backing belongs to a particular child vault. Type Conservation Enforcement status Reviewed preservation Primary evidence Continuation initialization , truth-auction retention accounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-02","heading":"ESC-02 Local unresolved REP reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property totalLocalUnresolvedAttoRep equals the sum of unresolved local deposits, and each vault-local counter is its exact component. Example: If Alice has 3 unresolved REP and Bob has 5, their counters are 3 and 5 and the global local-unresolved total is 8. Type Conservation Enforcement status Reviewed preservation Primary evidence Unresolved counters","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-03","heading":"ESC-03 Outcome carry reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For each outcome, currentCarryTotalAttoRep equals effective inherited unresolved principal plus unresolved local deposits. Effective inherited principal subtracts immediate-parent direct claims and becomes zero for an inherited losing outcome after finalization. Example: A child snapshots 7 Yes REP, the parent directly claims 2 REP, and the child receives a new unresolved 2 REP Yes deposit. Its current Yes carry is (7 - 2) + 2 = 7 REP . Type Conservation Enforcement status Reviewed preservation Primary evidence Escalation accounting invariants , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-04","heading":"ESC-04 Stable deposit identifiers","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An ordinary game's stable deposit identifier is its local deposit index. A continuation game derives the identifier from its own address, outcome, and local index, so two different continuation deposits cannot share a carry or nullifier key merely because their local indexes match. Example: Deposit zero on Yes in a child game and deposit zero on Yes in its grandchild produce different stable identifiers. Type Safety Enforcement status Reviewed preservation Primary evidence Stable deposit identity , EscalationGameSettlement._getStableLocalParentDepositIndex , SecurityPoolForker.getEscalationDepositId","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-05","heading":"ESC-05 Single-use claims per branch","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Along any single root-to-descendant fork path, each local or inherited deposit may be claimed, settled, refunded, or exported at most once. Child nullifiers are branch-local, so selected sibling branches keep separate claim authorization. A direct claim from an ancestor is the exception and is owned by ESC-10 . Example: Consuming a carried proof in a Yes grandchild prevents replay farther down that branch while a sibling branch remains independent. Type Safety Enforcement status Reviewed preservation Primary evidence Carry nullifiers , MMR proofs , carried-proof replay test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-06","heading":"ESC-06 Aggregate export accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Aggregate unresolved export clears the exporting vault's three outcome totals, unresolved counter, and parent escrow exactly once. It retains the deposit rows and carry commitment solely as immutable proof material for selected children. Example: After Alice exports her aggregate claim, her parent escrow is zero even though her historical deposit row remains available to prove a child claim. Type Conservation Enforcement status Reviewed preservation Primary evidence exportVaultUnresolvedTotalsWithoutTransfer","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-07","heading":"ESC-07 Authenticated carried winner payout","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A carried claim must authenticate an unconsumed proof for the final winning outcome. The proof fixes the original claim identity and its committed depositor, who receives the normal winning payout even when another account relays the transaction. Liquidation cannot change that recipient. Example: Bob may relay Alice's valid winning proof, but the payout still goes entirely to Alice as the committed depositor. A losing proof cannot consume backing, and reward math may make a winning payout greater than its principal. Type Conservation Enforcement status Contract guard Primary evidence withdrawDeposit","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-08","heading":"ESC-08 Game REP settlement conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every REP unit held for a game is accounted for exactly once as winning principal, burned escalation haircut, reward funding, losing principal, unsettled residual, ordinary-game REP swept back to the pool, fork-continuation REP burned, or REP moved out by fork activation or a Truth Auction. Settlement cannot create an additional REP claim. Example: Paying winners and sweeping the final residual reduces the game balance to zero without total payouts exceeding the REP previously held. Type Conservation Enforcement status Reviewed preservation Primary evidence Settlement","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-09","heading":"ESC-09 Terminal game outcomes","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once resolution or non-decision closes a game path, later deposits cannot reopen or change that terminal result. Example: After Yes becomes final, a later attempt to deposit on No reverts rather than changing the winner. Type Safety Enforcement status Contract guard Primary evidence EscalationGame","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-10","heading":"ESC-10 Ancestor claim replay protection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property If a deposit is claimed directly from an ancestor during an own fork, every existing or later descendant treats the corresponding proof as spent, even if that descendant has not written its own nullifier, and subtracts the claimed principal from its effective inherited principal. Example: Claiming deposit 4 from the parent blocks proof 4 in an already-created child and in a grandchild created later. Type Safety Enforcement status Reviewed preservation Primary evidence Forked claims , direct-claim replay test across current and late children","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-11","heading":"ESC-11 Residual sweep preconditions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Residual REP cannot be settled until effective unresolved principal is zero for every outcome. For a continuation, the sweep first retires its inherited aggregate forkCarryDisputeStakedAttoRep ; after that retirement, no local dispute stake or vault escrow may remain in totalDisputeStakedAttoRep . Inherited losing principal retires at finalization without a proof; winning inherited proofs and every local unresolved deposit still require their applicable terminal transition. Ordinary-game residual returns to the pool, while fork-continuation residual is burned and cannot accrue to child-local backing units. Example: After Yes finalizes, an unclaimed inherited No leaf does not block sweeping. An unclaimed inherited Yes proof, an unsettled local deposit, or a live vault escrow record still does. Type Conservation Enforcement status Contract guard Primary evidence sweepResidualRepToSecurityPool , external-fork residual burn regression test , own-fork residual burn regression test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-12","heading":"ESC-12 Pool and continuation payout agreement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property When a universe forks on a pool's question, each child pool and its continuation game use that child's Invalid, Yes, or No branch as the final pool-question outcome. Once a pool inherits that fixed outcome, new local escalation deposits and every later fork transition revert, whether the new universe fork uses the same question or another one. Deposit withdrawal reverts unless the pool and game report the same outcome. Example: A Yes child created by a fork on the pool question pays carried Yes deposits even if copied game balances favored No. It rejects new local dispute-staked REP before escrow, so a later local non-decision cannot lock vault redemption. A later matching or unrelated universe fork leaves the stored SystemState.Operational and fixed Yes outcome unchanged, and eligible share, vault REP, and carried-proof redemption paths remain available, while universe-fork guards still freeze normal operating calls. Type Safety Enforcement status Reviewed preservation Primary evidence activateForkMode , getQuestionResolution , fixed-outcome propagation , and pool/game payout check","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-13","heading":"ESC-13 Non-decision threshold and live start-bond arithmetic","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For a positive fork threshold of F attoREP, non-decision requires ⌈F / 2⌉ attoREP on at least two outcomes. Therefore the two threshold balances total at least F , while one attoREP less on both outcomes totals strictly less than F . At pool construction, the configured start bond is max(1 REP, live universe theoretical REP supply / 10,000,000) , and a new origin requires the live non-decision threshold to exceed it. If an existing pool's live threshold later falls to or below that configured bond, ordinary game deployment clamps the live start bond to nonDecisionThresholdAttoRep - 1 , provided the threshold exceeds one attoREP. Example: If F = 5 attoREP, non-decision requires 3 attoREP on two outcomes, which total 6 attoREP; one attoREP less on both, 2 and 2 , totals 4 attoREP, below the fork threshold. Type Safety Enforcement status Contract guard Primary evidence getNonDecisionThresholdAttoRep , origin threshold admission , deployEscalationGame , and start-liveness regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-14","heading":"ESC-14 Carry commitment structural integrity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For every outcome, exported carry peaks, leaf count, unresolved total, and nullifier root equal the corresponding outcome state. Only leaf-count-selected peak heights are occupied, independently bagging those peaks yields the exported root, and consumed proof indexes are unique. The accounting definition of unresolved total is owned by ESC-03 . Example: Three Yes leaves occupy the height-zero and height-one peaks; bagging those two peaks reproduces the exported Yes root before and after one inherited proof is consumed. Type Conservation Enforcement status Reviewed preservation Primary evidence getForkCarrySnapshot and getForkCarryRoots , bagCarryPeaks , independent carry-structure invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"oracle","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A18 independent correction incentive , A19 observable correctable price , and A06 lifecycle executors . No oracle invariant bounds operation value by report liquidity or bounds pending-report duration; these are the excluded guarantees EG03 and EG04 . Per-function accept and reject conditions are in the oracle guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-01","heading":"ORA-01 Authorized settlement callbacks","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only the configured OpenOracle may supply a settlement callback, and its report identifier must equal the coordinator's pending report. Example: A callback from another contract or for an older report ID cannot update the cached REP/ETH price. Type Safety Enforcement status Contract guard Primary evidence openOracleCallback , callback caller and report-identity guard test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-02","heading":"ORA-02 REP-per-ETH price direction","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An accepted price is positive REP per ETH: amount2 REP × 1e18 / amount1 WETH . Higher values require more REP for the same ETH obligation. Example: A report of 200 REP for 2 WETH stores 100 REP per ETH, not 0.01 ETH per REP. Type Safety Enforcement status Contract guard Primary evidence openOracleCallback , ratio direction","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-03","heading":"ORA-03 Oracle price validity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A cached price is usable only while nonzero and strictly younger than its chain-specific validity window . Example: On mainnet, a price whose final report reached settlement eligibility exactly five minutes ago is stale; one that reached it four minutes and 59 seconds ago remains usable. Type Safety Enforcement status Contract guard Primary evidence isPriceValid , five-minute validity boundary test , late-settlement freshness regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-04","heading":"ORA-04 Single-use staged operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every staged operation has one immutable identifier. Once execution is attempted with a usable price, success or a caught failure consumes that identifier, emits the result, and prevents a retry. An uncaught transaction revert instead rolls back the entire attempt. Example: A pool-level withdrawal rejection is caught and emitted as failed, after which the same operation ID cannot be executed again. Type Safety Enforcement status Contract guard Primary evidence executeStagedOperation , staged-operation overwrite and double-execution test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-05","heading":"ORA-05 Staged operation targets","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Withdrawals target the initiating vault. Liquidations name separate operator, receiver, and target roles; the receiver must differ from the target, while the operator may equal either. A liquidation fails when the protected target REP-backing-unit or underwriting-commitment snapshot becomes stale. Example: Alice can stage her own REP withdrawal. A liquidation operator can target Bob, but its receiver cannot be Bob; execution fails if Bob changes his REP backing units or underwriting commitment after staging. Type Safety Enforcement status Contract guard Primary evidence Staging and snapshot checks","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-06","heading":"ORA-06 Consumed execution failures","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An expired operation, a liquidation with a stale target snapshot, a withdrawal that would move zero REP, or a liquidation inside the configured minimum price distance is a consumed failure under ORA-04 : it emits an observable failure result instead of remaining executable. Example: If an earlier withdrawal empties a vault, its second queued withdrawal is consumed as a zero-effect failure rather than retried after every price update. Type Liveness Enforcement status Contract guard Primary evidence executeStagedOperation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-07","heading":"ORA-07 Staged-operation queue and index bijection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Operation IDs are append-only. Active enumeration contains each and only each operation with a live initiator; the bounded pending settlement queue contains unique active IDs; and pendingOperationSlotId is zero for an empty queue or equals its head. Example: Settling four queued operations removes those four IDs from both indexes, leaves an overflow operation active for manual execution, and does not reuse any consumed ID. Type Safety Enforcement status Reviewed preservation Primary evidence active and pending staged-operation indexes , queue/index invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-08","heading":"ORA-08 Dispute and settlement boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The settlement deadline is exclusive: disputes require the current clock to be strictly before the deadline, while settlement is available at and after it. Example: At timestamp deadline , a new dispute is rejected and settlement is allowed. Type Safety Enforcement status Contract guard Primary evidence settle and dispute validation , exact settlement-deadline test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-09","heading":"ORA-09 Oracle balance-domain boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Direct REP or WETH held by the coordinator is outside OpenOracle and remains untouched by settlement or recovery. OpenOracle credits balances by beneficiary rather than by report: the callback sends the coordinator's entire withdrawable internal REP and WETH credit to the recorded pending sponsor, including any third-party deposit that names the coordinator as beneficiary. Example: REP transferred directly to the coordinator remains there, while REP deposited into OpenOracle for the coordinator is swept with the report proceeds to the current sponsor and leaves only OpenOracle's balance sentinel. Type Conservation Enforcement status Reviewed preservation Primary evidence pendingReportSponsor and _withdrawOpenOracleReporterBalances , deposit and withdrawTo , coordinator/OpenOracle balance-domain test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auctions","heading":"Truth Auctions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the Truth Auction guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-01","heading":"AUC-01 Bid admission","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Bids are accepted only during the one-week window, at a supported tick whose computed ETH-per-REP price is positive, and at or above the auction's minimum bid size. Example: A bid submitted one second after the one-week window or below the minimum bid size reverts without being recorded. Type Safety Enforcement status Contract guard Primary evidence submitBid , bid-size and tick admission tests , bid and finalize deadline test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-02","heading":"AUC-02 Auction caps","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Final retained ETH never exceeds the ETH raise cap, and total purchased REP never exceeds the REP sale cap. Example: If bids offer 12 ETH against a 10 ETH cap, finalization retains at most 10 ETH, and the rest stays refundable through bid settlement. Type Conservation Enforcement status Contract guard Primary evidence computeClearing and finalize , dual-cap clearing tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-03","heading":"AUC-03 Single-use bid settlement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each bid is settled at most once; claimed state is set before refundable ETH is credited to bidder-specific pull escrow. Settlement never calls recipient code. withdrawPendingEthRefund clears the caller's credit before its only external call, and a rejected transfer reverts the clear. Example: A reverting bidder cannot block settlement or withdraw another bidder's credit. Its own failed pull preserves the complete balance for a later authorized retry. Type Safety Enforcement status Contract guard Primary evidence withdrawBids and refund functions","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-04","heading":"AUC-04 Claim-order independence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Per-bid REP, refund, underwriting-commitment, and bad-debt results do not depend on post-finalization claim order. The fixed cumulative-position rule that produces this is owned by AUC-06 . Example: Alice claiming before Bob gives each vault the same REP, ETH refund, and underwriting commitment as Bob claiming before Alice. Type Conservation Enforcement status Reviewed preservation Primary evidence allocateFromCumulativePosition , order-independent settlement test , cross-tick dust withdrawal-order test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-05","heading":"AUC-05 Allocation and refund reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A zero-demand auction records zero purchased REP. Otherwise, the sum of all winning-bid REP allocations equals the stored aggregate purchase, and each bid's unretained ETH remains refundable. Example: If finalization stores 30 purchased REP, all winning claims together receive exactly 30 REP and every unretained attoETH is refunded. Type Conservation Enforcement status Reviewed preservation Primary evidence Auction settlement , UniformPriceDualCapBatchAuction.finalize and withdrawBids","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-06","heading":"AUC-06 Bidder-vault credits","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Credit. A bid claim keeps purchased REP pool-held and transfers the bid's proportional REP backing units, underwriting commitment , and finalization-to-claim fees from the unassigned position to the bid's recorded vault. These credits add to, rather than replace, that vault's migrated position. Bad debt. The claim also transfers the proportional auction bad debt while the auction-finalization generation is current; after that generation expires, the raw claimed-debt counter advances without crediting stale debt to the vault. Conservation. Each decrease in unassigned backing and commitment equals the corresponding vault credit, and current-generation unassigned debt decreases by its corresponding vault credit. The auction rate is derived only from bounded child-local units, and cumulative credit cannot exceed the finalized denominator. Order independence. Commitment and current-generation bad-debt division dust follows each bid's fixed cumulative ETH position, so each winner's allocation is independent of claim order. A winning dust bid whose REP allocation rounds to zero can still receive a positive fixed-position commitment share. Aggregates. Claiming does not change total or fee-eligible underwriting commitment, active open interest, current-generation total bad debt, retention rate, or aggregate accrued fees. Example: A vault with migrated REP backing units keeps them when settling a winning auction bid. A current-generation claim moves the bid's backing units, deterministic commitment share, proportional bad debt, and accrued fees into that vault while leaving every pool aggregate unchanged. If the generation has expired, the same claim moves the backing units, commitment share, and fees but assigns no old debt. If a dust bid's REP share is zero but its commitment share is positive, claiming that bid alone still credits the commitment. Type Conservation Enforcement status Reviewed preservation Primary evidence Auction-claim settlement , _creditAuctionProceeds , creditForkAuctionVault , claim-ordering reconciliation test , claim-order bad-debt test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-07","heading":"AUC-07 Uniform weak-demand allocation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property In underfunded clearing, qualifying ETH is retained bid ETH offered at or above the cap-implied qualification threshold. The threshold is not an execution-price floor. Qualifying bidders collectively receive maxAttoRepBeingSold in proportion to that ETH at the aggregate effective price underfundedWinningAttoEth / maxAttoRepBeingSold . Each qualifying bid uses its full ETH, and per-bid cumulative floors assign indivisible attoREP, so a dust winner can round to zero REP without changing the aggregate price. With no qualifying ETH, every bid refunds. Example: If Alice supplies 60% and Bob 40% of qualifying ETH, they receive 60% and 40% of the complete REP sale cap subject to deterministic attoREP rounding. Type Conservation Enforcement status Reviewed preservation Primary evidence Truth Auction clearing design , underfundedWinningAttoEth allocation in UniformPriceDualCapBatchAuction , underfunded settlement tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-08","heading":"AUC-08 Forced-ETH-resistant finalization","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Auction finalization succeeds regardless of unsolicited ETH already present in the child pool or forker. This is the auction case of BAL-02 (the forced ETH stays surplus) and LIFE-02 (it cannot block the transition). Example: One attoETH forced into the child before finalization remains surplus and does not change protocol-accounted collateral. Type Liveness Enforcement status Reviewed preservation Primary evidence finalizeTruthAuctionRepair , forced-ETH bidding and finalization tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-09","heading":"AUC-09 Value-free finalization liveness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property At and after the auction deadline, finalization succeeds without added ETH, and a finalization call carrying ETH reverts. Qualifying bids then settle for REP and non-qualifying bids refund. The collateral the child activates with is owned by FORK-12 . Example: Exactly at the deadline, finalizeTruthAuction with no value succeeds, and the same call with 1 attoETH attached reverts with No repair ETH . Type Liveness Enforcement status Contract guard Primary evidence SecurityPoolForker.finalizeTruthAuction , finalizeTruthAuctionRepair , finalization deadline and no-donation tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-10","heading":"AUC-10 Persistent tick bid history","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Bid cumulative ETH remains append-only for a tick even when the active AVL node is deleted and later recreated. Refunded history is subtracted exactly once, so every later accepted bid retains a valid allocation or refund path. Example: Deleting an empty price tick and later bidding at that price continues cumulative ETH after the old history instead of making the new bid unclaimable. Type Conservation Enforcement status Reviewed preservation Primary evidence _appendBid and refund-prefix accounting and repeated tick deletion/recreation tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-11","heading":"AUC-11 Auction tree and public-model equivalence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before finalization, active tick pages contain exactly the nonzero ticks not removed by pre-finalization refunds, in descending order, and clearing computed from the AVL tree equals an independent calculation over those bids. Finalization freezes that tree and clearing result: later claims change bid flags and ETH liabilities but not active tick pages. Post-finalization liabilities are owned by AUC-12 . Historical insertion and refund-prefix obligations are owned by AUC-10 . Example: Before finalization, an independent descending-tick scan returns the same clearing result as the contract. After a winner settles, its bid is marked claimed and any refund moves to pull credit, while the final clearing page and result remain unchanged. Type Safety Enforcement status Reviewed preservation Primary evidence AVL tree and clearing , enumeration and auction integration , seeded independent-model and frozen-snapshot tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-12","heading":"AUC-12 Auction ETH liability conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before finalization, auction ETH equals active unrefunded bids plus aggregate pendingEthRefundsAttoEth and derived surplus. After finalization, the remaining balance equals refunds still attached to unclaimed bids plus credited pendingEthRefundsAttoEth and derived surplus. Settling a refund moves value between those two liabilities without transferring ETH; only an authorized pull reduces the balance. Per-bid settlement partitions and aggregate REP allocation are owned by AUC-05 . Example: Before finalization, settling a 2 ETH losing bid removes it from active clearing and adds a 2 ETH bidder credit, leaving raw auction ETH unchanged until that bidder pulls it. Type Conservation Enforcement status Reviewed preservation Primary evidence finalize , withdrawBids , and credited refunds , seeded and pull-refund ETH-liability tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"lifecycle","heading":"Lifecycle, liveness, observability, and external calls","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A02 viable operating costs , A16 timely inclusion , A06 lifecycle executors , and A26 Ethereum execution .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-01","heading":"LIFE-01 Pool state transitions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Pool state topology permits only Operational → PoolForked for a parent and ForkMigration → ForkTruthAuction → Operational for a child. Example: A child cannot move directly from ForkMigration to Operational ; even when no repair auction is needed, startTruthAuction enters ForkTruthAuction and finalizes in the same transaction. Type Safety Enforcement status Reviewed preservation Primary evidence SystemState , fork transitions ; see FORK-12 for child accounting consistency.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-02","heading":"LIFE-02 Permissionless transition liveness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once a resolution, migration, auction-completion, or withdrawal function's documented semantic preconditions hold, dust, unsolicited balances, empty collections, or earlier permissionless calls cannot permanently prevent some caller from completing it. Example: Forced ETH and an empty losing-bid list do not prevent a caller from finalizing an otherwise complete Truth Auction. Type Liveness Enforcement status Reviewed preservation Primary evidence FORK-04 , BAL-02 , and AUC-08 ; named LIFE-02 fixed-point and stateful lifecycle regressions , forced-balance and zero-demand auction regressions , and oracle recovery and empty-vault regressions","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-03","heading":"LIFE-03 Atomic failure behavior","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An uncaught revert rolls back every state mutation and transfer in the transition. Deliberately consumed failures, which commit an explicit failed result instead, are owned by ORA-04 . Example: If a child migration reverts after an attempted token transfer, neither the transfer nor its accounting update remains committed. Type Safety Enforcement status Reviewed preservation Primary evidence EVM revert semantics, OpenOraclePriceCoordinator.executeStagedOperation consumed-failure paths","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-04","heading":"LIFE-04 Deadline equality rules","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every deadline assigns equality to one side of the boundary. These entries own their boundaries: FORK-05 (pool migration stays open at equality; auction start opens afterward), AUC-01 (bidding closes at equality, when finalization opens), ORA-03 (cached prices are stale at equality), and ORA-08 (OpenOracle disputes close and settlement opens at equality). The remaining boundaries are: A universe fork and the first escalation deposit are both allowed at question-end equality. Staged operations remain executable through equality and expire afterward. An escalation result becomes final only after its end timestamp. ERC-2612 permits include equality, while ERC-3009 authorizations use a strict validity window. Example: Exactly at a question's end time, both forkUniverse and the first depositToEscalationGame succeed; one second earlier, both revert. Type Safety Enforcement status Contract guard Primary evidence question-end fork boundary , initial-reporting boundary , migration and auction boundaries , escalation finality boundary , cached-price and staged-operation boundaries , and OpenOracle dispute and settlement boundary","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-05","heading":"LIFE-05 Bounded transition work","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property No mandatory transition iterates over the whole deposit, bid, or vault history in one transaction; callers use bounded pages, fixed outcome sets, proofs, or balanced-tree traversal. Work is not constant in fork depth. Computing a carried claim's payout calls getUnresolvedClaimInterval on each source game between the claiming game and the game where the deposit was made, so its gas grows linearly with the number of forks the deposit has been carried across. The contracts enforce no maximum fork depth. The lookups that stay depth-independent are listed in EXT-05 . Example: Settling one carried deposit verifies one proof and makes one interval call per ancestor game; it does not iterate over the other deposits in those games. Type Liveness Enforcement status Reviewed preservation Primary evidence SecurityPool.getVaults , auction bid pages and AVL traversal , MerkleMountainRange proofs , EscalationGameClaimDelegate.getUnresolvedClaimInterval","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"obs-01","heading":"OBS-01 Event-state replay equivalence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Ordered canonical events reconstruct the same universe, pool, vault, coordinator, and escalation carry state exposed by storage. Replay isolates contract-local counters and recognized emitters, and every replay-supported state transition emits the checkpoint or delta needed to reach its resulting storage value. Example: Replaying seeded pool and vault operations matches their accounting storage, while replaying a deployed parent deposit, fork snapshot, and child carry checkpoint matches the child's roots, peaks, leaf counts, unresolved totals, and nullifier roots. Type Safety Enforcement status Reviewed preservation Primary evidence contract interaction reference , event replay model , actual-log storage-equivalence tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-01","heading":"EXT-01 Genesis token behavior boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Genesis REP and configured WETH obey the token accounting model defined, per network, by security assumption A21 . Type Conservation Enforcement status External assumption Primary evidence Security assumption A21","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-02","heading":"EXT-02 Callback-safe accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property External ETH or token callbacks observe effects already committed for that action. A required delivery that fails reverts without leaving partial accounting; an explicitly deferrable delivery instead commits the action together with an exactly accounted recipient liability. Example: A fee recipient's fallback observes its claimable fees already cleared, so reentry cannot redeem the same claimable fees twice. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPool.redeemFees , UniformPriceDualCapBatchAuction.withdrawPendingEthRefund , OpenOraclePriceCoordinator refund paths , rejecting-sponsor refund rollback test Related assumption A22 asset-recipient compatibility","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-03","heading":"EXT-03 ERC-1155 callback safety","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property ERC-1155 receiver callbacks cannot mint beyond pool capacity, alter the amount minted, or reenter the same accounting effect twice. Example: A receiver callback during complete-set minting cannot call back into the pool and reuse the same ETH capacity for a second mint. Type Safety Enforcement status Reviewed preservation Primary evidence createCompleteSet wrapper , createCompleteSet accounting , ERC-1155 receiver acceptance and rejection tests Related assumption A22 asset-recipient compatibility","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-04","heading":"EXT-04 Same-block deadline ordering","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Transaction ordering within a block cannot move an action across a deadline. The equality assignments owned by LIFE-04 depend only on the block timestamp, so mutually exclusive before-deadline and after-deadline actions cannot both succeed at one timestamp. Example: At the OpenOracle settlement deadline, ordering a dispute before settlement in the block still cannot make the dispute valid. Type Safety Enforcement status Contract guard Primary evidence ORA-08 , same-block dispute and settlement ordering , same-block staged execution and expiry ordering , and same-block migration, bidding, and finalization ordering","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-05","heading":"EXT-05 Depth-independent lineage lookups","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Origin registration, inherited-fork detection during child construction, and direct-claim replay checks do not traverse universe or pool ancestry. Carried-claim payout reads are not covered: their cost grows with fork depth, as LIFE-05 states. Example: At lineage depths 1 and 32, a replay query for the same global deposit id performs the same lineage-registry and claimed-id lookups rather than 1 or 32 parent calls. Type Liveness Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory.getOriginId , getPoolId , and getSecurityPoolHasInheritedForkOutcome , SecurityPoolForker.getEscalationDepositId and isEscalationDepositClaimedDirectly , depth-independent replay gas test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["assumptions","security","threats","guarantees"],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Statoblast and Zoltar enforce accounting, authorization, and lifecycle rules onchain. Their economic safety and practical liveness still depend on the participant, market, asset, deployment, client, data, Ethereum, and cryptographic assumptions below. An assumption is not a guarantee enforced by the contracts. Each entry says what must remain true, what can fail if it does not, and where the related mechanics are explained. The Statoblast and Zoltar invariants catalog lists contract-enforced properties and their implementation evidence. Participation and coordination Forks, truth, value, and liquidity Oracle correction, inclusion, and operational data Assets, clients, deployment, Ethereum, and cryptography Guarantees deliberately not made","title":"Statoblast security model","topic":"Safety","weight":1},{"fragment":"orientation","heading":"Security-model orientation","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The assets and state at stake are REP , ETH settlement collateral , outcome shares , vault backing, Escalation Game deposits, child-universe accounting, and the integrity of event-derived state. Boundary Examples Trusted protocol components Zoltar, SecurityPools , share tokens, price coordinators , forkers , and their configured delegates. External dependencies OpenOracle , WETH/REP token behavior, Ethereum execution and finality, RPCs, wallets, and proof data. Untrusted actors Traders, vault owners, liquidators, disputers, bidders, settlers, keepers, and indexers. Failure outcomes Reverted calls, delayed transitions, underfunded child repair, stale prices, incorrect external data, or unreconstructable history. The assumptions below explain what must remain true for these assets and transitions to retain their intended safety or liveness properties; they are not additional contract guarantees.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"security-review-orientation","heading":"Reviewing an operational concern","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"To classify an economic or liveness concern, find its external dependency in the grouped assumptions below and follow that entry's mechanics links. Contract-enforced properties are in the invariant catalog; fork-depth gas behavior, for example, is LIFE-05 and EXT-05 . Operator work relies particularly on these assumptions: A06 lifecycle executors A15 intended question selection A20 chain-data and proof availability A22 asset-recipient compatibility A23 verified deployments A24 client, RPC, and wallet integrity A25 safe immutable parameters A26 Ethereum execution and finality A27 cryptographic security A28 account authority","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-participation","heading":"Participation and coordination","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions explain why someone performs the economically useful action instead of merely being permitted to perform it.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a01","heading":"A01 Participants act on risk-adjusted economic incentives","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Enough participants prefer actions with greater expected value after gas, fees, delay, capital lockup, and risk. The model does not rely on altruistic defense. Failure boundary: A nominally profitable liquidation, dispute, bid, migration, or fork defense may not happen when its risk-adjusted return is unattractive. Mechanics: economic roles , liquidation incentives , auction clearing , and oracle incentives .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a02","heading":"A02 Required actions remain worth their operating costs","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For each time-sensitive action, transaction fees, opportunity cost, coordination cost, and capital lockup remain small enough relative to the value protected or earned. Failure boundary: An action can be technically executable but economically abandoned before its deadline. Mechanics: Truth Auction lifecycle , oracle gas parameters , and Escalation Game lifecycle .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a03","heading":"A03 Each economic role has enough independent participants","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Trading, liquidation, escalation, migration, auction bidding, price correction, and settlement have enough non-colluding participants for the relevant action. Secondary-market trading is external to Statoblast. Failure boundary: Thin or controlled participation can remove price discovery, competitive bidding, or an opposing outcome deposit. Mechanics: economic roles , fork coordination , and auction participation .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a04","heading":"A04 Participants can mobilize REP to raise an alarm","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Market participants can mobilize enough REP, from a wallet or from vault backing through its vault owner, to fund an early competing Invalid , Yes , or No deposit and keep the local contest active while additional capital reacts. Wallet REP cannot fund a deposit in a fork-continuation game. Failure boundary: A wrong local outcome can become final before better-capitalized participants enter. Mechanics: escalation resolution , escalation accounting , and escalation guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a05","heading":"A05 Participants value continued access to the supported Statoblast lineage","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The participants whose coordination determines durable use value continued access to the supported Statoblast lineage at least as highly as its configured statoblastSecurityMultiplierBps basis points of the value secured by that lineage. BPS_DENOMINATOR = 10_000 converts that stored value to its human multiplier. Value Statoblast access × BPS_DENOMINATOR ≥ statoblastSecurityMultiplierBps × Value secured Compare one lineage’s continued-use value and secured value at the same pre-attack time. Failure boundary: Participants may rationally abandon, grief, or coordinate away from a lineage whose continued-use value is too small. Mechanics: fork security , fork migration , and Statoblast security boundary .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a06","heading":"A06 At least one executor advances every required public transition","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"An adequately funded participant or service monitors and calls each needed permissionless transition, including liquidation initiation, local escalation deposits and settlement, fork activation, child creation, vault and share migration, auction start and finalization, bid settlement, OpenOracle report settlement, settled-report callback recovery, overflow operation execution, and proof-based claims. Failure boundary: Permissionless state can remain stalled even though no contract authorization prevents progress. Mechanics: lifecycle liveness , fork migration guardrails , and oracle guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-forks","heading":"Forks, truth, value, and liquidity","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions connect onchain branching and accounting to offchain truth judgments, asset value, liquidity, and migration.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a07","heading":"A07 A supported lineage preserves enough aggregate child value","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For each protected Statoblast origin lineage, evaluate the parent and its child-pool continuations in one numeraire at the fork-security decision horizon, before long-run value has fully concentrated on one branch. The sum of traded child-lineage values remains large enough compared with that parent lineage’s pre-fork value under the origin’s immutable statoblastSecurityMultiplierBps . Each child asset is valued in its own branch; unrelated external collateral is not counted again. Value parent lineage ≤ ∑ child ∈ Lineage continuations Value child × BPS_DENOMINATOR statoblastSecurityMultiplierBps lineage Parent and child values use the same origin lineage, valuation source, numeraire, and decision horizon. For multiplier 20_000 BPS , aggregate child-lineage value must be at least twice parent-lineage value; multiplier 30_000 BPS requires three times that value. Failure boundary: Value destruction or fragmentation can make a malicious or unnecessary fork cheaper than the harm it causes. Mechanics: fork economics , fork coordination , and pool migration .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a08","heading":"A08 REP market capitalization approximates economic value","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At the stated valuation time and system scope, REP market capitalization is a sufficiently accurate observable proxy for the discounted cash flow participants expect from REP. Failure boundary: Thin, manipulated, or speculative pricing can overstate the economic value securing open interest. Mechanics: REP economics and economic backing claims .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a09","heading":"A09 Users value the universes they judge truthful","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users prefer the universe or universes they judge truthful, so economic activity and durable asset value concentrate there. Unlike A07’s fork-security decision horizon, this assumption describes the later, durable allocation of value after users coordinate. Value before fork ≈ Value truthful universe When several branches remain plausibly truthful, document the value split instead of assuming one winner. Failure boundary: Coordination on a false branch, or durable fragmentation across branches, defeats the value-concentration security argument. Mechanics: branch non-guarantees and pool fork migration .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a10","heading":"A10 Participants can access timely outcome evidence","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users can obtain enough reliable real-world evidence before the relevant protocol deadline to judge which universe is truthful. Failure boundary: Missing, delayed, or conflicting evidence can split honest capital or let a false local outcome become final. Mechanics: question encoding , invalid outcomes , and local resolution .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a11","heading":"A11 Migration is operationally practical","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users, exchanges, interfaces, custodians, and other integrations are willing and able to migrate assets and state into the child universe or universes they support during the applicable windows. Failure boundary: Supported branches can remain illiquid or undercollateralized because economic claims and backing do not move there. Mechanics: REP splitting , pool migration , and share migration guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a12","heading":"A12 Truth Auctions can convert supported child REP efficiently","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"When repair is needed, enough Truth Auction demand can buy some supported child REP for ETH at an acceptably small discount and operating cost. This does not assume that the full repair target is raised. Failure boundary: Weak or strategically withheld demand leaves the child operational with impaired collateral. Mechanics: auction lifecycle , clearing , and repair accounting .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a13","heading":"A13 REP is sufficiently liquid","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants can acquire or sell the required REP quantities without price impact or delay large enough to invalidate reporting, disputing, liquidation, auction, or migration economics. Failure boundary: Capital may exist in principle but cannot be assembled at a usable price before the deadline. Mechanics: economic roles , escalation , and oracle positions .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a14","heading":"A14 REP economic value exceeds the open interest it secures","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For a stated pool, lineage, or system scope at one timestamp, open interest and REP discounted cash flow are valued in the same numeraire, and REP discounted cash flow remains strictly greater. For a pool-level evaluation, open interest means the pool’s protocol-accounted ETH collateral unless the analysis explicitly names a broader exposure measure. The REP supply and price basis must also be stated; market capitalization is the observable proxy in A08 . This external relationship is separate from each pool’s onchain multiplier-adjusted REP backing check. Open Interest < Discounted Cash Flow REP Record scope, timestamp, common numeraire, price source, REP supply basis, and open-interest definition when evaluating this strict inequality. Failure boundary: REP holders may rationally accept or cause losses larger than the durable REP value placed at risk. Mechanics: security pools , liquidation backing , and oracle exposure analysis .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a15","heading":"A15 Question selection remains aligned with user intent","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Interfaces and users verify the immutable question ID and metadata when selecting a market or pool, and the question has evidence and wording from which participants can reach an outcome or intentionally choose Invalid . Failure boundary: Unverified selection can route users and capital to an unintended market or pool, while ambiguous wording or unavailable evidence can split local outcome coordination. Mechanics: UNI-02 and question identity .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-oracle","heading":"Oracle correction, inclusion, and operational data","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions cover truthful REP/ETH price discovery, deadline access, capital, independent correction, and the offchain information required to act. OpenOracle's optional flexible-escalation and halt-only-fee flags can change a corrector's required capital and net incentive, so a deployment that enables them must evaluate the same assumptions against its configured flag set.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a16","heading":"A16 Deadline transactions can obtain Ethereum inclusion","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Honest users can submit competitively priced Ethereum transactions and obtain canonical inclusion within every relevant dispute, escalation, migration, auction, staging, and settlement window. Each onchain comparison assigns the exact deadline timestamp to one phase. Same-block ordering cannot move an action across that boundary: users must target the phase valid at the block timestamp rather than rely on transaction ordering to extend an expired window. Failure boundary: Censorship or congestion lasting through a deadline can finalize a wrong report or prevent a supported action. Mechanics: deadline invariants , auction windows , and oracle censorship model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a17","heading":"A17 OpenOracle has an available, adequately capitalized corrector","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At least one OpenOracle participant continuously monitors pending REP/ETH reports, can identify candidate errors using the reference market in A19 , can fund the scenario-dependent WETH and REP replacement position plus transaction costs, and can obtain inclusion before settlement. The participant's net incentive to perform the correction is the separate boundary in A18 . Failure boundary: An incorrect report can settle and authorize price-sensitive pool actions when no capable participant detects, funds, and includes a correction. Mechanics: REP/ETH oracle , correction incentives , and attack model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a18","heading":"A18 At least one available corrector has an independent net incentive","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At least one participant satisfying A17 is not under common control with the sponsor-funded coordinator reporting path, does not share the manipulation payoff, and is not bribed or compensated. The participant's net payoff from correcting is strictly greater than its net payoff from leaving the harmful report uncorrected. Two external submissions are not required for every request. Failure boundary: A sponsor-controlled, bribed, or economically indifferent corrector can make the contestable report path behave like a single trusted reporter. Mechanics: settlement validation scope , economic tradeoffs , and oracle invariants .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a19","heading":"A19 A robust reference market makes harmful REP/ETH errors correctable","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Independent participants can observe a manipulation-resistant reference REP/ETH price. Every price error large enough to unlock a security-relevant pool action also leaves a correction opportunity that remains profitable after actual gas, prevailing priority fees, OpenOracle fees, price impact, and required capital lockup. Failure boundary: A harmful deviation below the profitable correction threshold, or a manipulated/illiquid reference market, can settle without an economically rational challenge. Mechanics: report sizing , external-payoff model , and settlement limits .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a20","heading":"A20 Canonical chain data and proof construction remain available","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants can access reorg-aware Ethereum history, recognized contract addresses, OpenOracle report state, and the event data needed to construct carry and nullifier proofs before use. Failure boundary: A valid dispute, settlement, migration, or inherited claim can become practically unavailable even while its contract entrypoint remains live. Mechanics: event replay , carry proofs , and operator orientation .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-technical","heading":"Assets, clients, deployment, Ethereum, and cryptography","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions define the technical foundation below the protocol’s onchain guards.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a21","heading":"A21 Genesis REP and configured WETH obey the required accounting model","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Genesis REP and configured WETH move exactly the requested base units, use 18 decimals, return supported ERC-20 values, and do not rebase, charge transfer fees, invoke unexpected callbacks, blacklist protocol contracts, pause required transfers, or permit unauthorized minting. WETH remains redeemable 1:1 for ETH, the genesis theoretical supply is accurate, and the hard-coded Constants.BURN_ADDRESS burn sink remains inaccessible. These are external assumptions on both networks, with one exception: on Sepolia the reviewed GenesisReputationToken enforces genesis REP issuance and transfer behavior, provided A23 verifies its deployed bytecode and wiring and A26 preserves Ethereum execution. Sepolia WETH is Uniswap's published contract, which the deployer verifies only by runtime-code hash. Canonical child REP is the reviewed ReputationToken contract and adds no external-token assumption. Failure boundary: Origin-pool, genesis-fork, or oracle accounting can overstate balances, backing, burned supply, or WETH value. Mechanics: EXT-01 and oracle token pair .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a22","heading":"A22 Participant-controlled recipients can accept required asset deliveries","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Vaults, oracle sponsors, traders, share holders, and other caller-controlled recipients use addresses that accept native ETH when claiming fees, collateral, or proceeds. Truth-auction settlement instead credits bidder-specific pull escrow without calling the bidder; the bidder must accept ETH only when withdrawing that credit. Contract recipients also return the required ERC-1155 receiver selector when complete-set creation, share migration, or an outcome-share transfer delivers tokens to them. A rejected ETH pull or push reverts that transfer, and a rejected ERC-1155 callback reverts the mint or transfer and its surrounding protocol action. No protocol path can force a rejecting address to accept a later delivery or redirect every payout or mint. Failure boundary: A contract account that rejects ETH or the required ERC-1155 callback can strand its own payout or make its complete-set, migration, transfer, or claim action unavailable even while protocol-wide accounting remains safe. Mechanics: ETH callback safety , ERC-1155 callback safety , share-token receipt , auction refunds , oracle request refunds , and security pool guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a23","heading":"A23 Users select verified canonical deployments","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The reviewed release is built reproducibly with its pinned compiler and toolchain configuration. The deterministic manifest freshness check rejects address drift, while the deployment plan verifies pinned runtime-code hashes for planned contracts and bootstrap descendants. Users and integrations must still verify post-deployment wiring, factory and forker provenance, pool lineage, question ID, and the manifest against the intended network. Constructor admission alone is not a safety proof. Failure boundary: Toolchain drift, unavailable or mismatched reviewed hashes, permissionless lookalike instances, wrong dependencies, or unintended lineage and question wiring can bypass the reviewed protocol even when the selected bytecode functions as configured. Mechanics: release posture , deployment status , compiler configuration , OpenOracle build provenance , and authority invariants .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a24","heading":"A24 Clients, RPCs, and wallets preserve user intent and canonical state","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Interfaces, indexers, RPC providers, and wallet software return canonical, reorg-aware state; construct and display the intended chain, target, calldata, parameters, and ETH value; and submit only transactions the user authorizes. Users verify transaction previews rather than treating an application label as an onchain guarantee. Failure boundary: Compromised or stale offchain software can misroute signatures or capital, hide deadlines or events, or cause users to authorize valid but unintended calls without violating contract guards. Mechanics: deployment discovery , contract interactions , and operator verification .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a25","heading":"A25 Immutable parameters preserve economic and executable security margins","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The selected parameter relationships keep the fork threshold and fork haircut economically meaningful, the start bond affordable, the pool multiplier and the pool-held-REP branch multiplier derived from it ( BAL-04 ) large enough for their distinct coverage roles, the oracle target error profitable to correct after fees and gas, dispute and settlement windows usable, and callback and transition gas executable. The Statoblast pool statoblastSecurityMultiplierBps is distinct from openOracleSecurityMultiplierBps . Failure boundary: Weak or internally inconsistent immutable parameters can defeat the economic or liveness argument even when the canonical contracts function exactly as configured. Mechanics: Statoblast pool parameters , fork economics , liquidation economics , oracle parameters , and oracle attack model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a26","heading":"A26 Ethereum preserves the execution environment the protocol relies on","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Ethereum continues to provide correct EVM execution and atomic rollback, sufficient canonical finality, usable timestamp and block.basefee semantics, and block gas limits and gas schedules under which every mandatory immutable transition remains executable. Failure boundary: Deep reorganizations, invalid state execution, adversarial time behavior, or gas repricing can reverse accepted state or strand required transitions. Mechanics: contract interactions , atomicity and deadlines , and Escalation Game lifecycle .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a27","heading":"A27 Ethereum cryptographic primitives remain secure","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Keccak-256 remains collision- and preimage-resistant at the truncated widths used by the protocol, and CREATE2 identity remains sound. secp256k1 ECDSA signatures remain unforgeable with correct EOA signer recovery for Ethereum transactions and EIP-712 authorizations. OpenOracle's fixed Permit2 singleton and LiquidationApprovalRegistry.permitLiquidationApproval , through SignatureValidation , additionally validate either an EOA signature or an ERC-1271 contract-account signature correctly. OpenOracle fixes the Permit2 address, requires the exact permitted amount, sends the requested tokens to itself, and constructs the witness from the beneficiary, relayer, token owner, and intent. Permit2 defines the EIP-712 domain, deadline, permitted-amount ceiling, unordered-nonce replay protection, and EOA/ERC-1271 signature validation. Verification under A23 must cover the pinned Permit2 implementation at that fixed address. Failure boundary: Forged identities, colliding questions or universes, false carry proofs, forged EOA transactions, incorrect EOA recovery or ERC-1271 acceptance, or broken domain and nonce enforcement can violate otherwise-correct guards or authorize an unintended token transfer. Mechanics: universe identity , proof hashing , Permit2 deposit authorization , Permit2 signature interface , liquidation-approval signature validation , pinned Permit2 implementation provenance , and deterministic address guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a28","heading":"A28 Participants retain control of account authority","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants protect the private keys, signing devices, session permissions, and delegated ERC-20 or ERC-1155 approvals that authorize their accounts. Account recovery and custody arrangements do not give an unintended party effective control during a security-sensitive window. Failure boundary: A stolen key, compromised signer, or overbroad approval can authorize valid but unwanted transfers, deposits, bids, migrations, or configuration changes without violating a contract guard. Mechanics: transaction authority , security pool guardrails , and account-authority monitoring .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"excluded-guarantees","heading":"Guarantees deliberately not made","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These outcomes remain possible without contradicting the security model. They should be included in user, operator, and integration risk disclosures. EG01. Zoltar creates valid branches but does not enforce that the fork question is relevant to a user, establish the objectively truthful branch, obtain user consent to a fork, or force users to coordinate on one branch. EG02. A Truth Auction may raise less than its repair target; the child then activates with migrated collateral plus accepted auction ETH. EG03. OpenOracle report liquidity does not cap the notional value of operations using an accepted price, and settlement does not prove external price correctness. EG04. A participant with unbounded capital can keep funding valid disputes and delay the sponsor lane indefinitely; no bounded coordinator-availability claim is made. EG05. The immutable protocol has no administrator who can pause, upgrade, roll back, or rescue an unsafe deployment after launch. EG06. Escalation principal and expected rewards are not senior to open-interest repair. A child Truth Auction may proportionally reduce them, and a losing escalation claim pays its committed depositor nothing.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["testnet","Sepolia","deploy","private key","spending limit"],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"How-to guide The testnet deployer installs the complete deterministic Zoltar and Statoblast infrastructure in one run. It is safe to rerun: a contract already at its target address is skipped only when its runtime bytecode matches, and an unexpected contract at a target address stops the deployment.","title":"Deploy testnet contracts","topic":"Operations","weight":1},{"fragment":"before-you-deploy","heading":"Before you deploy","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Complete the repository setup in the README . Use a dedicated testnet account. To size its balance without deploying, run the deployer once with --max-total-cost-eth=0.000001 : its preflight aborts and the abort message reports the upper-bound cost of the missing steps. A normal run prints the same figure in its Estimated maximum cost log line. Use an HTTPS RPC endpoint. Loopback HTTP endpoints are accepted for local test networks. Make sure the deployer account has no pending transactions. If the testnet rejects the fixed raw legacy transactions that install the canonical CREATE2 deployer and the proxy deployer, make sure both are already present as predeploys. Sepolia is the default target (chain ID 11155111 ). A different testnet must support EIP-1559, the Cancun opcodes used by Zoltar and Uniswap V4, and the Osaka CLZ opcode used by the compiled contracts. The deployer rejects Ethereum mainnet (chain ID 1 ).","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"deploy-with-github-actions","heading":"Deploy with GitHub Actions","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Use the Deploy Testnet Contracts workflow for a deployment from main . Create a protected GitHub environment named testnet-deployment . Add the deployer's private key as the environment secret TESTNET_DEPLOYER_PRIVATE_KEY . Optionally add ETHERSCAN_API_KEY as well; without it post-deploy verification skips Etherscan. Open Actions → Deploy Testnet Contracts → Run workflow . Select main , complete the inputs, and enter DEPLOY as the confirmation. Review the job summary for each planned deployment's result and address. It includes transaction hashes for contracts deployed during the run. The job runs only when the workflow is started from main and the confirmation is exactly DEPLOY . Otherwise GitHub skips it without an error and no summary is produced; if the run shows a skipped job, check the branch and confirmation and start it again. Use a public RPC URL without credentials. Workflow inputs are stored in GitHub metadata and are not secret.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"deploy-locally","heading":"Deploy locally","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Load PRIVATE_KEY from a secret manager or a hidden prompt. Never paste the key into a command, because the command may be saved in shell history. In Bash: read -rsp 'Testnet deployer private key: ' PRIVATE_KEY \\ && echo && export PRIVATE_KEY Run the deployer with an explicit RPC endpoint and spending limits: bun run deploy:testnet -- \\ --rpc-url=https://rpc.example \\ --chain-id=11155111 \\ --max-fee-per-gas-nanoeth=100 \\ --max-total-cost-eth=20 Remove the key from the shell when the command finishes: unset PRIVATE_KEY The deployer reads the exported PRIVATE_KEY automatically. You can instead pass --private-key=0x... directly, but then the complete command, and therefore the key, may be saved in shell history. Run bun run deploy:testnet -- --help for all options. Options other than --private-key also accept uppercase arguments after -- or environment variables. Input Default Purpose RPC_URL / --rpc-url Required RPC endpoint for the target network CHAIN_ID / --chain-id 11155111 Expected decimal chain ID MAX_FEE_PER_GAS_NANO_ETH / --max-fee-per-gas-nanoeth 100 Rejects higher RPC fee suggestions. If a canonical deployer is missing, the run aborts when this is below 100 , the fixed gas price of the deployers' raw transactions. MAX_TOTAL_COST_ETH / --max-total-cost-eth 20 Caps the conservative preflight estimate and transaction budget PRIVATE_KEY / --private-key Required 0x -prefixed 32-byte deployer key The defaults are authorization limits, not a spend forecast or a required balance. Before sending a transaction, the command checks the RPC chain ID, EVM features, EIP-1559 support, canonical deployer compatibility, expected bytecode, and fee limits. It then estimates only the missing deployment steps. If the conservative estimate exceeds MAX_TOTAL_COST_ETH , it exits; on a live network nothing has been funded or deployed at that point, while an Anvil development node may already have received the replayed Uniswap contracts. Per-transaction checks enforce the same budget while the deployment runs. The run logs each planned contract with Status: deployed , Status: already deployed , or Status: ready (installed without a submitted transaction), then verifies the bootstrap support contracts. A step that fails logs Status: failed and stops the run. When deployment succeeds, the command runs source verification for the target chain. Only Sepolia ( 11155111 ) is verified; any other chain logs that it has no known explorer support and succeeds. Verification submits the addresses in the tracked docs/sepolia-deployment-addresses.json manifest, not addresses discovered during the run. Blockscout and Sourcify run without a key; Etherscan runs only when ETHERSCAN_API_KEY is set and is otherwise skipped with a message. A verification failure makes the command exit nonzero even though the contracts are deployed , and prints the command to retry on its own: bun run verify:contracts -- --chain-id=11155111 . Treat a nonzero exit as \"check which stage failed\" rather than \"nothing was deployed\".","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"recover-an-interrupted-run","heading":"Recover an interrupted run","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Wait for all pending transactions to settle, then rerun the same command. The deployer revalidates completed contracts and resumes with the first missing step.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"what-gets-deployed","heading":"What gets deployed","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"deterministic genesis REP the canonical CREATE2 deployer, the proxy deployer, and Permit2 a deterministic Uniswap V3 SwapRouter on chains other than Sepolia, deterministic WETH and a complete Uniswap deployment (V3 factory, QuoterV2, V4 PoolManager, and V4 Quoter) the Zoltar and Statoblast protocol factories and their bootstrap support contracts the Trading factory and router, at the canonical 0.30% fee The command does not create Uniswap pools or add liquidity; protocol factories create market-specific contracts later, when those features are used. Uniswap sourcing per chain is listed in the contract inventory , and the deployment status reference explains how clients read which steps are installed. The bots read core addresses from the tracked mainnet and Sepolia manifests, so on testnets they work only against Sepolia and Sepolia replays such as a local Anvil node with chain ID 11155111 . A deployment to another testnet is not usable by the bots until that chain has a generated manifest.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["release","launch","checklist","genesis REP","manifest"],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"How-to guide Follow this guide before tagging a Zoltar and Statoblast release. It lists the checks that must pass before the tag and, for Sepolia and deterministic testnets, the genesis REP review that determines every deterministic address there. Mainnet uses the existing REPv2 token and deploys no genesis REP.","title":"Prepare a protocol release","topic":"Operations","weight":1},{"fragment":"immutable-protocol-release-posture","heading":"Know what a release cannot do","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"The contracts are immutable: no operator can pause, upgrade, roll back, or rescue them after deployment, so a release publishes verifiable provenance instead (commit and tag, deterministic addresses, CI and QA results, production UI artifact hash, known limitations) and never describes a UI deployment as an emergency control. See EG05 .","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"launch-release-checklist","heading":"Run the release checklist","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"From a fresh dependency install ( bun install --frozen-lockfile ), run bun run check:mainnet-deployment:generated . It fails when either generated deployment manifest is stale. If so, regenerate both manifests with bun ./tooling/contracts/check-mainnet-deployment.mts --write , which only rewrites mainnet-deployment-addresses.json and sepolia-deployment-addresses.json ; review the diff, then rerun the check. Run bun run ui:build:prod . It repeats the manifest check, so it fails if a manifest is still stale. Confirm the build used the pinned compiler configuration in solidity/ts/compile.ts , the exact tool versions in solidity/package.json , and the imported OpenOracle profile in UPSTREAM.md . Review the pinned runtime-code hashes: the EXPECTED_*_RUNTIME_CODE_HASHES maps in ui/zoltarShared/ts/protocol/deployment.ts and ui/statoblastShared/ts/protocol/deployment.ts . Check them in three ways, then publish the reviewed hashes with the release: Run bun ./tooling/testing/bun-test.mts --preload ./bun-test-setup-ui.ts ui/zoltar/ts/tests/protocol/deployment.test.ts ui/statoblast/ts/tests/protocol/deployment.test.ts . It confirms that a clean local build still matches the pinned hashes of the directly compiled steps (the deployment status oracle, Multicall3, ZoltarQuestionData, and five Statoblast artifacts); it does not cover the other pinned contracts. On Sepolia, rerun bun run deploy:testnet . It checks the runtime code of every installed contract against its pinned hash. It is not read-only: it needs PRIVATE_KEY , deploys any missing step, and then runs explorer verification. For any other deployed address, compare the keccak-256 hash of its eth_getCode result with the pinned hash by hand before marking the release canonical. Push the final tag only after the CI gate succeeds on the same commit. The tag must match v (for example v12 ); the Version deploy workflow rejects any other form. That workflow reruns CI, builds the InterPlanetary File System (IPFS) publisher image, reads the content identifier (CID) from that image, checks only that it has the bafy… form, and creates or updates the GitHub release with that CID in its notes. Confirm the release exists and records the CID before announcing. In the production UI release notes, state that ?simulate=1 is a browser-local sandbox. Treat a stale, unavailable, or unsupported live quote as a blocker for the affected client action; never substitute a simulation price for it.","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"genesis-rep-deployment","heading":"Review genesis REP allocations (Sepolia and deterministic testnets)","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"Sepolia genesis REP allocations are canonical source data in sepoliaRepAllocations.ts . The configured 11 million REP mint cap is divided equally among the listed holders; adding a holder automatically reduces every holder's allocation. Integer division may leave the total minted supply below the cap by less than one attoREP per holder. Review both the holder list and the computed total before deployment. The constructor of GenesisReputationToken rejects an empty list, a zero address, a repeated holder, a zero balance, and a total above the cap. There is no administrator, post-deployment mint, allocation correction, or recovery entrypoint, so fix an incorrect allocation in the source list before deployment and then regenerate the deterministic manifests. Because constructor arguments are part of CREATE2 init code, any allocation change produces a new genesis REP address and new addresses for every deployment step whose constructor wiring depends on it. Never continue a deployment from a manifest generated for a different allocation list.","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["monitoring","assumptions","operators","signals"],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"How-to guide Check that the economic and liveness assumptions behind a deadline-bearing or price-sensitive action still hold before you take it, and keep checking until its last deadline. The contracts cannot tell you when such an assumption has stopped holding.","title":"Monitor security assumptions","topic":"Operations","weight":1},{"fragment":"how-to-use","heading":"Check an action's assumptions","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"List the assumptions the action depends on. The security model lists which assumptions protect which mechanism. Find the rows for those assumptions in the table below . Take each row's reads for the same lineage , pool, and block as the action. Express the values in one numeraire and cover the action horizon . If a read is weak or unavailable, apply the row's response before proceeding. Repeat the reads on the row's cadence until the action's last deadline has passed. Most on-chain reads are also indexed by augurScan under /operations/… (see the augurScan README ). The liquidator and OpenOracle arbitrager bots in bots/ show live pool, vault, and report state in their dashboards.","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"terms","heading":"Terms used in the table","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"Numeraire The one unit of account, such as ETH, in which you express every value you compare. Action horizon The period until the action's last deadline. Corrector An account that disputes an incorrect OpenOracle report; see A17 . Callback-recovery candidate A price coordinator whose pending report OpenOracle has already settled; see settlement recovery . Overflow operation A staged operation outside the next settlement callback's batch of four; see execution batches .","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"assumption-monitoring","heading":"Reads, cadence, and response for each assumption","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"Assumptions What to read Review cadence Response when the boundary is weak or unknown Executor incentives and participation — A01, A02, A03, A06 Liquidation candidates and net reward: liquidator bot dashboard Dispute opportunities and net reward: OpenOracle arbitrager dashboard Active reporters, correctors, escalation depositors, and Truth Auction bidders: augurScan /operations/reports , /operations/escalations , /operations/auctions Callback-recovery candidates: coordinator pendingReportId , then the settlement timestamp in OpenOracle storedGame(reportId) ; anyone can clear one with recoverSettledPendingReport() Overflow operations: coordinator getActiveStagedOperationCount() minus getPendingSettlementOperationCount() Continuously for deadline-bearing flows; before launch and after parameter or gas-regime changes Fund or arrange independent executors, reduce exposed value, or disclose that the affected transition may stall Fork lineage value and migration readiness — A05, A07, A09, A11 Fork start: Zoltar getForkTime(universeId) Migration progress: augurScan /operations/forks Parent and child REP prices: market quotes in one numeraire Custodian, exchange, interface, and proof-tool readiness: each party's published support statement (no on-chain read) Before a fork-security claim and throughout migration and coordination windows Do not claim fork deterrence, practical migration, or value concentration; narrow supported lineage and exposure REP value and liquidity versus secured exposure — A08, A13, A14 Theoretical REP supply : Zoltar getUniverseTheoreticalSupplyAttoRep(universeId) Pool open interest : settlementCollateralAttoEth in getPoolAccountingSnapshot() Pool-held REP: getTotalPoolHeldAttoRep() Cached REP/ETH price: coordinator lastPrice REP depth and price impact: arbitrager Uniswap venue quotes Pool and vault risk: augurScan /operations/risk REP discounted cash flow: off-chain valuation (no on-chain read) At launch, continuously while open interest exists, and after material price, supply, liquidity, or exposure changes Cap or stop new exposure in clients and disclosures; do not describe REP backing as economically sufficient Outcome evidence and escalation funding — A04, A10 Escalation Game deadline: getEscalationGameEndDate() Outcome funding: getOutcomeBalancesAttoRep() and getBindingCapitalAttoRep() , or augurScan /operations/escalations REP available to fund a correction: wallet REP balanceOf (wallet deposits, except in a game carried across a fork) and vault REP backingUnitsToAttoRep(securityVaults(vault).repBackingUnits) of each ready account Outcome evidence: where each source publishes (off-chain) From question creation through local resolution and any fork window Mark the market or action impaired, surface the deadline, and avoid asserting that honest local correction remains fundable Truth Auction demand — A12 Truth Auction bids: auction getActiveTickPage(offset, limit) and previewFinalization() , or augurScan /operations/auctions REP/ETH depth and expected discount: arbitrager Uniswap venue quotes Bidder gas cost: RPC eth_feeHistory Before and during every repair auction Disclose likely incomplete repair and plan operation of the child at only migrated collateral plus accepted auction ETH Transaction inclusion and Ethereum execution — A16, A26 Base and priority fees: RPC eth_feeHistory Block gas limit: latest block Reorg history: augurScan /operations/integrity Escalation deadline: getEscalationGameEndDate() Truth Auction close: auction auctionStarted plus one week Migration close: forker forkData(pool) forkActivationTime plus eight weeks Margin: each deadline minus expected inclusion delay Continuously while a deadline or mandatory transition is live Raise transaction fees where rational, use independent submission paths, and disclose missed-deadline or stranded-transition risk REP/ETH price correction — A17, A18, A19 Pending report: coordinator pendingReportId , then OpenOracle storedGame(reportId) Report outcomes: coordinator PriceRequested , PriceReported , and PriceReportRejected events, or augurScan /operations/reports Independent correctors: whether any, such as an operator running the OpenOracle arbitrager , reports disputes profitable after fees, gas, and price impact Corrector inventory: wrapped Ether (WETH) and REP balances Continuously while a report is pending or a cached price can authorize operations Block or discourage new price-sensitive operations and disclose that an incorrect report may settle Token behavior and recipient compatibility — A21, A22 Sepolia genesis REP code: keccak-256 of eth_getCode against reputationToken in EXPECTED_SEPOLIA_DEPLOYMENT_RUNTIME_CODE_HASHES ( ui/zoltarShared/ts/protocol/deployment.ts ) Sepolia WETH code: the same against sepoliaPublished.weth.runtimeCodeHash in scripts/artifacts/uniswap-deployment.json Mainnet REPv2 and WETH code: an externally sourced reference hash (no repository pin) Sepolia genesis REP supply: shared/zoltar/ts/deployment/sepoliaRepAllocations.ts against getTotalTheoreticalSupply() WETH redeemability and recipient ETH and ERC-1155 acceptance: a test transfer from a disposable account At deployment verification and before first use of a new recipient or integration Reject the deployment or incompatible recipient; do not rely on redirected recovery Deployments, clients, data, and keys — A20, A23, A24, A27, A28 Manifest freshness: bun run check:mainnet-deployment:current Explorer source verification: bun run verify:contracts -- --chain-id= Code presence: getDeploymentMask() Runtime hashes: release checklist Event replay: a second RPC or augurScan /operations/integrity Signers, typed-data domains, nonces, and approvals: each operator's key store At release, on every environment or account change, and continuously for indexers Stop signing or operating, reject an unverifiable deployment, revoke compromised authority where possible, and re-establish canonical state from independent sources Question selection — A15 Question creation, end date, and labels: ZoltarQuestionData questionCreatedTimestamp , getQuestionEndDate , and getOutcomeLabels Evidence plan and pool relevance: off-chain review Before pool selection Reject or warn on the selection; do not represent an admitted question as relevant or resolvable Immutable parameters — A25 Deployed configuration: manifest protocolConfig Fork and non-decision thresholds: Zoltar getForkThresholdAttoRep(universeId) and getNonDecisionThresholdAttoRep(universeId) Oracle costs: coordinator getRequestPriceCostAttoEth() and getSettlementCallbackGasLimit() Required relationships: A25 Before deployment and after any change in external gas or market conditions used by the model Treat the immutable deployment as unsupported; there is no administrative parameter repair","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["operators","guardrails","recovery","edge cases"],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Reference What a Statoblast security pool , share migration, Escalation Game , fork migration, Truth Auction , or REP/ETH price coordinator will and will not accept, one subsystem at a time. Statoblast is the prediction-market layer built on the Zoltar fork oracle; see the system overview . Every rule names the contract source that enforces it, so operators, indexers, and interface maintainers can check it against the exact Solidity. The invariant catalog connects these local guardrails to cross-contract conservation, liveness, and the stated economic assumptions; the security model is normative for external assumptions. Release procedure lives in Prepare a protocol release , assumption monitoring in Monitor security assumptions , and the remaining support contracts in the contract inventory .","title":"Subsystem guardrails","topic":"Safety","weight":1},{"fragment":"security-pool-guardrails","heading":"Security pool guardrails","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"The following pool-creation, minting, withdrawal, and direct-ETH rules are enforced by contracts. Participant-controlled payout and share-receiving addresses must satisfy A22 asset-recipient compatibility . Deterministic identity depends on A27 cryptographic security , while vault and token authority depends on A28 account authority . Area Implementation behavior Source Origin multiplier deployOriginSecurityPool requires statoblastSecurityMultiplierBps above 10,001 BPS ( Multiplier must exceed 10001 BPS ). SecurityPoolFactory.sol Origin question The question must exist ( Question does not exist ), must not have ended ( Question has already ended ), and must have exactly two categorical labels, Yes then No ( Question must have two outcomes , First outcome must be Yes , Second outcome must be No ). Statoblast adds Invalid as the third trading and resolution outcome. SecurityPoolFactory.sol , ShareToken.sol , BinaryOutcomes.sol Origin universe The universe must be unforked ( Universe already forked ) and have a REP token ( Universe REP token missing ). SecurityPoolFactory.sol Origin uniqueness SecurityPoolFactory allows one pool per origin and universe ( Security pool origin and universe already claimed ). The origin is the question, origin universe, security multiplier, and oracle priority fee. SecurityPoolFactory.sol Start-bond admission A new origin's non-decision threshold must exceed its start bond ( Escalation threshold too low ). ESC-13 owns the start-bond formula and its later clamp. SecurityPoolFactory.sol , SecurityPoolUtils.sol Vault REP floor A zero configured vault REP floor selects the live universe theoretical REP supply divided by 100,000; a nonzero constructor value is the exact override. SecurityPoolUtils.sol Commitment floor minimumSecurityBondDebtAttoEth , the smallest nonzero commitment a liquidation may leave with its target or give its receiver, is a nonzero factory constructor argument ( Minimum security bond debt zero ). The default deployment configuration sets it to 1 ETH. SecurityPoolFactory.sol , SecurityPoolOperationsDelegate.sol Deployment history The factory records security-pool deployments and exposes paged deployment-history reads for indexers and UIs. SecurityPoolFactory.sol Pool salt SecurityPoolFactory derives securityPoolSalt = keccak256(abi.encode(parent, universeId, questionId, statoblastSecurityMultiplierBps, initialReportPriorityFeeAttoEthPerGas)) , using a zero parent for an origin. SecurityPoolFactory.sol Coordinator and auction addresses The coordinator and child Truth Auction factories each hash securityPoolSalt with their caller ( SecurityPoolFactory ) for their CREATE2 salt. OpenOraclePriceCoordinatorFactory.sol , UniformPriceDualCapBatchAuctionFactory.sol Pool address The pool deployment worker uses literal CREATE2 salt zero; its address varies through the full constructor init-code hash, which contains the pool wiring. SecurityPoolDeployer.sol Share-token address An origin share token uses originId , the keccak256 hash of the ABI-encoded questionId , statoblastSecurityMultiplierBps , initialReportPriorityFeeAttoEthPerGas , and originUniverseId in that order, directly as its CREATE2 salt, while factory ownership, Zoltar, and question ID remain in its init code. Children reuse that lineage token and inherit its priority fee. SecurityPoolFactory.sol , ShareTokenFactory.sol Share-token salt squatting Direct ShareTokenFactory callers cannot reserve the canonical origin-pool share-token address. CREATE2 includes constructor arguments in the init-code hash, and the share token owner is msg.sender , so a direct caller using the canonical salt deploys a caller-owned token at a different address than the SecurityPoolFactory deployment. ShareTokenFactory.sol , ShareToken.sol Complete-set capacity Like other operational flows, complete-set minting first requires an unforked universe ( Forked ) and an Operational pool ( Pool inactive ). It then reverts with Fork await while a fork continuation is pending, Escalation mint closed once an Escalation Game exists, Settlement unavailable for zero ETH or an inherited fork outcome, Exchange rate undefined when the deposit converts to no shares or outstanding shares have no collateral, and Over capacity when settlement collateral plus the deposit would exceed the pool's total underwriting commitments . Minting reads no oracle price or REP backing; BAL-03 states the rule. SecurityPool.createCompleteSet , SecurityPoolSettlementDelegate.createCompleteSet Fee eligibility Fee-eligible underwriting commitment includes vault-assigned commitments and sold Truth Auction commitments awaiting claim. BAL-08 owns the ledger invariant. SecurityPool.sol Fee reserve and rounding Settlement-collateral decay first enters an unallocated reserve; vault checkpoints and auction claims move only whole attoETH into totalClaimableVaultFeesAttoEth and carry sub-attoETH remainders forward. totalAccruedFeesAttoEth() returns reserve plus assigned claimable fees. Index carry is cleared when pool financials are installed or a vault's underwriting commitment changes or moves by liquidation; assigning finalized-auction commitment to its winning vault preserves it. SecurityPool.updateSettlementCollateral , SecurityPool.updateVaultFees , SecurityPool._clearFeeIndexRemainder Terminal fee reserve After a fork ends accrual and every eligible allocation is reconciled, the next vault fee checkpoint returns unclaimable whole reserve attoETH to settlement collateral. Fee cutoffs per pool and epoch are specified in the updateSettlementCollateral reference . SecurityPool.sol Retention-rate updates Retention-rate updates no-op when the pool is not Operational ; otherwise utilization divides tracked collateral by total underwriting commitments, independent of price and backing. No commitments or any Escalation Game, open or resolved, select the maximum retention rate. Unclaimed sold auction commitment therefore already affects utilization and fee accrual. A later claim changes only its vault assignment, not fee eligibility, total commitment, minting capacity, or retention solely because of that claim. SecurityPool.sol Multiplier-preserving REP outflows withdrawRepFromVault rejects withdrawal while the vault still has REP escrowed in an escalation game. Withdrawals and new escalation deposits independently preserve multiplier-adjusted REP backing for the affected vault and aggregate pool at the latest valid REP/ETH price. SecurityPool.sol External fork withdrawal lock If the universe forked before the local escalation game ended and non-decision was not reached, parent-pool escalation withdrawal reverts. The child continuation already has the canonical snapshot and aggregate backing: winning inherited deposits settle there by proof, inherited losers require no transaction, and clearing the vault's unresolved parent escalation-deposit accounting is optional. SecurityPool.sol , EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep REP-to-backing-unit round-up The pool’s internal REP-to- backing-unit conversion uses ceiling division when it removes vault REP backing units for an escalation deposit. That intentionally removes enough REP backing units to cover the requested REP even when the conversion is fractional. SecurityPool._attoRepToBackingUnitsRoundUp , SecurityPool.depositToEscalationGame Vault-funded escalation deposit Beyond the unforked-universe and Operational -pool requirement of other operational flows, depositToEscalationGame rejects a pool with an inherited fixed outcome ( Forked ), a pending fork continuation ( Fork await ), a question that has not ended when no game exists ( Question active ), and a carried game that has not resumed ( Fork paused ). It deploys the game on the first valid deposit, previews the accepted amount ( No deposit when zero), and removes vault REP backing units rounding up ( REP too low , Escrow low ). With any pool commitment it requires a valid price ( Stale price ). It then applies the BAL-04 checks to the vault and the pool ( Vault backing insufficient , Pool backing insufficient ) and requires the remaining vault REP to be zero or at least the vault REP floor ( Vault REP below minimum ). ESC-13 owns the start-bond clamp applied when the game is deployed. SecurityPool.depositToEscalationGame , EscalationGameFactory.deployEscalationGame , EscalationGame.recordDepositFromSecurityPool Wallet-funded escalation deposit depositWalletRepToEscalationGame transfers REP from the caller's wallet straight into the game; that REP never becomes vault backing or commitment capacity. It needs no vault and no oracle price and runs no backing check. It rejects an inherited fixed outcome or a forked universe ( Forked ), a non-operational pool ( Pool inactive ), a pending fork continuation ( Fork await ), a question that has not ended when no game exists ( Question active ), and a carried game ( Fork game ). SecurityPool.depositWalletRepToEscalationGame , SecurityPoolOperationsDelegate.depositWalletRepToEscalationGame Direct ETH receiver Ordinary calls to receive() accept ETH only from the forker, its Truth Auction, or its parent pool. Forced ETH can bypass receive() ; it remains raw, unaccounted surplus and is not collateral or accrued fees. SecurityPool.sol Vault enumeration getVaults(startIndex, count) pages the vault registry newest-registered first and returns an empty array when count == 0 or the start index is out of range; getVaultCount() reports the registry length. VAULT-03 owns registry membership and what consumers must read before displaying an entry. SecurityPool.getVaults","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"share-migration","heading":"Share migration","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Share migration after a fork is user-facing asset migration, not vault REP migration. Canonical rules live in FORK-10 for persistent per-child materialization, SHARE-04 for the economic-claim denominator, and FORK-11 for unequal materialized supplies. Area Implementation behavior Source Persistent entitlement ShareToken.migrate preserves the caller's parent token balance as a branch-independent entitlement. After its first use that source balance is transfer-locked, preventing a seller and buyer from materializing the same claim. ShareToken.sol Target list The target outcome list must be non-empty ( ShareToken migration requires at least one target outcome ), contain only well-formed outcomes of the fork question under Zoltar question-data validation ( ShareToken target outcome is malformed for the fork question ), and be strictly increasing ( ShareToken target outcomes must be provided in strictly increasing order ). ShareToken.sol , ZoltarQuestionData.sol Canonical source and fork transition Migration requires a canonical source pool for the token's universe. If that pool is still Operational , migrate first asks its forker to initiate the pool fork; the call proceeds only after the source is PoolForked . That conditional transition can freeze the source pool and emit the ordinary pool-fork and snapshot events. ShareToken.migrate , SecurityPoolForker.initiateSecurityPoolFork Canonical destinations Every destination must be a canonical direct child of the source pool. A single-target migration may lazily create a missing child while the child-pool deployment window is open; a multi-target migration requires every canonical child pool to exist before the call ( ShareToken bulk migration requires canonical child pools ). Lazy creation can also emit child-link, REP-migration, and continuation events. ShareToken.migrate , SecurityPoolForker.createChildUniverse Independent materialization Each selected child token id is minted up to the current source balance. A later call can select another existing child, and source shares added through an ancestor migration materialize only their previously unminted delta. ShareToken.sol Economic denominator startTruthAuction copies the frozen parent's remaining economic claim supply into the child rather than its currently materialized ERC-1155 supply. Complete-set minting and redemption update that denominator; share migration does not because its claims were reserved at fork time. SecurityPoolForker.sol , SecurityPool.sol Timing Shares can materialize indefinitely in an already-created child; creating that child is bounded by the child-pool deployment window . Raw Zoltar child-universe deployment and migration-REP splitting follow Zoltar's fork and balance guards, not this pool timestamp. ShareToken.sol , SecurityPoolForkerVaultMigrationBase.sol , Zoltar.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"escalation-resolution-and-deposits","heading":"Escalation resolution and deposits","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section specifies accepted deposits, edge-case resolution results, and the consumption of carry proofs or residual REP. Area Implementation behavior Source Deposit preview The preview path expects a proposed amount of at least the current startBondAttoRep . EscalationGame.previewDepositOnOutcome Recorded deposit amount The recorded deposit must be positive, and the accepted amount must be at least startBondAttoRep unless it exactly fills the selected outcome to nonDecisionThresholdAttoRep . EscalationGame.recordDepositFromSecurityPool , EscalationGameCalculations._getAcceptedDepositAmount Outcome room Accepted deposit amount is capped to the selected outcome's remaining room under nonDecisionThresholdAttoRep . EscalationGameCalculations._getAcceptedDepositAmount Tie adjustment If the accepted amount would create a tie with the current maximum balance while still below non-decision, the contract reduces the accepted amount by 1 attoREP ; if that breaks the accepted-amount rule, the deposit is rejected. EscalationGameCalculations._getAcceptedDepositAmount Unresolved resolution state If two or more outcomes meet the current running cost, getQuestionResolution() returns None . EscalationGameCalculations.getQuestionResolution Matching-fork continuation resolution After the continuation deadline, a game with a fixed child outcome settles deposits against that outcome. Payout settlement rejects any pool/game outcome mismatch. See Matching-question child outcome for the pool-level finality rule. EscalationGameCalculations.getQuestionResolution , EscalationGameSettlement._getPayoutQuestionResolution , SecurityPoolForker.getQuestionOutcome Empty-game fallback If all outcome balances are zero after the running cost is non-zero, getQuestionResolution() returns Invalid ; if the running cost is still zero, the unresolved check returns None first. EscalationGameCalculations.getQuestionResolution Strict leading resolution After the unresolved-cost check and the all-zero Invalid fallback, a strict Invalid , Yes , or No lead returns that outcome. Local deposits cannot create a tie below non-decision (see Tie adjustment ). Continuation snapshots preserve the parent balances exactly, including ties, so every selected branch starts from the same unresolved game state. EscalationGameCalculations.getQuestionResolution , EscalationGameProofVerifier._getStrictLeaderOrNone , EscalationGameCalculations._getAcceptedDepositAmount , EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances Structural non-decision predicate hasReachedNonDecision() becomes true when two or more outcomes reach nonDecisionThresholdAttoRep ; nonDecisionState separately records how that balance condition entered the lifecycle. ESC-13 owns the threshold arithmetic. Zoltar.getNonDecisionThresholdAttoRep , EscalationGameCalculations.hasReachedNonDecision nonDecisionState = None No explicit non-decision state is active. Deposits may remain available subject to the ordinary activation, continuation, timing, and amount guards. EscalationGame.previewDepositOnOutcome , EscalationGameDepositDelegate.recordDeposit nonDecisionState = Local A local deposit brought a second outcome to the threshold. The game stores the real nonDecisionTimestamp , closes further deposits, and canTriggerOwnFork() returns true. That predicate is game-local: a pool with an inherited fixed outcome still rejects the fork transition in activateForkMode() . EscalationGameDepositDelegate.recordDeposit , EscalationGameCalculations.canTriggerOwnFork , SecurityPool.activateForkMode nonDecisionState = InheritedThresholdTie Set when a continuation snapshot carries two or more threshold-full balances; no local nonDecisionTimestamp is recorded and deposits are closed. With a fixed child outcome, the game follows the continuation clock and canTriggerOwnFork() is false. Otherwise fork eligibility remains until applyTruthAuctionHaircut removes REP sold in the Truth Auction and breaks the tie; that clears the state, emits InheritedThresholdTieReopened , and on resume rebases the clock to the reduced binding capital with a fresh response period and reopens pool-mediated deposits. EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances , EscalationGameCalculations.getEscalationGameEndDate , EscalationGameCalculations.canTriggerOwnFork , EscalationGameDepositDelegate.applyTruthAuctionHaircut Carry proofs Inherited carry uses Merkle Mountain Range peaks and nullifier roots so child games can consume proofs without replaying already-spent parent deposits. EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._verifyAndConsumeCarriedDepositProof Continuation withdrawal After a child pool's carried game resolves, anyone may relay a batch of winning carried proofs for one depositor ( One vault ). ESC-07 owns the payout recipient and ESC-05 the single use of each proof. SecurityPool.withdrawForkedEscalationDeposits , EscalationGameSettlement.withdrawDeposit , EscalationGameDepositDelegate.consumeCarriedDeposit Carried payout amount Retained principal maps the deposit's cumulative endpoints through each ancestor's auction ratio; the reward uses the separate reward interval , binding capital , winning balance, and fork-threshold scaling. Allocations within a game are fixed, so claim order cannot change payouts. EscalationGameClaimDelegate.getUnresolvedClaimInterval Inherited losers Inherited losing outcomes retire without a proof once the result is final; locally created losing deposits settle ordinarily. EscalationGameSettlement.withdrawDeposit Carried-claim gas Allocation reads call each source game in the deposit's lineage , so gas grows with fork depth. No maximum depth is enforced; see LIFE-05 . EscalationGameClaimDelegate.getUnresolvedClaimInterval Optional unresolved parent escalation-deposit accounting cleanup Optional. SecurityPoolForker.migrateVaultWithUnresolvedEscalation first runs ordinary vault migration for that vault, then exports one Invalid / Yes / No principal tuple to one selected child without a token transfer. It never processes another vault, preserves proof leaves, and neither funds dispute-staked REP backing nor authorizes inherited claims. SecurityPoolForker.migrateVaultWithUnresolvedEscalation , EscalationGameEscrow.exportVaultUnresolvedTotalsWithoutTransfer , EscalationGameForker.migrateVaultWithUnresolvedEscalation Residual sweep sweepResidualRepToSecurityPool returns an ordinary game's residual to the security pool and burns a carried game's entire residual. ESC-11 owns the preconditions. EscalationGameSettlement.sweepResidualRepToSecurityPool","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"fork-migration","heading":"Fork migration","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section specifies pool-level migration after a universe fork: proxies, child-pool creation, pool-proxy REP splitting, and child outcome selection. Area Implementation behavior Source Pool-specific migration identity The forker lazily deploys one deterministic SecurityPoolMigrationProxy per parent pool. The proxy is the stable msg.sender for Zoltar migration accounting. REP sent to its predictable address before deployment remains isolated surplus: fork accounting uses newly routed REP and the Zoltar migration ledger, not the proxy’s preexisting ERC-20 balance. SecurityPoolForker.sol , SecurityPoolMigrationProxy.sol Proxy authority The migration proxy is owner-controlled by the forker and wraps lockRep , forkUniverse , splitToChild , and child REP sweeping. SecurityPoolMigrationProxy.sol Child REP backing During vault migration, the forker ensures the child pool is backed by enough child-universe REP for cumulative migrated REP credited to that child. SecurityPoolForkerVaultMigrationBase.sol Vault fees during migration Migration uses one fixed, fee-exclusive snapshot and a cumulative REP ceiling. The parent vault is checkpointed before its underwriting commitment is cleared, so earned fees remain redeemable, and parent-to-child ETH transfers cannot consume the balance reserved by totalAccruedFeesAttoEth() . The invariant catalog specifies BAL-07 fee-reserve protection , FORK-09 cumulative child collateral , and FORK-08 continuation backing . SecurityPoolForker.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPool.sol Split shortfall tracking The forker tracks how much REP has already been split for each parent-pool/outcome pair and only splits the shortfall before sweeping child REP into the child pool. SecurityPoolForkerVaultMigrationBase.sol Canonical continuation snapshot Fork initialization stores the complete parent Invalid / Yes / No balances, carry totals, peaks, leaf counts, and nullifier roots once. Every lazily created child reads that same stored snapshot, even if an allowed parent claim occurs before a later child is created. SecurityPoolForker._snapshotEscalationAtFork , SecurityPoolForkerBase._initializeChildForkedEscalationGameIfNeeded , EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances Aggregate escalation backing An external unrelated fork reproduces the drained game's dispute-staked REP one-for-one in each selected child. The escalation's own fork transfers aggregate backing net of the fork haircut instead; ordinary pool-held REP remains one-to-one. Each selected child receives its applicable aggregate backing once, and resumeFromFork remains paused until that backing is present after accounting for child REP already exported by valid direct pre-resume claims. See FORK-08 for the raw and effective principal definitions and exact funding bound. Neither path scales or releases per-vault child escrow. SecurityPoolForker.initiateSecurityPoolFork , SecurityPoolForker.forkZoltarWithOwnEscalationGame , SecurityPoolForkerVaultMigrationBase._ensureChildEscalationBacking , EscalationGame.resumeFromFork Direct-claim replay protection A successful direct own-fork claim records both the stable parent deposit identity and cumulative claimed principal by outcome. Every current, late, or recursively inherited child rejects a second payout; effective inherited principal subtracts immediate-parent direct claims so those leaves cannot strand the residual sweep. EscalationGameForker.claimForkedEscalationDeposits , SecurityPoolForker.isEscalationDepositClaimedDirectly , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep Continuation setup Child creation installs the canonical carry commitment, source-game link, and aggregate backing without waiting for vault transactions or copying claims and owners. The fixed 64-peak MMR frontier is logarithmic commitment storage for up to 2^64 - 1 leaves, not a participant cap; see Merkle Mountain Range carry-proof peaks . SecurityPoolForkerBase._finalizeAwaitingForkContinuationIfReady , EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep Continuation resume Once the child is operational and fully funded, resumeForkedEscalationGame resumes it in one bounded permissionless call. Winning proofs can then be relayed, and optional parent cleanup may happen independently. SecurityPool.resumeForkedEscalationGame Own-fork REP buckets When escalation triggers its own fork, escalationChildRepAtForkAttoRep equals disputeStakedRepToForkAttoRep - ⌊forkThresholdAttoRep / forkBurnDivisor⌋ . vaultRepAtForkAttoRep preserves ordinary pool-held REP one-for-one. Creating one selected child does not reduce the post-fork-haircut escalation backing available to another selected child. SecurityPoolForker.forkZoltarWithOwnEscalationGame , SecurityPoolForker.getOwnForkRepBuckets , SecurityPoolForkerBase._initializeOwnForkRepBuckets Child-pool deployment window Child pools are created lazily for selected fork outcomes, only while the parent pool is PoolForked ( Parent not forked ) and the migration window is open ( Migration closed ). The same window bounds pool-local vault and REP migration. FORK-05 owns the eight-week boundary. SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolUtils.sol Matching-question child outcome When the parent universe forks on the pool's question, the child stores its selected branch as a fixed result. depositToEscalationGame and depositWalletRepToEscalationGame reject new local deposits, and activateForkMode rejects every later pool fork transition ( Forked in each case). ESC-12 owns the property; Forks and migration gives the collateral and REP-liveness rationale. SecurityPool.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolForker.sol Unrelated-fork child outcome A child created by an unrelated fork without an inherited fixed result uses a local escalation result only if that escalation ended before the universe forked; otherwise continuation or later state must produce the outcome. SecurityPoolForker.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"truth-auction-operations","heading":"Truth Auction operations","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Collateral-repair auctions have three operator-critical boundaries: forker ownership, a one-week bidding window, and paged settlement into vault accounting. Bids close at auctionStarted + AUCTION_TIME ; both direct auction finalization and the public forker wrapper allow finalization at >= that boundary. The canonical clearing rules and examples are in Truth Auction . Area Implementation behavior Source Owner Child-pool Truth Auctions are owned by SecurityPoolForker . The direct auction startAuction and finalize calls are owner-only, while anyone can reach them through startTruthAuction and finalizeTruthAuction . UniformPriceDualCapBatchAuction.sol , SecurityPoolForker.sol Finalized settlement After finalization, only the auction owner withdraws bid outcomes from the auction; SecurityPoolForker wraps that call so anyone can settle a vault's bid pages. UniformPriceDualCapBatchAuction.sol , SecurityPoolForker.sol Child fee activation Completed migration or truth-auction settlement starts a new child fee epoch. Migrated ownership and sold truth-auction ownership enter the fee denominator at finalization. Each later auction claim assigns the bidder vault its ownership and fees accrued from the saved finalization index through the current index without changing the pool’s live eligible total; intervening capacity changes and liquidations remain preserved. SecurityPool.sol , SecurityPoolForker.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"repeth-oracle-operations","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section covers coordinator staging, callback recovery, stale-operation handling, and liquidation boundaries. Report sizing, request cost, and current OpenOracle parameters are canonical in the OpenOracle integration parameters . Area Implementation behavior Source Atomic initial report The sponsor commits an explicit ETH bounty of at least the dynamic request cost and funds the WETH/REP position; the coordinator retains the whole bounty and submits that position atomically as the initial reporter. A caller-selected WETH amount above the dynamic minimum is allowed. See OpenOracle sizing and funding for derivation, reporter withdrawals, application buffering, and escalation effects. OpenOraclePriceCoordinator.sol , openOracle.ts Immediate execution If a price is still valid, the operation executes immediately and positive unused ETH is refunded. A contract caller must accept the refund callback or the execution rolls back; the canonical refund warning also covers newly opened reports. OpenOraclePriceCoordinator.sol Fresh-price request guard requestPrice reverts while the cached coordinator price is still valid ( Oracle price already fresh ), so callers cannot open a redundant pending report on top of a fresh cache. OpenOraclePriceCoordinator.sol Staging guardrails Withdrawal and liquidation amounts must be non-zero ( Staged operation amount must be non-zero ); a zero underwriting commitment is a valid exit. Validity must be positive and no more than five minutes ( Staged operation timeout must be positive , Staged operation timeout exceeds the maximum allowed ). Withdrawals and underwriting-commitment changes target the operator's own vault ( Self operation target mismatch ). A liquidation receiver must differ from its target ( Receiver is target ); ORA-05 owns the role rules. A delegated receiver requires a valid bounded approval and queue-time reservation, while the self-receiving operator path requires no signature. OpenOraclePriceCoordinator.sol , OpenOraclePriceCoordinatorTypes.sol Delegated receiver approvals LiquidationApprovalRegistry supports direct receiver approvals and Ethereum Improvement Proposal 712 (EIP-712) permits from externally owned accounts (EOAs) or ERC-1271 contract wallets. An approval binds pool, receiver, exact operator, exact or wildcard target, cumulative and per-operation ETH debt limits, minimum post-health factor, validity window, and nonce. Revocation blocks new reservations without disturbing pending ones; nonce invalidation blocks stale approvals. LiquidationApprovalRegistry.sol , openOracle.ts Approval reservation lifecycle Staging reserves at most requested debt, snapshotted target underwriting commitment, per-operation allowance, and available cumulative allowance. Success consumes exactly the transferred underwriting commitment and releases the remainder; an untransferred residual consumes no approval quota. Every terminal failure and permissionless expiration releases once. Approval validity must cover the latest legal execution time. OpenOraclePriceCoordinator.sol , LiquidationApprovalRegistry.sol Pending report bound At most four price actions are attached to one settlement callback, counting each commitment change, liquidation, or withdrawal within a vault bundle separately. Deposits use no slot. Bundles must fit the remaining callback capacity; single operations can still be tracked as active outside the callback batch. OpenOraclePriceCoordinator.sol Sponsor exclusivity Once the cached price is stale and a caller funds a fresh coordinator report, only that pendingReportSponsor can append more staged operations until settlement. Valid disputes reset the settlement clock, so this paid exclusive lane can be extended indefinitely; the coordinator makes no bounded-availability guarantee. The economic tradeoffs , attack model , and parameter table own dispute funding, escalation, and rounding details. OpenOraclePriceCoordinator.sol , OpenOracle.sol Rejected settlement When the callback fails any condition in coordinator settlement validation , it emits PriceReportRejected , leaves lastPrice unchanged, clears the pending report so a new price can be requested, and terminally fails every operation attached to that report, releasing each delegated-liquidation reservation. OpenOraclePriceCoordinator.sol , OpenOracle.sol Recovery path Coordinator reports opt into OpenOracle's STORE_ALL and TRACK_DISPUTES flags. Recovery requires a pending report whose stored OpenOracle settlement timestamp is nonzero. It returns withdrawable reporter balances to the sponsor, clears the report, consumes all associated pending operations, and releases their liquidation reservations. An expired operation can also be cleaned permissionlessly before any valid-price requirement. OpenOraclePriceCoordinator.sol Consumed failures Expired operations ( Staged operation expired ), stale liquidations ( Stale liquidation ), zero-effect withdrawals ( Withdraw amount has no effect ), and liquidations too close to threshold are consumed and emitted as failed executions. ORA-06 owns the property. OpenOraclePriceCoordinator.sol Vault operation bundle submitVaultOperations applies a deposit, commitment change, liquidations of other vaults, and withdrawal to one pool. At most four price actions fit a bundle. A fresh-price failure reverts the submission; with a stale price the deposit remains while the remaining actions execute atomically after settlement. Any change to a queued liquidation target's REP backing units or underwriting commitment fails the whole bundle, including the owner's commitment change and withdrawal. See coordinator execution and funding . VaultOperations.sol Liquidation snapshot A staged liquidation becomes stale if target REP backing units or its underwriting commitment ( underwritingLimitAttoEth ) changes. The underwriting-commitment snapshot bounds the reservation; the proportional-obligation snapshot is historical context. Execution rechecks full-commitment target health and the receiver's entire resulting underwriting commitment against live price and backing. REP awards cap at available target units without reducing the accepted underwriting commitment. Successful transfer conserves total underwriting commitments. Residual exposure remains visible and earns fees. See queued execution . OpenOraclePriceCoordinator.sol , SecurityPool.sol Liquidation distance A staged liquidation must remain at least minLiquidationPriceDistanceBps beyond the liquidation threshold when it executes. OpenOraclePriceCoordinator.sol , SecurityPoolOperationsDelegate.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["inventory","factories","delegates","SecurityPoolUtils","trust boundary"],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Reference This page lists every production Solidity source by area. The contract interaction reference documents the entrypoints of the contracts users and keepers call; this page adds the caller and trust boundaries of the deployment helpers, delegate modules, and libraries that reference does not cover, the SecurityPoolUtils previews, and the Uniswap contracts a testnet deployment uses.","title":"Contract inventory","topic":"Contracts","weight":1},{"fragment":"caller-and-trust-boundaries","heading":"Caller and trust boundaries","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Deployment helpers are not interchangeable with canonical protocol discovery. Several are intentionally permissionless and bind the caller into each deployed address, through a caller-namespaced salt or the caller in the init code; an application must discover canonical instances through SecurityPoolFactory , recognized security pools , and recognized forker events rather than treating every factory-created address as canonical. Module Direct caller boundary Canonical-use boundary EscalationGameFactory deployEscalationGame and deployEscalationGameFromFork have no permission check, but a successful caller must implement the ISecurityPool reads used during construction; an EOA or incompatible contract reverts. The CREATE2 salt is zero; the caller is bound into the init code as the new game's securityPool , so each caller has one game address; the factory itself becomes the game's immutable owner and immediately calls start or startFromFork . Ordinary deployment requires a threshold above one attoREP and lowers a start bond at or above that threshold to threshold - 1 . The factory has no owner role and no later resumeFromFork relay. Accept a game only after EscalationGameSet from a recognized pool. In the supported continuation path, the owning pool calls resumeFromFork , which also verifies aggregate funding. ShareTokenFactory Anyone can call deployShareToken to deploy or retrieve a token keyed by keccak256(abi.encode(msg.sender, salt, questionId)) . The CREATE2 salt is the raw salt ; the caller and question id enter through constructor arguments, and that caller is the token's initial authorized address. Origin lineage tokens are the instances created by SecurityPoolFactory and named in DeploySecurityPool ; children reuse the parent's token. UniformPriceDualCapBatchAuctionFactory Anyone can call deployUniformPriceDualCapBatchAuction . Its salt is namespaced by caller and supplied salt, and its operational owner is the caller-supplied owner address. During external-universe initiation, the source must be authorized by its declared share token; own-game initiation does not perform that check, and neither relationship proves configured-factory registration. Child linking requires a deployed auction that this forker has never trusted before and preserves the source's factory and forker. Canonical pools remain the instances registered by the configured SecurityPoolFactory . OpenOraclePriceCoordinatorFactory Anyone can call deployOpenOraclePriceCoordinator under a caller-namespaced salt with caller-supplied OpenOracle, REP token, and positive initialReportPriorityFeeAttoEthPerGas ; coordinator construction rejects zero and values that would consume the reserved OpenOracle uint128 report and escalation-halt capacity. The caller therefore chooses this immutable gas-price assumption within that bound. The same call deploys and initializes the coordinator's LiquidationApprovalRegistry clone and binds it to the coordinator. A pool coordinator is the instance named by canonical DeploySecurityPool ; SecurityPoolFactory atomically binds it to that pool before returning, and canonical child deployment inherits the value from the parent coordinator. PriceCoordinatorDeploymentWorker , LiquidationApprovalRegistryDeployer , and CreationCodeChunk The coordinator factory constructor deploys one worker and one registry deployer; only that factory may call the worker's deploy and configureLiquidationApprovalRegistry or the registry deployer's deploy . The worker stores coordinator creation code in two CreationCodeChunk data contracts, deploys coordinators with CREATE2 , and is the only address that may call setLiquidationApprovalRegistry . The registry deployer creates the registry implementation and deploys minimal-proxy clones under the coordinator's salt. Code-size and deployment plumbing with no protocol authority; users do not call them. LiquidationApprovalRegistry implementation The implementation the registry deployer creates is never initialized, so anyone can call its initialize and bind it to an arbitrary coordinator. Clones are initialized in their deployment transaction. Trust registry state only at the address returned by a recognized coordinator's liquidationApprovalRegistry() . SecurityPoolDeployer and SecurityPoolDeploymentWorker Only the configured SecurityPoolFactory may call the deployer; only that deployer may call its worker. They are code-size deployment plumbing. The proxy deployer deploys one deterministic SecurityPoolOperationsDelegate , and its address is passed into the SecurityPoolFactory constructor. The proxy deployer is the deterministic CREATE2 deployment proxy that every canonical deployment goes through; it is not a Solidity source in this repository and appears in the deployment manifests as step proxyDeployer . The factory passes that address through its deployer and worker to every pool. Its deterministic address is published as securityPoolOperationsDelegate . Pools become canonical only when the factory emits SecurityPoolRegistered and DeploySecurityPool . SecurityPoolMigrationProxy Only its immutable owner , the SecurityPoolForker that created it, may call lockRep , forkUniverse , splitToChild , or sweepChildRep . Its deterministic per-parent address is exposed by getMigrationProxyAddress and recorded in fork snapshot events; users do not call it. EscalationGameDepositDelegate , EscalationGameClaimDelegate , EscalationGameForker , SecurityPoolForkerVaultMigrationDelegate , SecurityPoolSettlementDelegate , and SecurityPoolOperationsDelegate Their public methods are delegatecall implementations. The deposit delegate implements depositRepOnOutcome , depositRepOnOutcomeWithPermit , depositRepOnOutcomeWithAuthorization , recordDeposit , recordForkedEscrowForOutcome , applyTruthAuctionHaircut , funding-gated resumeFromFork , consumeEscrowedRepForOwner , consumeCarriedDeposit , consumeUnresolvedRepForClaimOwners , creditClaimOwners , and creditExternalClaimOwners . The shared claim delegate handles retention checkpoint reads and initialization; it has no ownership or import surface. The forker delegates implement escalation and vault migration. SecurityPoolSettlementDelegate is abstract and contributes complete-set minting validation and funded inherited-collateral installation to the single deployed SecurityPoolOperationsDelegate . That operations delegate implements underwriting commitment changes, aggregate mint backing checks, and authorized liquidation transfers that conserve total underwriting commitments without writing off residual exposure. REP backing and fees are accounted separately. See the SecurityPool and EscalationGame interaction references for the public entrypoints, including the selectors each contract's fallback() routes to its delegate. A direct call may revert against uninitialized state or may mutate only the helper's isolated storage; it is not a protocol action. Accept resulting state and logs only when the recognized game, pool, or forker executes the matching wrapper through delegatecall . State changes and events then occur in that recognized contract's context. Canonical liquidation enters through SecurityPool.performLiquidation , which only the pool's VaultOperations executor may call; continuation progress enters through SecurityPool.resumeForkedEscalationGame . SecurityPoolEventEmitter and SecurityPoolForkEventEmitter SecurityPoolEventEmitter inherits the pool's typed SecurityPoolStorage base and exposes emitPoolAccountingCheckpoint and emitVaultAccountingCheckpoint . SecurityPoolForkEventEmitter inherits the forker's typed SecurityPoolForkerStorage base and exposes emitForkSnapshotEvents . The entrypoints are externally callable and payable , but direct calls execute against the helper's own storage and emit from the helper address. Payability permits delegatecalls from value-bearing protocol flows; callers must not send ETH directly because it is not protocol collateral and the helpers have no recovery surface. Pools delegate accounting checkpoints to their pool-layout emitter, while the forker delegates fork snapshots to its forker-layout emitter, so logs are emitted from the recognized pool or forker address. Indexers must reject matching signatures from either helper or any unrecognized emitter. Storage-layout tests protect both typed delegate layouts. EscalationGameProofVerifier , MerkleMountainRange , and SecurityPoolUtils Math and proof routines have no lifecycle authority. Public verifier calls and SecurityPoolUtils pure previews can be used for previews, but do not mutate a game or pool. SecurityPoolUtils also has state-changing external library functions, configureForkMigratedVault , consumeUnassignedCommitment , and creditForkAuctionVault , which execute through delegatecall in the forker's context; library call protection rejects direct calls to them. A result becomes protocol state only through a recognized game, pool, or forker transaction and its events. DeploymentStatusOracle Anyone can call getDeploymentMask ; the constructor alone fixes the ordered address list and emits DeploymentAddressesSet . It reports code presence only, not canonical wiring or readiness. Decode it using its constructor event or the matching deployment manifest order.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"securitypoolutils-read-surface","heading":"SecurityPoolUtils read surface","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"The table lists every external or public read of the library; its three state-changing library functions are in the trust-boundary table above. The previews distinguish a vault's underwriting commitment from its current proportional share of open interest . REP-per-ETH prices use PRICE_PRECISION , and health factors and security multipliers use basis points. The previews have no lifecycle, caller, freshness, or canonical-pool authority; only a recognized pool or coordinator transaction can apply their result. Function Exact boundary behavior Conceptual owner calculateFeeAccrual(settlementCollateralAttoEth, retentionRate, timeDelta, indexRemainder, feeEligibleUnderwritingLimitAttoEth, feesOwedRemainder) Applies fixed-point retention over elapsed time to settlement collateral net of the already-counted but uncredited decay (indexRemainder + feesOwedRemainder) / 1e18 , carries the global index remainder, and returns whole credited fees plus the next fee remainder. Credited fees therefore never exceed settlement collateral. Canonical callers avoid a zero fee-eligible underwriting commitment total before this division. Fee accrual calculateVaultFee(underwritingLimitAttoEth, feeIndexDelta, remainder) Floors the vault's whole fee credit and returns the remaining fixed-point numerator for its next checkpoint. Fee accrual calculateVaultOpenInterestAttoEth(activeOpenInterestAttoEth, vaultUnderwritingLimitAttoEth, totalUnderwritingLimitAttoEth) Attributes live pool open interest pro rata to underwriting commitment, rounding a positive vault share upward. A zero vault or total underwriting commitment returns zero. Dynamic capacity calculateBundledLiquidationTransfer(targetBackingUnits, targetUnderwritingLimitAttoEth, targetOpenInterestAttoEth, requestedDebtAttoEth, repEthPrice, currentPoolHeldAttoRepBalance, currentTotalRepBackingUnits, minimumRemainingAttoRep) Both target exposure arguments are the target's full underwriting commitment. Transfers the lesser of request and that commitment. The REP award, the debt's REP value plus a 5% bonus (105%), rounds up in REP and backing units, then caps at available target units. Partial transfers reserve the configured minimum REP when available. A full transfer can use all target units. The receiver must independently satisfy health for its full underwriting commitment; no residual underwriting commitment is written off. Vault liquidation isVaultHealthy(poolHeldVaultRepBackingAttoRep, disputeStakedAttoRep, underwritingLimitAttoEth, repEthPrice, poolSecurityMultiplierBps) Checks the associated-REP and free pool-held REP requirements against the full underwriting commitment at a factor of 10,000 BPS. Both requirements round upward; a zero commitment is healthy. Capacity and health calculateRetentionRate(settlementCollateralAttoEth, mintingCapacityAttoEth) Zero minting capacity returns the maximum retention rate. Otherwise retention decreases linearly through the 80% utilization dip and remains at the minimum rate above it. Retention rate isVaultHealthyAtFactor(poolHeldVaultRepBackingAttoRep, disputeStakedAttoRep, underwritingLimitAttoEth, repEthPrice, poolSecurityMultiplierBps, healthFactorBps) Public pure. The isVaultHealthy check with both REP requirements multiplied by healthFactorBps / 10,000 , rounded upward. A factor below 10,000 BPS returns false, before the zero-commitment case returns true. Receiver approvals calculateLiquidationBackingUnitsAward(debtToMoveAttoEth, repEthPrice, currentPoolHeldAttoRepBalance, currentTotalRepBackingUnits) Public pure. Returns the backing units for the REP value of the moved commitment plus the 5% bonus, rounding upward in REP and again in units. With zero total units or zero pool-held REP it returns the REP award multiplied by PRICE_PRECISION . Vault liquidation calculateInitialEscalationDepositAttoRep(theoreticalSupplyAttoRep) Public pure. Returns theoreticalSupplyAttoRep / 10,000,000 , with a floor of 1 REP. SecurityPoolFactory calculateMinimumVaultRepDepositAttoRep(theoreticalSupplyAttoRep, configuredMinimumAttoRep) Public pure. Returns configuredMinimumAttoRep when it is nonzero, otherwise theoreticalSupplyAttoRep / 100,000 . SecurityPoolFactory getUnassignedPositionFeeAccounting(securityPoolAddress) External view. Returns the forker's auction-finalization fee index for the pool's unassigned position and the fees that position has accrued since, underwritingLimitAttoEth × (feeIndex − feeIndexAtFinalization) / PRICE_PRECISION . The fee amount is zero when the pool has no Truth Auction or the auction purchased no REP. SecurityPoolForker getBadDebtGeneration(securityPool) External view. Returns badDebtGeneration from the pool's getPoolAccountingSnapshot() . SecurityPool","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"production-contract-inventory","heading":"Production contract inventory","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Every production Solidity source appears in one row. The first row lists the sources with a page in the contract interaction reference; the sources of the other documented contracts appear in the row for their area. Area Named contracts and modules Role Core contracts Zoltar.sol , ZoltarQuestionData.sol , SecurityPool.sol , OpenOraclePriceCoordinator.sol , VaultOperations.sol , UniformPriceDualCapBatchAuction.sol Universe forks and REP migration, question storage, the security pool, its price coordinator and vault bundle executor, and the Truth Auction. Entrypoints: Zoltar , ZoltarQuestionData , SecurityPool , OpenOraclePriceCoordinator , VaultOperations , and UniformPriceDualCapBatchAuction . Deployment tracking DeploymentStatusOracle.sol Reports one code-presence bit per configured deployment-step address. See Deployment Status Oracle . Carry proof hashing MerkleMountainRange.sol , EscalationGameProofVerifier.sol , EscalationGameTypes.sol Defines the carried-deposit leaf shape, the 64-peak limit, proof-length rules, and nullifier-root replay protection. See Merkle Mountain Range carry proofs . Escalation game composition EscalationGame.sol , EscalationGameCalculations.sol , EscalationGameCarry.sol , EscalationGameClaimDelegate.sol , EscalationGameDepositDelegate.sol , EscalationGameEscrow.sol , EscalationGameSettlement.sol , EscalationGameState.sol , EscalationGameStorage.sol Splits the game across immutable ownership and storage, claim and deposit delegation, calculations, continuation proofs, escrow, and settlement without exposing those internal modules as separate canonical games. ERC-20 support ERC20.sol , IERC20.sol , IExternalGenesisReputationToken.sol , IERC20Metadata.sol , Context.sol , SafeERC20Ops.sol , GenesisReputationToken.sol , ReputationToken.sol Base REP token implementation, ERC-20 and external genesis REPv2 interfaces, metadata, execution context, safe transfer wrappers, the constructor-allocated testnet stand-in for mainnet REPv2 ( GenesisReputationToken ) with fixed theoretical supply, and the inherited transfer , approve , and transferFrom entrypoints. ERC-1155 and token ids ERC1155.sol , ShareToken.sol , TokenId.sol , IERC1155.sol , IERC1155Receiver.sol , IERC165.sol , IShareToken.sol Outcome-share token plumbing, interface support, token-id encoding, inherited setApprovalForAll , and both single and batch safeTransferFrom forms. Factories and deployers EscalationGameFactory.sol , SecurityPoolFactory.sol , SecurityPoolDeployer.sol , ShareTokenFactory.sol , UniformPriceDualCapBatchAuctionFactory.sol , OpenOraclePriceCoordinatorFactory.sol , Create2Deployment.sol Deterministic deployment entrypoints for pool, share-token, oracle-coordinator, liquidation-approval-registry clone, escalation-game, and auction instances, plus the shared CREATE2 helper library they use. Migration, settlement, liquidation, and storage modules SecurityPoolStorage.sol , DelegateCallForwarder.sol , DelegateCall.sol , SecurityPoolSettlementDelegate.sol , SecurityPoolOperationsDelegate.sol , SecurityPoolMigrationProxy.sol , SecurityPoolForker.sol , SecurityPoolForkerAuctionSettlementBase.sol , SecurityPoolForkerBase.sol , SecurityPoolForkerStorage.sol , SecurityPoolForkerTypes.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolForkerVaultMigrationDelegate.sol , UniformPriceDualCapBatchAuctionStorage.sol , OpenOraclePriceCoordinatorTypes.sol , EscalationGameForker.sol , SecurityPoolEventEmitter.sol , LiquidationApprovalRegistry.sol , SignatureValidation.sol Defines shared pool storage, delegated liquidation accounting and bounded approval reservations, Elliptic Curve Digital Signature Algorithm (ECDSA) and ERC-1271 signature validation, funded continuation delegatecalls, fork-time state, truth-auction settlement, vault and unresolved-escalation migration, event encoding, and stable proxy identity used while routing parent state into child pools. Protocol interfaces IEscalationGame.sol , IEscalationGameDelegateContexts.sol , ISecurityPoolDeploymentWorkerConfiguration.sol , IZoltarForkState.sol , ISecurityPool.sol , ISecurityPoolForker.sol , ISecurityPoolForkerChildEscalationGameInitializer.sol , IUniformPriceDualCapBatchAuction.sol , IWeth9.sol Typed boundaries used by games, pools, migration delegates, auctions, and WETH integration. Protocol utilities Constants.sol , ScalarOutcomes.sol , BinaryOutcomes.sol , SecurityPoolUtils.sol , Multicall3.sol , WETH9.sol Shared constants and math, outcome representations, Multicall3 aggregate , tryAggregate , tryBlockAndAggregate , blockAndAggregate , aggregate3 , aggregate3Value , and block-context reads, plus standard WETH9 deposit , withdraw , approval, and transfer support. Operator deployment helper GenesisUniswapV3Seeder.sol Lets the Chaos bot mint a bounded full-range genesis REP/WETH Uniswap V3 position, pays the pool callback from exact operator approvals, and refunds unused tokens. Trading protocol PredeploymentShareSink.sol , TradingLiquidityToken.sol , TwoWayConstantProductFactory.sol , TwoWayConstantProductMath.sol , TwoWayConstantProductPair.sol , TwoWayConstantProductRouter.sol , ITradingShareToken.sol , ITwoWayConstantProductFactory.sol , ITwoWayConstantProductPair.sol . Deterministic two-outcome pool deployment, constant-product pricing and reserves, routed liquidity and swap operations, receive-based share authorization, permit-enabled liquidity tokens, canonical Statoblast share-token integration, and quarantine of shares sent to counterfactual pair addresses before deployment. REP authorization support AuthorizationSignatures.sol , ERC20Authorization.sol , IERC20Authorization.sol . Pinned signature recovery, EIP-712 domain handling, ERC-2612 permits, and ERC-3009 transferWithAuthorization , recipient-bound receiveWithAuthorization , and cancelAuthorization used by newly deployed child REP. Imported oracle integration UPSTREAM.md , OpenOracle.sol , Errors.sol , ISignatureTransfer.sol , interfaces/IERC20.sol , interfaces/IERC165.sol , token/ERC20/IERC20.sol , IERC1363.sol , SafeERC20.sol , Panic.sol , ReentrancyGuard.sol , StorageSlot.sol , utils/introspection/IERC165.sol , Math.sol , SafeCast.sol OpenOracle's imported source, exact openPunt revision, compiler profile, and dependency provenance are owned by UPSTREAM.md . The coordinator submits attoETH/attoREP reports with dispute history and full game storage enabled; it does not enable the new optional flags. OpenOracle's packed event stream remains separate from Zoltar replay.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"testnet-uniswap-dependencies","heading":"Testnet Uniswap dependencies","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"The UI, the bots, and the testnet deployer read Uniswap addresses from one registry, shared/core/ts/deployment/uniswapDeployments.ts . Chain WETH, V3 factory, QuoterV2, V4 PoolManager, V4 Quoter SwapRouter Sepolia ( 11155111 ) Uniswap's published contracts ( V3 , V4 ); the deployer requires each to carry Uniswap's exact runtime code. An Anvil node with the Sepolia chain ID receives them by replaying Uniswap's original creation transactions, vendored byte for byte in scripts/artifacts/uniswap-deployment.json . Deterministic SwapRouter (v1) bound to the published factory; Uniswap publishes none on Sepolia. Any other testnet Deterministic WETH plus a complete Uniswap V3 and V4 deployment from the pinned bytecode. Deterministic SwapRouter from the pinned bytecode.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["deployment","bitmask","runtime bytecode","status"],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"DeploymentStatusOracle is a deployment-progress helper. It does not measure protocol readiness or initialization success. It only reports which configured deployment-step addresses currently contain runtime bytecode.","title":"Deployment status oracle","topic":"Contracts","weight":1},{"fragment":"mask","heading":"What getDeploymentMask() returns","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"The constructor stores one ordered address[] deploymentAddresses . getDeploymentMask() loops over that array and checks deploymentAddresses[index].code.length . When code exists, the oracle sets bit index in the returned uint256 . This is a code-presence bitmap. A set bit means code exists at the configured address. A clear bit means the address currently has no code. The oracle does not verify constructor arguments, ownership wiring, or post-deployment setup. A row of deployment steps maps by index into bit positions in a uint256 mask. Each step sets its bit only when code exists at that configured address. Deployment status mask Each configured deployment step uses one bit position in the returned word. The oracle sets that bit only if the step's address currently contains code. deployedMask = ∑ i = 0 codePresent ( i ) ⋅ 2 i Each configured deployment step contributes one bit position to the returned word.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"ordering","heading":"How bits map to deployment steps","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Bit positions are array positions. Bit 0 maps to the first constructor address, bit 1 to the second, and so on. Off-chain decoding must use the same ordered list that seeded the oracle. The constructor emits DeploymentAddressesSet(address[] deploymentAddresses) with that exact ordered list. It is the on-chain source for recovering a particular oracle instance's bit mapping. The manifest below describes the current planned deployment and must match the constructor event for that instance. The current user interface (UI) and deployment helpers derive the constructor list from deploymentSteps with one exception: the oracle does not include its own address in its constructor array. The manifest still lists deploymentStatusOracle as a deployment step, but the UI tracks that step out of band and starts consuming mask bits from the remaining addresses. The tables below render the complete bit mappings directly from the canonical mainnet deployment manifest and Sepolia deployment manifest , excluding deploymentStatusOracle . Each manifest's ordered deploymentSteps array is the canonical mapping for that network. The orders differ: Sepolia inserts the genesis REP token at bit 1 , so the same mask names different steps on each network. Select the network before decoding. A second, Zoltar-only oracle is deployed by the Zoltar app's deployment flow and by the testnet deployer. Neither manifest lists it or publishes its address: the testnet deployer's plan names it zoltarDeploymentStatusOracle , a step id that exists only in that plan, alongside the tradingFactory and tradingRouter steps the manifests also omit. Its constructor list is a prefix of the manifest mapping: the proxy deployer, genesis REP on Sepolia, Multicall3, ZoltarQuestionData , and Zoltar . Decode its mask with the same table; only those leading bits exist. Bit Mainnet step id Label Status in entered mask Loading the canonical manifest… Bit Sepolia step id Label Status in entered mask Loading the canonical manifest… If the manifest's constructor order changes, the rendered bit meanings change with it; this page does not maintain a second list. The manifest's derivedContracts list adds no mask bits. Five of its six entries ( securityPoolForker , escalationGameClaimDelegate , escalationGameFactory , securityPoolFactory , and securityPoolOperationsDelegate ) repeat a deploymentSteps address under a different label, so each already has a bit. Only escalationGameProofVerifier , which EscalationGameFactory deploys in its constructor, has no bit. The tables use the deploymentSteps labels. In the Sepolia manifest the genesis REP step has the id reputationToken and the label GenesisReputationToken . It is the token at network.genesisRepTokenAddress , not a child ReputationToken .","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"deployment-mask-decoder","heading":"Decode a deployment mask","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Decoded status Loading the canonical mapping… Network Ethereum mainnet Sepolia Mask value The decoder maps each set bit to the selected network's constructor address at the same index. Retry loading the canonical mapping","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"limit","heading":"Why the cap is 256 steps","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"The constructor requires deploymentAddresses.length <= uint256(type(uint8).max) + 1 , which is 256 . The limit exists because the result is a single uint256 , and each tracked step consumes one bit. Indices 0 through 255 are supported. A deployment process with more than 256 tracked addresses must split status across multiple masks or use a different representation.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"interpretation","heading":"Interpretation and verification boundaries","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Evidence What it proves What it does not prove Bit set Runtime bytecode exists at the configured address. Correct bytecode, constructor values, wiring, permissions, or operational readiness. Bit clear No runtime bytecode was observed at that address by this call. Whether the address is intentionally empty or the manifest is wrong. Manifest match The decoder used the intended ordered address list for the network. That deployed code matches the release or that remote procedure call (RPC) responses are honest. Full deployment verification Code hashes, required wiring, permissions, and manifest provenance can be checked together. Economic safety or future operational liveness.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"interpretation","heading":"Static decoder test vectors","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Mask Meaning 0x0 No tracked constructor address contains runtime code. 0x1 Only constructor address index 0 is present. 0x5 Constructor address indices 0 and 2 are present. 2^255 Only the highest supported bit, index 255, is present. The interactive tables require JavaScript. The ordered source lists are available in the mainnet deployment manifest and Sepolia deployment manifest ; bit i always corresponds to the i th constructor address after excluding deploymentStatusOracle .","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["MMR","carry proof","hashing","nullifier"],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Statoblast uses a Merkle Mountain Range (MMR) only for inherited escalation carry: the unresolved deposits a parent Escalation Game exports when its universe forks. Each child universe 's continuation game, the child Escalation Game that resumes the dispute during fork continuation , verifies withdrawals against those compact snapshots without replaying the full parent history on-chain. The hashing primitives live in MerkleMountainRange.sol . Snapshot storage, proof structs, peak bounds, and replay protection live in EscalationGameTypes.sol , EscalationGameCarry.sol , and EscalationGameProofVerifier.sol . Local carry appends live in EscalationGameDepositDelegate.sol .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":1},{"fragment":"leaf-shape","heading":"Leaf fields","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each leaf commits to one unresolved deposit. The encoding fixes the field order and hashing. Field Why it is committed depositor Binds the payout to the original depositor; see VAULT-04 . outcome Separates Invalid, Yes, and No carry domains. amountAttoRep Commits to the source principal. parentDepositIndex Provides the stable identity that selects the deposit's leaf in the nullifier tree , the per-continuation record of claimed carried deposits that prevents a proof from being replayed. cumulativeAmountAttoRep Preserves payout-order prefix data. sourceNodeId Distinguishes otherwise identical leaves copied from different local nodes.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"encoding","heading":"Normative encoding","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"The leaf ABI types are (address,uint8,uint256,uint256,uint256,uint256) , in the order depositor, outcome, amountAttoRep, parentDepositIndex, cumulativeAmountAttoRep, sourceNodeId . outcome is the Solidity enumeration ordinal ( 0 Invalid, 1 Yes, 2 No). Leaf hashing uses standard ABI word padding through abi.encode ; parent hashing uses the 64 raw bytes from abi.encodePacked(left, right) , so the order of left and right is significant. There is no additional domain separator. leafHash = keccak256(abi.encode(depositor, outcome, amountAttoRep, parentDepositIndex, cumulativeAmountAttoRep, sourceNodeId)) parentHash(left, right) = keccak256(abi.encodePacked(left, right)) // peaks[0..peakCount-1] are the occupied peaks in ascending height order bagPeaks(peaks, peakCount): if peakCount == 0: return bytes32(0) root = peaks[peakCount - 1] for i = peakCount - 1 down to 1: root = parentHash(peaks[i - 1], root) return root The fold starts at the highest occupied peak and places each lower peak as the left operand. With occupied heights 0 , 2 , and 3 , the root is parentHash(peak0, parentHash(peak2, peak3)) . A single peak is the root itself, and an empty range has root bytes32(0) . Proof verification rejects each of the following with the quoted revert string: an outcome whose snapshot has no leaves: Carry peak absent ; a zero amountAttoRep : Proof amount zero ; leafIndex >= leafCount : Bad carry leaf ; a merkleMountainRangePeakIndex that is not the height of the peak containing leafIndex : Bad carry peak ; a sibling array whose length is not peakHeight + peakCount - 1 : Bad MMR proof length ; a reconstructed root that differs from the bagged snapshot peaks: Bad carry proof ; a nullifier path whose length is not 64 : Bad nullifier length ; a nullifier path that does not reproduce the current nullifier root from an empty leaf, which includes an already-consumed nullifier: Bad nullifier proof .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"encoding","heading":"Conformance vectors","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Input or intermediate Value Leaf 0 ABI values 0x0000000000000000000000000000000000000001, 0, 1, 0, 1, 0 Leaf 0 hash 0xb01042d963a0c261d64893dfb7e1f221c93ef608653cb92f9ca2c8899ca4572b Leaf 1 ABI values 0x0000000000000000000000000000000000000002, 1, 2, 1, 2, 1 Leaf 1 hash 0xe0ca39e8852dc96783e8b8f0859cfbf155338f9144ba4b9fdd6af847299fc867 Two-leaf root 0x1c9c7f3c2c8bebf92ce393deb5dccdd253f2b10084af72defb5dcd4486832b27 Leaf 2 ABI values 0x0000000000000000000000000000000000000003, 2, 3, 2, 3, 2 Leaf 2 hash 0x92b2040f7e9b4f1e1b587eda2fb255419704a6ea1693789658adfddbf98389ae Three-leaf root 0x3488c83edd77c5259c9432e90f972d45d0ced819fd3691eddfe41fe05d676564 Empty nullifier root 0xe2c3ed4052eeb1d60514b4c38ece8d73a27f37fa5b36dcbf338e70de95798caa","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"peaks","heading":"Peaks and the 64-peak bound","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"The carry snapshot stores one peak per set bit in the leaf count. The system fixes MERKLE_MOUNTAIN_RANGE_MAX_PEAKS = 64 , and carry initialization requires each snapshot leaf count to be less than 2^64 . The constant caps the number of peak positions, not the number of leaves: any leaf count from 0 up to but not including 2^64 fits inside 64 peak slots. A leaf count of thirteen is shown as binary one one zero one, corresponding to occupied peaks at heights zero, two, and three which are later bagged into one root. MMR peaks. The occupied peak heights are exactly the set bits in the snapshot leaf count. To form one root, the verifier collects the occupied peaks in ascending height order and folds them with bagPeaks . snapshotLeafCount < 2 64 Carry initialization rejects a larger leaf count with Leaf count high . Local carry appends behave like binary addition with carries: a new leaf merges upward through occupied lower peaks until it finds the first empty peak slot. If that upward carry would reach height 64 , the append reverts with MMR too tall .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"proofs","heading":"Proof structure","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"A carried-deposit proof has two parts. First it proves membership in the inherited MMR snapshot for one outcome. Then it proves that the same parentDepositIndex has not already been consumed in this continuation's nullifier tree. Component Purpose leafIndex , merkleMountainRangePeakIndex , merkleMountainRangeSiblings Proves the carried deposit belongs to the inherited snapshot root for that outcome. nullifierSiblings Proves the nullifier leaf is still empty so the carried deposit cannot be replayed. The membership lane combines the carried deposit leaf with bottom-up siblings inside its selected peak, then with other occupied peak roots in ascending height order to reconstruct the snapshot root. The nullifier lane hashes the stable parent deposit index and combines it with a fixed-depth sibling path to prove the claim has not already been consumed. Carry proof anatomy. The MMR sibling array first reconstructs one selected peak and then supplies every other occupied peak. The independent 64-level nullifier path prevents the same stable deposit identity from being consumed twice. merkleMountainRangePeakIndex is the occupied peak height, not the ordinal position of that peak among occupied peaks. leafIndex is the leaf's global position across the whole snapshot. The verifier derives the peak that contains that position, requires merkleMountainRangePeakIndex to equal its height, and orders the in-peak siblings by the in-peak offset leafIndex - peakStart , where peakStart is the peakStartIndex returned by getCurrentCarryPeakForLeaf . Claim accounting also keys inherited-versus-local provenance and settled principal by the global position. For example, if the full snapshot has 13 leaves, the height- 3 peak holds global leaves 0 through 7 , the height- 2 peak holds 8 through 11 , and the height- 0 peak holds 12 . A proof for the third leaf of the height- 2 peak uses merkleMountainRangePeakIndex = 2 and leafIndex = 10 ; its in-peak offset is 2 . merkleMountainRangeSiblings is also ordered in two phases. The first merkleMountainRangePeakIndex entries are the bottom-up Merkle siblings inside the selected peak. The remaining entries are the other occupied peak roots in ascending peak-height order, skipping the selected peak height. That exact ordering is why the verifier checks merkleMountainRangeSiblings.length == peakHeight + peakCount - 1 .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"nullifier-tree","heading":"Nullifier tree","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each continuation outcome keeps a binary Merkle tree of fixed depth NULLIFIER_DEPTH = 64 , hashed with the same parentHash . The path is uint256(keccak256(abi.encode(parentDepositIndex))) . Only its low 64 bits are used: bit d , counted from the least significant bit, selects the side at depth d , starting at the leaf. A 0 bit hashes parentHash(node, sibling) ; a 1 bit hashes parentHash(sibling, node) . An unconsumed leaf is bytes32(0) ; a consumed leaf is bytes32(uint256(1)) . The empty root is bytes32(0) hashed with itself 64 times: root = parentHash(root, root) . Its value is in the conformance vectors . nullifierSiblings lists the 64 siblings from the leaf upward. The verifier recomputes the current root with the empty leaf, then stores the root recomputed with the consumed leaf.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"mmr-proof-planner","heading":"Plan a carry proof","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Choose a snapshot leaf count and one occupied peak. The planner reports the global leafIndex range of that peak, checks an in-peak offset, and reports the exact sibling-array lengths the verifier enforces. It does not construct hashes or replace an off-chain proof builder. Selection Valid in-peak offset Selected peak capacity 4 leaves; leafIndex 8…11 Snapshot Snapshot leaf count Occupied peak height Height 2 Proof position In-peak offset MMR sibling hashes required 4 Nullifier sibling hashes required 64 Binary leaf count 1101₂ Occupied peak heights 0, 2, 3","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"snapshots","heading":"Snapshots in child continuations","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each continuation outcome stores both an inherited snapshot baseline and a mutable current state. Field Meaning snapshotLeafCount and snapshotPeaks The immutable inherited carry commitment. currentLeafCount and currentPeaks The descendant carry snapshot after inherited snapshot initialization plus local carry appends and local carry-leaf removal. Inherited proof consumption is tracked by currentNullifierRoot and unresolved totals rather than by mutating these peak fields directly. inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep The principal totals the current carry state must still represent. currentNullifierRoot The replay-protection root after any carried proof has been consumed. getForkCarrySnapshot() reports the current carry peaks, leaf counts, totals, and nullifier roots after local appends and proof consumption. getCarryLeafPageByOutcome() pages only local unresolved leaves.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"sources","heading":"Sources","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"MerkleMountainRange.sol EscalationGameProofVerifier.sol EscalationGameCarry.sol EscalationGameTypes.sol EscalationGameDepositDelegate.sol","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"","heading":"","keywords":["Statoblast","markets","security pools","overview"],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"Prediction markets Follow one question: “Will the fictional Aurora spacecraft launch before 31 December 2030?” Statoblast creates a collateralized market with Yes, No, and Invalid shares, resolves ordinary disagreement locally, and uses Zoltar branches only when local resolution cannot produce a decision or another fork interrupts the pool.","title":"How Statoblast works","topic":"Protocol","weight":1},{"fragment":"mental-model","heading":"1. Mental model","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Statoblast is the market layer. For each question, universe, and pool configuration (security multiplier and oracle priority fee) it deploys one SecurityPool that holds ETH settlement collateral , tracks vault owners' underwriting commitments , and mints, migrates, and settles shares. Zoltar owns the questions, universes, REP, and forks underneath it; Trading and OpenOracle sit beside it. The system overview introduces all four. The example question enters a SecurityPool. Local reporting may resolve the market or produce a non-decision; an independent fork of the pool's universe can also interrupt the pool while it remains unresolved and operational. Either fork trigger leads through child migration, collateral repair where needed, and branch-specific redemption. Market lifecycle. Local resolution is the ordinary route. An own-question non-decision or an independent universe fork while the pool remains unresolved and operational enters the migration and collateral-repair route.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"normal-lifecycle","heading":"2. Normal market lifecycle","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Register the example question in Zoltar and deploy its SecurityPool in one universe. Vault owners deposit REP; traders deposit ETH to mint complete sets. Traders may exchange shares through an exchange such as Trading . After the question ends, the first REP deposit on an outcome opens the Escalation Game . An unchallenged report wins three days later; a contested game runs until one outcome is the strict leader at its deadline. Holders then redeem winning shares from the pool's settlement collateral. ETH mints Invalid, Yes, and No shares. Operational pools redeem full sets, and finalized winning shares redeem through outcome settlement. Share lifecycle. One unit of ETH mints matching Invalid, Yes, and No claims; the complete set can be burned while the pool is operational or the winning share redeemed after finalization.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"participants-assets","heading":"3. Participants and assets","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Traders and liquidity providers Mint complete sets, hold or trade outcome shares, redeem claims, and optionally provide Yes/No liquidity. Vault owners Deposit REP, set a separate underwriting commitment in ETH, keep it backed, earn fees, and may report or migrate. Reporters Place REP-backed positions on Invalid, Yes, or No in the Escalation Game. Liquidation receivers and operators A receiver vault accepts a transferred underwriting commitment and receives REP backing. An operator submits the operation but receives no automatic protocol payment. Truth Auction bidders Supply ETH in exchange for child-pool REP-backed accounting positions when a child needs collateral repair. Asset or claim What it represents Where it is held or recorded ETH settlement collateral Backing for outstanding complete sets The SecurityPool; it is allocated, not copied, during migration REP Universe-specific reporting and security capital; never settlement collateral Wallets, SecurityPool vault accounting, Escalation Games, or migration contracts Outcome shares Yes, No, or Invalid claims for one pool and universe An ERC-1155 ShareToken deployed once per origin pool and reused by all of its fork descendants Underwriting commitment ETH a vault owner agrees to underwrite; its share of the pool total sets the vault's collateral obligations and fee rights SecurityPool vault accounting Escalation claims REP-backed positions on reported outcomes The Escalation Game until claimed or migrated Trading LP tokens A claim on one trading pool 's Yes and No reserves The trading pool's ERC-20 ledger","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"local-resolution","heading":"4. Local resolution","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# The game opens with the first REP deposit after the question ends. REP-backed balances then accumulate behind Invalid, Yes, and No. Their median is binding capital and determines the moving deadline. After that deadline, exactly one strict balance leader produces the local winner. Winning shares redeem from that pool. If two outcomes reach the non-decision threshold , the game does not choose between them. Anyone can then fork the universe on the market question through Statoblast, which pays the fork threshold from the REP held by the pool and the game. See the Escalation Game explanation for the required-support curve, deadlines, payouts, and how games continue across forks.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"forks-migration","heading":"5. Forks and migration","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# An unresolved operational pool can enter the fork path in two ways. Its own Escalation Game can reach non-decision and fork Zoltar on the market question; in this example, that creates Invalid, Yes, and No children. A fork of the pool's universe on another question can also interrupt it, in which case the children represent that categorical or scalar question's valid answers. A finalized pool remains settled and rejects later fork migration. A pool moves from active operation through fork, child deployment, REP and collateral migration, and any auction repair to an operational child. Fork timeline. The parent halts permanently; each child becomes operational only after migration and any required repair. Migration is open for a migration window of eight weeks, counted from the call that puts the parent pool into fork mode. A vault's parent backing claim, underwriting commitment, and proportional pool collateral are routed into one selected child pool. The same parent vault migration cannot be reused across siblings. Eligible outcome-share balances work differently: users can materialize branch-specific ledger claims in multiple selected child pools. That reproduces claims, not ETH; see what Zoltar does not guarantee . The full eligible source balance can materialize in each selected child as a separate branch claim, while the source remains locked. ETH is not copied. Share migration. Branch-specific token claims may appear in more than one child; settlement collateral follows vault migration and remains finite. If a child receives too little ETH, it can sell child REP through a one-week Truth Auction, which anyone can start once the migration window has closed. Full demand can repair the shortfall; weak demand can leave redemption below face value. A child begins with a collateral shortfall. Auction ETH may fully repair it, partially repair it, or leave it unchanged when there is no demand. Collateral repair. The auction raises what demand supports and never selects truth.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"fees-capacity-liquidations","heading":"6. Fees, underwriting, and liquidations","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# REP deposits do not create underwriting commitments; each vault owner sets one separately. A vault's share of total commitments sets its share of the pool's settlement collateral obligations and of the open-interest fees that outstanding collateral pays. New complete sets can be minted only while total commitments cover the resulting collateral and no Escalation Game has opened. Minting needs no oracle price or backing check, because vault owners already answer for their full commitments ( invariant BAL-03 ). A vault whose REP no longer backs its commitment can be liquidated: some or all of its commitment and backing move to an authorized receiver vault. See vault liquidation .","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"security","heading":"7. Security assumptions and non-guarantees","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# REP-backed incentives do not prove objective truth; users and applications decide which branches retain activity. OpenOracle depends on timely, profitable correction of inaccurate REP/ETH reports. A fork gives each child only the ETH that migrates to it ( Zoltar's non-guarantees ). ETH pushed into a pool outside its accounting is not counted as collateral. Steps that anyone may trigger, such as forking or starting an auction, still need someone to send the transaction. Spot prices from trading pools are manipulable and are never protocol oracles. Normative assumptions and guarantees are listed in the security model and invariant catalog .","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"security","heading":"Design rationale","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"Statoblast's ancestry includes the Arctic Tern Oracle , Sisyphean Exchange , Partial Colored Coins , and Isonzo . Those research ideas influenced the design; the deployed contracts govern current behavior.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["Zoltar","universes","questions","REP"],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"Branching universes Zoltar records global questions and lets an eligible parent universe branch into outcome-specific child universes . Each child universe has its own REP ledger, and REP holders move into children under fixed migration rules.","title":"Zoltar and branching universes","topic":"Protocol","weight":1},{"fragment":"branching","heading":"A parent becomes separate child ledgers","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# For a binary market question, one forking parent universe creates separate Invalid, Yes, and No child ledgers. An unrelated fork instead follows its own fork question's valid answers. Forking parent Invalid branch Valid outcome branches Branch set. A binary launch question produces Invalid, Yes, and No children. Alice converts 100 parent REP into a migration balance , a parent-universe credit that can mint the same amount in each valid child, and uses it to mint 100 child REP in the Yes universe and 100 child REP in the No universe. These are separate branch-specific ledgers. They are not 200 globally interchangeable REP, they do not copy ETH, and Zoltar does not guarantee equal economic value across branches. Applications and users later determine where economic activity continues.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"questions","heading":"Global questions and fork eligibility","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Questions are global Zoltar objects and are not bound to a universe. Any account can fork a universe by naming a question when three conditions hold: the universe has not forked before, so each universe forks at most once; the question exists and its end time has passed; and the caller supplies the full fork threshold in that universe's REP. Zoltar does not check that the question concerns the universe, so applications such as Statoblast enforce any stricter relationship they need. The fork question decides which child universes can exist: one for each of its valid answers. A categorical question allows Invalid and each of its labels. A scalar question allows Invalid or a well-formed packed scalar answer. Zoltar sets no migration deadline; REP holders can add to their migration balance at any time after the fork.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"guarantees","heading":"What Zoltar guarantees","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Universe and child identities derive deterministically from their parent and outcome. Only valid outcomes for the fork question can create child universes or receive child REP. Each account cannot mint more REP into one child than its recorded migration balance permits. Child REP is controlled by Zoltar and remains tied to its universe identity. Every child starts with the parent's pre-fork theoretical REP supply , the per-universe supply figure from which fork thresholds are derived, less exactly the fork haircut .","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"non-guarantees","heading":"What Zoltar does not guarantee","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# It does not choose a truthful or canonical child. It does not copy ETH or application state into every child. Each child receives only the collateral that migrates to it, so a Statoblast child pool can remain impaired if too little ETH follows and its Truth Auction cannot raise the difference. It does not guarantee equal REP value, liquidity, or redemption across branches. It does not prove a supplied global question is relevant to the universe being forked. It does not guarantee that applications continue in every branch.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"accounting","heading":"Deterministic identities and migration accounting","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# A child universe ID is derived from its parent universe ID and selected outcome. Child REP uses a predictable deployment address derived from the Zoltar address and universe ID. Adding parent REP to a migration balance burns or transfers it from the parent ledger. That balance can then materialize the same branch-specific amount in multiple valid children, with per-child accounting preventing replay beyond the source amount. Starting a fork removes the fork threshold from parent supply. The threshold is the live universe theoretical REP supply divided by the threshold divisor, rounded up, so every universe with nonzero supply has a positive fork cost. The fork haircut, the threshold divided by the burn divisor and rounded down, is not credited to migration; the remainder becomes the initiator's migration balance. Both divisors are fixed when Zoltar is deployed. The configured defaults are a threshold divisor of 20 and a burn divisor of 5: the threshold is 5% of supply and the haircut is 20% of the threshold, about 1% of supply. Zoltar rejects a burn divisor below 5, so the haircut never exceeds 20% of the threshold. The full fork threshold leaves parent supply. Most becomes the initiator's migration balance and the fork haircut is not credited. Fork deposit. The default split, subject to integer rounding. fork threshold = ⌈live theoretical REP supply ÷ threshold divisor⌉ fork haircut = ⌊fork threshold ÷ burn divisor⌋ Each fork reduces theoretical supply by its fork haircut, so later thresholds decline along that lineage. Repeated forks. Integer-rounded fork haircuts reduce theoretical supply and therefore later fork thresholds.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"encodings","heading":"Question and outcome encodings","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Question IDs hash the stored question data together with the outcome labels, which a categorical question must supply in strictly descending order of their hashes. A categorical answer is 0 for Invalid or a number from 1 to n that selects one of the n labels in that order. Scalar questions store a range and tick count; a valid packed answer allocates all ticks between its two payout fields. The all-zero word is canonical Invalid, while reserved-bit or payout-sum violations are malformed and rejected. A scalar answer contains reserved bits, a namespace bit, and first and second payout numerators. Valid payout fields sum to the question's tick count. Namespace bit First payout Second payout Packed scalar answer. Encoding validation keeps Invalid distinct from malformed input. Exact storage fields, permissions, and entrypoints are listed in the contract reference . Security assumptions are listed in the security model .","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["Trading","AMM","liquidity","prices"],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Explanation Trading is a separate on-chain exchange for Statoblast outcome shares , one of possibly many that can be built on Statoblast. Statoblast still owns market creation, collateral, migration, resolution, and redemption through each market's SecurityPool .","title":"How Trading works","topic":"Trading","weight":1},{"fragment":"complete-set-entry","heading":"From ETH to a directional position","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Each ETH entry first creates a complete set : one Yes, one No, and one Invalid share. A market's trading pool , a Yes/No pair, is an automated market maker (AMM) that holds only Yes and No reserves. The router sends the unwanted directional share into the pair, receives more of the selected directional share, and returns the directional position and the Invalid share to the user. The Invalid share never enters the AMM; it remains a separate claim if the market later resolves Invalid.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"prices","heading":"What the prices mean","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Yes and No prices are conditional on valid resolution. They describe the relative price of the two directional outcomes; they are not estimates of invalidity. Interfaces should therefore label the Yes and No values directly and present Invalid separately. Spot prices come from current reserves and are not an oracle . Settlement uses the SecurityPool's resolved outcome, while solvency-sensitive REP/ETH operations use OpenOracle.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"market-isolation","heading":"One pair per SecurityPool","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Each SecurityPool maps to its own pair. Parent and child pools therefore have separate pairs, reserves, prices, and liquidity-provider tokens; liquidity, like everything else in a fork , is not copied between them.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"reading-paths","heading":"Where to go next","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Learn by doing Your first Trading market and your first trade . Get something done Set up development , configure the UI , deploy the contracts , seed alternative odds , exit a position , remove liquidity , handle resolution , and handle a fork . Understand the design The two-way market , Invalid insurance , conditional pricing , the LP position , early-exit limits , forks and resolution , architecture decisions and limitations . Look something up Contracts , router , events , SDK , deployment configuration , invariants , units and rounding , and the security model .","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Escalation Game","disputes","deadlines","accounting"],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The Escalation Game gives a finished Statoblast market a local, REP-backed resolution path before a universe-wide fork is necessary. A report that nobody challenges wins three days after the first deposit opens the game. For a binary launch question, suppose Yes has 8 REP, No has 5 REP, and Invalid has 2 REP. The median balance, 5 REP, is the game's binding capital : the stake the strongest challenger has committed, and the amount that sets the scheduled deadline. A deposit that raises only the leading Yes balance does not move that deadline; a deposit that raises Invalid above 5 REP raises the median and moves it later. After the deadline, Yes wins only if it remains the unique strict leader. If two outcomes each reach the non-decision threshold before local finalization, the game records non-decision and the SecurityPool follows the Zoltar fork path. The threshold is half of Zoltar's fork threshold , rounded up, and is fixed when the game opens. A tie is never treated as a local winner. Any REP holder can deposit from a wallet, except in a game carried across a fork. A vault owner can instead deposit REP that already backs their vault; those deposits must additionally leave the vault and the pool sufficiently backed. Each deposit must meet the start bond , the larger of 1 REP and one ten-millionth of the universe's theoretical REP supply when the pool was deployed, unless it exactly fills an outcome to the non-decision threshold.","title":"Escalation Game","topic":"Protocol","weight":1},{"fragment":"escalation","heading":"Escalation","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The first deposit after the question ends opens the game. Each deposit adds to its outcome's cumulative balance; it does not have to exceed the leader. Meanwhile the required support rises along a fixed curve over time. The game's deadline is the moment required support overtakes binding capital, so the deadline moves later only when a deposit raises the median balance. A challenger that stops adding REP lets the rising requirement pass its stake, and the leader wins. Required support is zero through day 3, starts at the start bond just after day 3, and reaches the non-decision threshold on day 52. Required support. Nothing is required for the first three days. From day 3 the requirement climbs from the start bond to the non-decision threshold, reaching it on day 52. The EscalationGame reference gives the exact curve.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"escalation-game-example","heading":"Try a simplified escalation round","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"This simulator uses the contract model: a three-day activation delay, a 49-day escalation interval, and the fixed-point required-support curve. Change the configuration, then choose an outcome and requested deposit to see clipping, tie adjustment, acceptance, or rejection. Deposit result accepted: 1 REP Contract-model state activation pending Game settings Start bond 1 REP Non-decision threshold 10 REP Player positions Current Yes balance 1 REP Current No balance 1 REP Current Invalid balance 0 REP Player move Deposit outcome Yes No Invalid Requested deposit 1 REP Timeline Days since start 0 days Yes 1 → 2 REP No 1 → 1 REP Invalid 0 → 0 REP Configured start bond 1 REP Configured threshold 10 REP Projected leader Yes Projected median balance 1 REP Deposit before → after Yes 1 / 2 REP; No 1 / 1 REP; Invalid 0 / 0 REP Activation 3 days Scheduled deadline (before → after) day 3.0 → day 3.0","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"How the game ends","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The game ends in one of three ways: Strict local winner. After the scheduled deadline, exactly one outcome has the greatest balance. Statoblast finalizes on that outcome. Local non-decision. Two outcomes reach the non-decision threshold. Statoblast uses its fork path instead of choosing one locally. Interruption by another fork. The pool's universe forks on a different question at or before the deadline. The game has no local result and continues in the child pools instead; see forks and migration . Settlement rewards the side that held its ground. Winning deposits get their principal back plus a bonus. The runner-up's stake, the binding capital, pays for it: three fifths becomes the bonus pool and two fifths, the escalation haircut , is burned, unless the fork this game triggered already burned it as the fork haircut . REP staked on a third outcome is forfeited: a local game sweeps it to the SecurityPool, while a game carried across a fork burns it. The bonus is only available on the portion of winning deposits up to the reward-eligible cap , one and a half times binding capital; deposits beyond that cap simply get their principal back. Settlement also compares the universe's current fork threshold, in full, with the non-decision threshold the game fixed when it opened. If the current fork threshold is the lower of the two, every winning withdrawal is multiplied by the current fork threshold divided by that non-decision threshold, which can push the final transfer below principal. The comparison is skipped when the universe forked after the game ended. The EscalationGame reference works one payout through with exact numbers.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"Escalation game continuation","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"When a fork interrupts an unresolved game, Statoblast's SecurityPoolForker restarts it in each child pool as a carried game with the parent's balances and elapsed time. In a child created by a fork on the pool's own question, the outcome is already fixed to that child's outcome, so the game only settles deposits on it. After an unrelated fork, the game resumes and can still be contested, but only with vault-backed deposits. Depositors claim their positions in a child with a Merkle Mountain Range carry proof against the parent's deposit history, so no child copies every deposit onchain.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"Design rationale","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"Augur V2 cancelled active dispute games when a fork began and refunded their participants. Statoblast instead continues active games across the fork so a fork cannot erase the stakes players already put at risk. See the research note Zoltar forks should not cancel escalation games for the historical motivation.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["liquidation","underwriting commitment","backing constraints","operator","receiver vault","approval","reservation","bad debt"],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Liquidation moves part or all of an unhealthy vault's underwriting commitment , with a capped REP award, to an authorized receiver vault. The receiver must back its entire resulting commitment. Total commitments remain constant, so unrelated vaults retain their proportional obligations. The account that submits the liquidation receives no automatic protocol payment.","title":"Vault liquidation","topic":"Economics","weight":1},{"fragment":"position-model","heading":"Target, receiver, and operator","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"The target vault is the unhealthy vault whose commitment is reduced. The receiver vault accepts the transferred commitment and receives the REP award. The operator requests and stages the liquidation, paying that transaction's gas and any oracle cost. If the liquidation remains staged, any account may execute it later and pay the execution transaction's gas. The operator recorded at staging does not change when another account executes. The receiver and target must differ. The operator may be either one, but identity alone is not a health or Sybil-resistance boundary. Staging through the generic requestPriceIfNeededAndStageOperation call makes the operator the receiver and requires no signed approval; requestPriceIfNeededAndStageLiquidation names the receiver explicitly; a receiver other than the operator also needs a delegated approval. The first release assumes the operator and receiver coordinate compensation externally; the protocol neither creates a keeper marketplace nor takes a fee from the award.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"capacity-and-health","heading":"When a vault is liquidatable","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Each owner sets an underwriting commitment separately from REP deposits. A price change affects health, not commitments. Each vault covers settlement collateral in proportion to its share of total commitments, but health is measured against its entire commitment, so a vault may be liquidatable with zero settlement collateral. Vault health combines two backing constraints, each evaluated with upward rounding at the coordinator's fresh accepted oracle price . That price is quoted as REP per ETH, so a higher price means cheaper REP and a larger REP requirement. The associated-REP constraint requires pool-held backing plus eligible dispute stake to cover the commitment's REP value times the pool's security multiplier . The pool-held constraint requires pool-held backing alone to cover that REP value times a second multiplier: halfway between one and the security multiplier, but never below the liquidation reserve of 10,500 BPS (one plus the 5% award bonus). The reserve means a vault that meets the pool-held constraint holds enough REP to pay a full liquidation award. A liquidation executes only when the target fails at least one constraint, the oracle price exceeds the price at which the target first fails a constraint by at least minLiquidationPriceDistanceBps of the oracle price (10% in the deployment configuration), and neither the target nor the receiver carries bad debt . The distance guard keeps a slightly wrong accepted price from liquidating a vault that is only marginally unhealthy. The SecurityPool reference specifies the exact checks. A delegated approval may demand that the receiver be healthier than the protocol minimum after the transfer. That requirement is checked against live post-liquidation state at execution; a queue-time preview is never a guarantee. The LiquidationApprovalRegistry reference defines the field.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"rule","heading":"Commitment transfer and residual exposure","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"The requested amount bounds the commitment transferred. The REP award is the moved commitment's REP value at that price plus a 5% bonus, capped by the target's transferable backing; a partial liquidation also leaves the target its minimum REP deposit. A sufficiently funded receiver can take the entire commitment even when the award is underfunded. Partial liquidation leaves the residual commitment with the target; it writes off nothing and deletes no settlement liabilities. Commitment and capped REP move from the target to the receiver. Total commitments stay constant. Residual commitments and earned fees remain with the target. Commitment transfer. The receiver authorizes the transferred commitment and backs its entire resulting commitment. The receiver must authorize the transferred commitment and satisfy both backing constraints for its entire resulting commitment. Remaining target commitments and receiver positions must meet the minimum sizes. Earned fees stay with their owners and are checkpointed before weights move. Retained underbacked commitments continue earning fees; poor health does not suspend fee rights. The contract reference specifies award rounding.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"receiver-approvals","heading":"Bounded receiver approval","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"A receiver can approve an operator directly or by a bounded signature. The approval is specific to a pool, limits how much commitment the receiver will accept, sets a validity window and minimum resulting health, and can be revoked for future liquidations. A liquidation that is already staged keeps its reservation. See the LiquidationApprovalRegistry reference for fields, nonce rules, and wallet-signature handling.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"queue-semantics","heading":"Reservation and queued execution","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"When the receiver is not the operator, the price coordinator reserves the receiver's approval quota when the liquidation is staged, whether it runs immediately on a fresh REP-per-ETH price or waits for one. Execution then rechecks the live target and receiver rather than trusting the earlier preview. Success consumes only the commitment actually moved and releases unused quota; expiration or terminal failure releases the reservation so the receiver is not blocked permanently. The REP/ETH oracle operations reference covers staging, recovery, and failure handling.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"fork-behavior","heading":"Fork isolation","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Approvals and reservations belong to one pool and its coordinator and are not copied into child pools or universes; see what Zoltar does not guarantee . A receiver approving liabilities in one universe has not approved them in a child. Pending parent operations remain permissionlessly cleanable after the parent becomes unable to execute, releasing their reservations.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"related-references","heading":"Related references","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"SecurityPool functions and accounting Liquidation approval fields and signatures Price-coordinator operations and recovery","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["fees","open interest","retention","utilization","vaults"],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"Each SecurityPool charges an open-interest fee on its outstanding settlement collateral and pays it to the vaults that underwrite that collateral. The contracts express the fee as retention : the per-second fraction of collateral that stays with complete-set holders.","title":"Open-interest fees","topic":"Economics","weight":1},{"fragment":"why-fees-exist","heading":"Why the fee exists","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"Vault owners provide REP-backed security, keep their vaults healthy, and may need to take part in reporting and migration. In return, each fee-eligible underwriting commitment earns a share of the fee in proportion to its size. Collateral gradually decays into an unallocated fee reserve , and vault owners claim their shares from that reserve.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"rate","heading":"How the rate moves","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"The retention rate depends on utilization : settlement collateral divided by minting capacity , which equals the pool's total underwriting commitments, independent of price and backing. The per-second retention rate declines linearly as utilization rises and stops declining at the dip point, 80% utilization. Compounding the two per-second constants over a 365-day year, the annualized fee rises from about 9.5% at zero utilization to about 50.2% at the dip point and then holds. Security therefore becomes more expensive as open interest consumes underwriting slack. Retention and utilization curve. The annualized fee rises from its minimum at zero utilization to its maximum at the dip point, then remains flat. Annualized fee against utilization. Past the dip point the per-second retention rate is already at its minimum, so the fee stops rising. Minting capacity is zero when the pool has no commitments or once an Escalation Game has opened. The retention rate then returns to its maximum, MAX_RETENTION_RATE , which is the lowest fee, instead of treating the pool as fully utilized. The SecurityPool reference lists the constants, the dip point, and the formula clients use to annualize the rate.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"earning-and-cutoff","heading":"Who earns and when accrual stops","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"A pool with no fee-eligible commitments accrues no fee. Fees charge only the fraction of settlement collateral assigned to fee-eligible commitments. Retained underbacked commitments keep earning fees, and previously earned fees remain claimable. Ordinary redemption reduces settlement collateral without retiring underwriting commitments. When a child pool's Truth Auction finalizes with no purchases, its unassigned commitment stays visible but has no fee recipient until a vault takes over the entire residual commitment and backing and fully backs the result. Fee eligibility starts at takeover, without retroactive rewards. Migrated commitments and sold auction commitments enter the fee denominator at finalization, even when a winning bidder claims later. Accrual stops at a cutoff. An origin pool uses question end. If its question remains unresolved when the universe forks, fork time replaces that cutoff in either direction: a fork before question end stops accrual early, and a fork during an unresolved Escalation Game moves the cutoff later, so the next accrual also charges the interval from question end to the fork. A later unrelated fork does not reopen fees for an already finalized question. A child starts a new epoch when migration and any Truth Auction finalize, then accrues until local resolution or another fork; a child with a fixed outcome and no continuation game accrues no further fees. Accrual is lazy: state-changing pool operations checkpoint a global fee index, and vault operations checkpoint each vault against it, so no call iterates over every vault. Fractional amounts wait in explicit remainders until they reach whole attoETH. See the subsystem guardrails for checkpoint and fork-reconciliation sequencing and the SecurityPool contract reference for exact state transitions.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["truth auction","clearing","settlement","repair"],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"When a universe forks, each unresolved Statoblast SecurityPool splits into child pools, one per child universe ( forks and migration ). Each vault owner moves its REP and its share of the parent's settlement collateral into one child of its choice, so a child receives only the collateral of the vaults that chose it. Suppose the parent held 100 ETH of settlement collateral when it forked and a child receives only 70 ETH through migration. The child inherits the parent's full share supply, so its Truth Auction tries to raise the missing 30 ETH by selling child REP. Full repair: bidders contribute 30 ETH, so the child reaches its 100 ETH target. Partial repair: bidders contribute 12 ETH, so the child operates with 82 ETH and remains impaired. No demand: no qualifying bid contributes ETH, so the child remains at 70 ETH. The auction repairs collateral and never selects truth. It sells REP belonging to an already-defined child universe. The child resumes with only the ETH that migration and accepted bids actually provide.","title":"Truth Auctions","topic":"Economics","weight":1},{"fragment":"lifecycle","heading":"Lifecycle","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"Auction Lifecycle. After migration closes, startTruthAuction either activates the child immediately when no sale is needed or opens bidding. During bidding, once demand establishes a clearing tick, bids below it may refund before finalization. Finalization later activates the child; paged calls then settle winning and partial bids plus any remaining refunds. Auction lifecycle. The no-sale branch skips bidding entirely. On the repair branch, early refunds are optional and every path reaches finalization before winning bids settle.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Starting the auction","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The start call is permissionless but not automatic. It is valid strictly after the parent pool's migration window , which lasts eight weeks from the call that put the parent pool into fork mode, and it records the actual auction start time. That timestamp starts the one-week bidding window.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Bidding","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"Bidders submit bids at discrete price ticks , where each tick represents a maximum price in ETH per REP that the bidder is willing to pay. This is the inverse of the REP-per-ETH oracle price that vault health uses. Ticks are spaced geometrically, so each step changes the price by the same small percentage, as in Uniswap. The auction reference gives the base price, the step factor, and the supported range. Losing bids can be settled before finalization once current demand is enough to find a clearing tick. Only ticks below that clearing tick can use the pre-finalization path; binding or potentially winning bids stay in the auction. Settlement credits refundable ETH to the recorded bidder without calling recipient code. The bidder then calls withdrawPendingEthRefund to pull the complete credit. Once a clearing tick is found, it cannot be lowered, so currently losing bids remain losing bids.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Bidding end","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"When bidding ends, anyone may finalize the auction. Finalization clears the batch auction, sends the raised ETH to the child pool, and computes the accounting rates used to settle bidders. The child activates with the settlement collateral that migration delivered plus the accepted bid ETH, even when that total is below the parent's snapshot. Full repair is not guaranteed, and the remaining impairment is borne by the affected child's outcome-share holders, whose winning shares redeem below face value. Until winning bids are settled, the REP backing and commitment they bought sit in a position that no vault owns. Anyone may settle a winning bid, which credits the bidder's child-pool vault with its proportional REP backing units , underwriting commitment , and accrued fees; the auction does not send REP directly to the wallet. ETH pushed into the pool outside migration and the auction is not counted as collateral, so it cannot fake a successful repair.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"clearing","heading":"How clearing works","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The clearing process walks demand from the highest price downward. A bid above the clearing tick wins in full, a bid below it loses in full, and bids at the clearing tick share the last fill in the order they arrived. Two constraints limit how much the auction can clear: ETH raise cap. The auction raises no more ETH than the amount required to make share holders whole. REP sale cap. The auction sells no more REP than the child pool offers: its pool-held REP plus any REP staked in an unresolved Escalation Game, less a small retained residue. As soon as cumulative demand is enough to hit either cap at some price, that price becomes the clearing tick and all winning bids settle from it at one price. That is a valid uniform clearing even when the REP cap binds before the ETH repair target is fully met.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"clearing","heading":"When demand is too low","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"If demand never reaches either cap, only bids at or above the underfunded threshold participate: the price at which selling the whole REP sale cap would raise exactly the ETH raise cap. Lower bids receive refunds. Qualifying bidders share the whole REP sale cap in proportion to the ETH they contribute, so each pays the same effective price. With no qualifying demand, all bids refund and the child remains impaired. The contract uses bounded tick indexing and exact integer accounting so finalization does not loop over every possible price. See the auction contract reference for tick bounds, rounding, storage, and getter details, and the SecurityPoolForker reference for child-pool settlement accounting.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"interactive-example","heading":"Interactive clearing example","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The interactive example shows the uniform-clearing path, the underfunded path, and how the same bid ladder reacts when the ETH cap, REP cap, and bid sizes change.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"simple-auction-example","heading":"Try a simple auction clearing run","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The simplified calculator visualizes both finalized branches with three fixed price levels and real-number arithmetic. The clearing section specifies the contract's exact tick and cumulative-floor behavior. Mode uniform clearing near 3 ETH/REP ETH retained 12 ETH Auction settings ETH raise cap 12 ETH REP inventory 4 REP Player bids Alice bid near 5 ETH/REP 3 ETH Bob bid near 4 ETH/REP 4 ETH Carol bid near 3 ETH/REP 6 ETH High-price bids are considered first. If cumulative demand reaches the ETH raise cap or REP sale cap, the first binding tick sets normal uniform clearing. If neither cap is reached, finalization selects bids at or above the underfunded threshold and allocates the complete REP sale cap among them at one effective price. With no qualifying bids, every bid refunds. Interactive Demand Curve The stepped curve accumulates bids from the highest limit price to the lowest. The vertical rule is available REP, the horizontal rule is the current clearing price or underfunded threshold, and each bid point's shape and colour, named in the chart key, shows whether the bid wins in full, fills partly at the boundary, or is refunded. The chart updates as the auction controls change. Binding condition both caps Winning ETH kept not underfunded Underfunded threshold not underfunded Alice allocation 1.00 REP Bob allocation 1.33 REP Carol allocation 1.67 REP Total REP allocated 4 REP Refunds 1.00 ETH","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"three-auction-outcomes","heading":"What the contract reports","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The contract does not report full, partial, or no repair. It reports whether a cap bound: No auction runs when ETH migrated into the child already reaches the parent's settlement-collateral snapshot; the start call activates the child directly. A funded auction, reported by the funded field of the AuctionFinalized event, means a clearing cap bound. It is a full repair when the ETH raise cap bound and a partial repair when only the REP sale cap bound, so compare accepted ETH with the ETH raise cap. An underfunded auction means neither cap bound. It is a partial repair when some bids qualified at or above the underfunded threshold and no repair when none did. If the parent's Escalation Game was unresolved at the fork, part of the REP either kind of auction sells comes proportionally from REP staked in that game, and the child game's balances shrink to match. The SecurityPoolForker reference gives the allocation.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","price","coordinator","callback"],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"Explanation Statoblast needs a fresh REP/ETH exchange rate (quoted as REP per ETH) when it measures whether REP adequately secures ETH obligations. OpenOracle supplies an economically contestable price. A reporter posts a WETH/REP position at the claimed price, and anyone who believes the price is wrong can replace the report by trading against that position, so an inaccurate report is a profit opportunity. OpenOracle never decides whether a prediction-market answer is Yes, No, or Invalid.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":1},{"fragment":"protected-operations","heading":"Protected operations","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"A per-pool price coordinator protects REP withdrawals, liquidations, and staged changes to a vault's underwriting commitment , because each depends on REP value. Vault-backed Escalation Game deposits also require a fresh accepted price when the pool has any underwriting commitment; wallet deposits do not. Each SecurityPool still applies its own current health and authorization checks after a price is available.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"cached-and-fresh","heading":"Cached and fresh prices","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"An accepted report becomes the coordinator's cached price for a limited freshness window. An operation can use that cache while it remains fresh. When it is stale, a sponsor funds a new report and the coordinator stages eligible work until settlement. A child pool may inherit a numeric starting value, but it cannot use that value until the child accepts its own report. A cached fresh price may execute a guarded operation immediately. Otherwise an accepted settlement callback refreshes the price and runs a bounded batch; a rejected report terminally consumes its attached batch. Overflow operations remain active for later execution with a fresh price. Price-guarded operations. The price coordinator supplies a fresh input; the SecurityPool still enforces live safety.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"example","heading":"One request, dispute, and settlement","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"Alice requests a REP withdrawal from her own vault while the pool's cached price is stale. She funds an initial REP/ETH report plus a settlement bounty, and the coordinator records her pending operation. Bob believes the report is inaccurate, so he replaces it with the required opposing position before settlement. The dispute restarts the settlement window. If nobody replaces Bob's report before its new deadline, any account can settle it; that settler collects Alice's bounty, and OpenOracle calls the coordinator. The coordinator validates the report, refreshes its cache, and attempts Alice's withdrawal against the pool's live safety checks. Bob's replacement traded against Alice's position at her reported price, so she ends with a different mix of WETH and REP rather than her original deposit; the coordinator forwards whatever OpenOracle credits it for her report back to her. Her bounty is spent on settlement whether or not her withdrawal later succeeds. Alice's staged withdrawal expires once the settlement period plus her chosen validity window (at most five minutes) has passed since she queued it. Because Bob's dispute restarted the settlement window, the price may arrive after that point; her withdrawal then fails as expired and she must stage it again.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"limitations","heading":"Security limitations","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"OpenOracle relies on participants noticing and profitably correcting inaccurate reports. Congestion, censorship, incorrect gas assumptions, insufficient economic incentives, or repeated disputes can delay or undermine that process. A fresh price is not a guarantee that an operation will succeed, and a settled price says nothing about the market question's outcome. Two limits are deliberate. First, the coordinator keeps no notional budget: one accepted price may authorize several operations during its freshness window, so the report position is a correction incentive rather than a bond sized to the value those operations move. Second, there is no absolute deadline: every valid dispute restarts the settlement clock, so a participant willing to keep funding replacements, each paying fees and posting the required position, can delay settlement indefinitely. The protocol does not claim liveness against such a participant. Each report is sized from a gas-cost assumption. The priority fee in that assumption is fixed when the origin pool is created and inherited by its children; it is not observed from the request block. If prevailing priority fees are higher, the modeled incentive for a disputer is weaker; a value set too high raises the sponsor's initial WETH and REP requirement and can make requests impractical. The reference's stress model estimates what it costs an attacker to hold a manipulated report against correction while collecting an outside payoff. Its results depend on a dispute barrier that the model does not derive: the default is only OpenOracle's fixed fees, and gas, priority fees, price impact, capital lockup, and price volatility over the settlement horizon all raise the real barrier (see OpenOracle's report-cost derivation ). A deployment analysis must calibrate that barrier and decide what interval one model step represents; the model's output is an estimate, not an exposure cap the contracts enforce. The OpenOracle integration reference specifies funding formulas, report sizing, sponsor rules, queues, callbacks, recovery paths, configuration, and interactive estimators. The security model states the participation assumptions.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["bots","liquidator","arbitrager","augurScan","research","README"],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Reference This site covers the protocol. The material below lives next to the code it describes and is not searchable from here. Each link opens the current version on GitHub.","title":"Further reading","topic":"Ecosystem","weight":1},{"fragment":"operators","heading":"Run something","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Document Who it is for What it covers Statoblast liquidator Vault operators and keepers Monitoring pool health, staging and executing liquidations, and the bot's dashboard. OpenOracle arbitrager Price correctors Finding mispriced REP/ETH reports, funding disputes against Uniswap quotes, executor deployment, and settlement tracking. Chaos bot and its operator reference Testnet operators Exercising permissionless protocol paths with real transactions, safety limits, and runtime controls. augurScan , its operations guide , API reference , and state model Indexer operators and integrators The read-only protocol explorer: deployment, backup and upgrade, the HTTP API, and how retained evidence differs from the current view. Local test network and Sepolia Reth node Developers and node operators Docker Compose setups for the repository-pinned Anvil chain and a pruned Sepolia execution and consensus pair.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"code","heading":"Read the code","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Document Who it is for What it covers Repository README Contributors Setup, local development, simulation mode, common commands, and validation. Contract layout and the Statoblast contract directory Auditors and contract developers Why source paths are stable, which directory owns which contracts, and the OpenOracle vendoring boundary. Security regression suite Auditors The focused tests that reproduce past security findings and how to add one. Shared TypeScript packages and core UI ownership Front-end and tooling contributors Package boundaries, build dependencies, and which layer may import which. Statoblast test slices Contract developers How the split Statoblast suites are run individually and together. Security pool workflow test slices Front-end contributors How the split security-pool workflow suites of the Statoblast UI are run individually and together. Token authorization provenance Auditors Where the EIP-712 and ECDSA signature helpers come from and what was changed. augurScan backend boundaries Indexer contributors Which backend directory owns HTTP, scanning, storage, and evidence types. UI features , UI protocol client , and UI copy modules UI contributors Where feature components, typed contract reads and writes, and user-facing text live, and which may import which. Visual foundation UI contributors The shared design tokens, product accents, and status treatments used by every interface.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"research","heading":"Understand the design history","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"The oracle-research repository holds the proposals, rejected alternatives, and open questions behind the protocol. It explains why the design looks the way it does; the deployed contracts and this site's reference pages describe what it actually does today.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","parameters","funding","callbacks","estimators"],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"OpenOracle supplies a fresh REP/ETH price for Statoblast's solvency-sensitive operations. It does not decide market truth; local Escalation Games and Zoltar remain responsible for truth and branching. The OpenOracle explanation covers why Statoblast uses a contestable price and which operations depend on it. This page specifies the integration: formulas, parameters, and settlement-callback behavior. Per-function callers, preconditions, and events are in the coordinator contract reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":1},{"fragment":"openoracle-role","heading":"Token pair and cached price","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Statoblast configures WETH as token1 and REP as token2 . Keeping WETH on the exact side lets the coordinator size the report directly from ETH-denominated gas costs without first assuming a REP/ETH conversion price. When a report settles, the coordinator converts the settled token amounts into REP per ETH: lastPrice = amount2 ⋅ 10 18 amount1 The settled REP amount ( amount2 ) is scaled by the fixed price precision and divided by the settled WETH amount ( amount1 ). This raw-amount ratio is valid because the configured WETH and REP contracts both use 18 decimals. The coordinator does not normalize token decimals in the settlement callback. An accepted report becomes the coordinator's cached REP/ETH price. Its freshness window is one hour on Sepolia and five minutes on other chains. The window starts at settlement eligibility (the final report timestamp plus settlementTime ), not when settle is called, and lastSettlementTimestamp records that start. A late settlement therefore cannot extend the life of a price that was frozen earlier. The coordinator does not meter how much operation volume uses that price during the freshness window.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"optional-upstream-capabilities","heading":"Report flags","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator always submits flags 7 : FLAG_TIME_TYPE ( 1 , a timestamp clock), FLAG_TRACK_DISPUTES ( 2 , per-dispute history), and FLAG_STORE_ALL ( 4 , the complete report state in storage). It never sets the optional flags 8 , 16 , 32 , or 64 ; the OpenOracle provenance record identifies the vendored source and build profile.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"statoblast-integration","heading":"Integration architecture","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Every security pool has its own OpenOraclePriceCoordinator . The coordinator connects users, the pool, and the shared OpenOracle instance. It keeps the pool's cached REP/ETH price, pending report state, staged-operation queue, and settlement callback state. Keeping this state per pool prevents one pool's pending report or freshness window from becoming a protocol-wide queue. OpenOraclePriceCoordinator is deployed with an immutable OpenOracle address. For each origin or child security pool, SecurityPoolFactory asks OpenOraclePriceCoordinatorFactory for a fresh coordinator wired to the shared OpenOracle instance, shared WETH, and that universe's REP token. SecurityPoolDeployer passes the coordinator to the pool, after which the factory calls setSecurityPool once with the nonzero pool address. Only the configured pool may seed the coordinator's inherited lastPrice . A child pool inherits the parent's numeric price as a starting value, but its settlement timestamp remains zero, so that number is unusable until the child accepts its own report. After OpenOracle settles, the coordinator validates the report. An accepted report refreshes the REP/ETH price and runs pending operations through local guardrails. A rejected report leaves the price cache unchanged and terminally fails the attached pending batch. Integration flow. The coordinator is the trust boundary between Statoblast operations and OpenOracle reports.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Price request lifecycle","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Liquidations, REP withdrawals, and staged underwriting-commitment changes ( OperationType.SetVaultUnderwritingLimit ) begin at the pool's coordinator. The coordinator validates and stages the operation, then uses a cached price or opens an OpenOracle report. Owners may also set commitments directly at the pool. REP deposits add backing without changing commitments. Exact permissions and guards are in the SecurityPool reference . Validate and stage the operation. The coordinator checks the caller, target vault, requested amount, and validity window before any report is requested. Check the cached price. If the cached REP/ETH price is fresh, the coordinator attempts the operation immediately. Open a report when the price is stale. The refresh sponsor supplies the request bounty and initial WETH/REP position, and the coordinator creates the report as its initial reporter. Allow corrections. Other participants may replace the report by posting the position required by OpenOracle. Every valid replacement installs a new reporter and restarts the settlement window. Settle the current report. Once the settlement deadline is reached without another dispute, any account can call OpenOracle's settle , which finalizes the report and calls the coordinator. Accept or reject the price. The coordinator validates the report identity, history, economics, amounts, and settlement-time base fee before updating the cache. Execute queued operations. An accepted fresh price allows the coordinator to attempt the queued pool operations, each of which still performs its own current safety checks.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Staging preconditions","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A request that violates a staging precondition reverts before any report is requested. The preconditions of each entry point, including amounts, the validity window, vault targets, liquidation approvals, and the pending-report sponsor rule, are listed in the coordinator contract reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Execution batches","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"For a single operation with a valid cached price, the coordinator records the operation and attempts it in the same transaction. A liquidation gate or another pool check can still fail; the transaction then succeeds and the operation is consumed with ExecutedStagedOperation reporting success = false . An operation that waits for a report can also fail when it is attempted: after its expiry ( Staged operation expired ), when a liquidation target's backing units or underwriting commitment changed after staging ( Stale liquidation ), or when a withdrawal now previews to zero REP ( Withdraw amount has no effect ). When a new report is needed, one settlement callback can automatically attempt up to MAX_PENDING_SETTLEMENT_OPERATIONS (four) price actions, counting each commitment change, liquidation, or withdrawal inside a vault bundle separately. Deposits use no callback slot. A bundle must fit the remaining capacity; additional single staged operations remain active outside the callback batch. If they have not expired and the accepted price remains fresh, they can be executed later with executeStagedOperation . For a vault bundle, a fresh-price failure reverts the entire submission. With a stale price, the deposit completes immediately and the deferred commitment changes, liquidations, and withdrawal later execute or fail together. See the coordinator interaction reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Escalation Game deposits","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Escalation Game REP deposits do not use the staged callback path. When a pool has any underwriting commitment, depositToEscalationGame requires an already-fresh coordinator price and reverts when the price is stale. After previewing the accepted REP deposit, the pool uses lastPrice for the post-transfer vault and pool coverage checks.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"request-funding","heading":"Funding and report ownership","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Report funding is caller supplied. The coordinator's getRequestPriceCostAttoEth() getter calculates the minimum request bounty from the current base fee, callback gas limit, and the coordinator's own report processing budget: requestPriceCostAttoEth = block.basefee ⋅ 4 ⋅ ( callbackGasLimit + gasConsumedOpenOracleReportPrice ) + 101 callbackGasLimit is (gasConsumedSettlement + SETTLEMENT_GAS_OVERHEAD) × MAX_PENDING_SETTLEMENT_OPERATIONS , returned by getSettlementCallbackGasLimit() . 101 is the fixed REQUEST_BOUNTY_OFFSET_ATTO_ETH . With the configured values , the limit is 4,200,000 gas and the request cost is block.basefee × 17,200,000 + 101 attoETH: 0.516 ETH plus the offset at a 30 nanoETH base fee. Every entry point that can open a report takes an explicit bountyAttoEth . What happens to msg.value depends on the call: The call opens a report. bountyAttoEth must be at least getRequestPriceCostAttoEth() in the inclusion block, and msg.value must be at least bountyAttoEth . The coordinator forwards exactly bountyAttoEth to OpenOracle as the report's settlerReward and refunds the rest. The same transaction transfers the sponsor's initial WETH and REP position, so the sponsor funds the bounty and the position up front. A staging call finds a fresh cached price. No bounty is taken, and all of msg.value is refunded. A staging call adds an operation while a report is pending. No bounty is taken, and all of msg.value is refunded. requestPrice , requestPriceIfNeededAndStageOperation , and requestPriceIfNeededAndStageLiquidation refund msg.sender . stageVaultOperations , which only the coordinator's vaultOperations executor can call, refunds the bundle owner. Each refund is a low-level native-ETH call made only for a positive amount. If the recipient rejects it, the whole transaction reverts, including operation staging, immediate execution, and any report opened in the same transaction.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"rolling-dispute-exclusivity","heading":"Sponsor lane","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The sponsor lane is the exclusive right of pendingReportSponsor , the account that funded the pending report, to add operations to that report's settlement. Those follow-up operations pay no additional bounty; other callers must wait until the report finishes. requestPrice reverts while the cached price is fresh or a report is pending.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"security-guarantee","heading":"Report sizing and correction incentives","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator sizes each report so that correcting a price error of at least targetPriceErrorForDispute stays profitable after OpenOracle's fees and the modeled gas cost of one dispute multiplied by openOracleSecurityMultiplierBps . That multiplier is separate from a SecurityPool's backing multiplier, statoblastSecurityMultiplierBps . A report can be corrected in either direction. The formula assumes the less profitable one, in which the true REP/ETH price is (1 + targetError) times the reported price, and models the correction as releasing the fraction (targetError - fees) / (1 + targetError) of the WETH position before gas. The required position is the multiplied gas cost divided by that fraction. The minimum initial WETH position also has a floor of 1% of the pool's settlement collateral ( settlementCollateralAttoEth ), and the same floor applies to the escalation halt: reportAttoEth ( gasPriceAttoEthPerGas ) = ⌈ gasPriceAttoEthPerGas ⋅ gasUnitsForOneDispute ⋅ openOracleSecurityMultiplierBps ⋅ ( percentagePrecision + targetPriceErrorForDispute ) 10000 ⋅ ( targetPriceErrorForDispute - protocolFee - feePercentage ) ⌉ openInterestReportAttoEth = ⌈ settlementCollateralAttoEth 100 ⌉ minimumToken1ReportAttoEth = reportAttoEth ( initialReportPriorityFeeAttoEthPerGas ) + max ( reportAttoEth ( block.basefee ) , openInterestReportAttoEth ) escalationHaltAttoEth = max ( ⌊ initialWethReportAttoEth ⋅ escalationHaltMultiplierBps 10000 ⌋ , openInterestReportAttoEth ) All amounts are in attoETH. percentagePrecision is 10,000,000 , the denominator of targetPriceErrorForDispute , protocolFee , and feePercentage . No REP price, expected REP price movement, or individual protected-operation notional enters the minimum WETH calculation. The coordinator sets initialWethReportAttoEth = max(minimumToken1ReportAttoEth(), requestedInitialAttoWeth) , uses that value as OpenOracle's currentAmount1 , and derives amount2 = ⌈initialWethReportAttoEth * proposedRepPerEthPrice / 1e18⌉ in the same transaction.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"formula-inputs","heading":"Formula inputs","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The shared deployment configuration is the set of constants in shared/statoblast/ts/initialReport/oracleInitialReport.ts that the deployment passes to the coordinator factory constructor. Formula input Current value Source block.basefee Current request block EVM block context initialReportPriorityFeeAttoEthPerGas Origin-pool parameter; the UI defaults to 10 nanoETH Immutable lineage configuration inherited by child pools settlementCollateralAttoEth Current pool settlement collateral Configured security pool OPEN_INTEREST_DIVIDER 100 (a 1% floor) Coordinator constant gasUnitsForOneDispute 300,000 gas Factory constructor; shared deployment configuration ORACLE_GAS_UNITS_FOR_ONE_DISPUTE openOracleSecurityMultiplierBps 100,000 bps ( 10x ) Factory constructor; shared deployment configuration OPEN_ORACLE_SECURITY_MULTIPLIER_BPS targetPriceErrorForDispute 500,000 / 10,000,000 ( 5% ) Factory constructor; shared deployment configuration ORACLE_TARGET_PRICE_ERROR_FOR_DISPUTE protocolFee 100,000 / 10,000,000 ( 1% ) Factory constructor; shared deployment configuration ORACLE_PROTOCOL_FEE feePercentage (OpenOracle's reporter fee) 10,000 / 10,000,000 ( 0.1% ) Factory constructor; shared deployment configuration ORACLE_FEE_PERCENTAGE escalationHaltMultiplierBps 100,000 bps ( 10x ) Factory constructor; shared deployment configuration ORACLE_ESCALATION_HALT_MULTIPLIER_BPS","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"security-guarantee","heading":"Construction bounds and parameter effects","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Coordinator construction requires: positive dispute gas units positive request gas: gasConsumedSettlement or gasConsumedOpenOracleReportPrice is nonzero a nonzero initialReportPriorityFeeAttoEthPerGas a target error no greater than 100% an OpenOracle security multiplier of at least 1x and at most type(uint256).max / (percentagePrecision + targetPriceErrorForDispute) combined OpenOracle fees below the target error a nonzero escalationHaltMultiplierBps a timestamp clock with dispute tracking ( timeType and trackDisputes both true) maxSettlementBaseFeeMultiplierBps of at least 1x minLiquidationPriceDistanceBps no greater than 100% Construction also bounds initialReportPriorityFeeAttoEthPerGas so that the priority-fee component of the minimum report, reportAttoEth(initialReportPriorityFeeAttoEthPerGas) , does not exceed half of min(type(uint128).max, type(uint128).max × 10000 / escalationHaltMultiplierBps) ; a larger fee reverts with Initial report priority fee exceeds OpenOracle limits . OpenOraclePriceCoordinatorFactory stores the shared configuration without validating it, so an invalid configuration deploys the factory successfully and makes every later coordinator deployment revert. At a 30 nanoETH base fee, a configured 10 nanoETH priority fee, and 100 WETH of settlement collateral, the modeled gas cost of one dispute is 0.012 ETH , the minimum report is 3.230769230769230770 WETH , and the escalation halt is 32.307692307692307700 WETH .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"initial-report-estimator-example","heading":"Dynamic WETH report estimator","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"This calculator mirrors the onchain formula. The deployment parameters and caller-selected amount are shown as adjustable inputs to make their effect explicit. For a deployed coordinator, the base fee and pool settlement collateral can change from one request block to another. Selected initial WETH 3.2308 WETH Fee bound fees below target error Network costs Block base fee 30 nanoETH Initial-report priority fee 10 nanoETH Gas units for one dispute 300,000 gas Pool security Pool settlement collateral 100 WETH OpenOracle security multiplier 10.0x Target wrong-price error 5.0% Oracle fees OpenOracle protocol fee 1.0% OpenOracle reporter fee ( feePercentage ) 0.1% Coordinator policy Escalation halt multiplier 10x Report request Requested initial WETH 0.00 WETH Initial-derived halt 32.307692307692307700 WETH Open-interest halt floor 1.000000000000000000 WETH Minimum token1 report 3.230769230769230770 WETH Escalation halt 32.307692307692307700 WETH Modeled dispute gas cost 0.012000 ETH Buffered gas target 0.120000 ETH Correction profit fraction after fees 3.7143%","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Settlement validation, rejection, and recovery","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Low-level callback failure","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"OpenOracle invokes the coordinator through a low-level callback whose success is intentionally neither stored nor emitted. A failed callback does not automatically undo an otherwise valid OpenOracle settlement. The coordinator accepts callbacks only from the configured OpenOracle and only for the current pending report id. If those checks revert inside the low-level call, the report can still settle while the coordinator remains pending. If the settlement transaction cannot retain enough gas headroom after the callback attempt, OpenOracle reverts settlement with InvalidGasLimit . In that case, the report has not settled and coordinator recovery is not yet available.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"settlement-validation-scope","heading":"Coordinator settlement validation","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A callback that successfully enters the coordinator can still produce a rejected price. The coordinator clears the pending report state, emits PriceReportRejected with the quoted reason, and leaves the price cache unchanged when the first of the following conditions holds: the settlement block's base fee exceeds the request-time cap, which is the base fee implied by the committed bounty scaled by maxSettlementBaseFeeMultiplierBps : Base fee too high ; storedGame(reportId).numReports is saturated at the uint24 maximum: Counter saturated ; numReports is zero, or the settled WETH amount is below reportAttoEth(initialReportPriorityFeeAttoEthPerGas) + reportAttoEth(recordedBaseFee) from the sizing formula , where recordedBaseFee is the base fee OpenOracle stored for the final report in disputeHistory(reportId, numReports - 1) : Report uneconomic ; the freshness window measured from settlement eligibility has already closed: Report stale ; either settled token amount is zero: Empty oracle settlement ; the integer REP/ETH calculation produces a zero price: Oracle price is zero . These checks establish only that the final WETH position meets the modeled security floor and that the callback data is structurally acceptable. They do not prove that the accepted price is externally correct, that an independent corrector exists, or that a correcting transaction will obtain inclusion.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Rejected-price cleanup","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A rejected report does not replay its pending settlement operations. Instead, the coordinator terminally fails every operation attached to that report, removes it from the active and pending sets, and releases any liquidation-approval reservation. A caller must stage a new operation to try again with a later price.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Recovering a settled report after callback failure","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"When OpenOracle has already settled but the coordinator remains pending because the low-level callback did not complete, anyone can call recoverSettledPendingReport . Recovery clears the pending report, sponsor, and base-fee cap; withdraws the coordinator's OpenOracle WETH and REP balances to the sponsor; and terminally fails every pending settlement operation attached to the report, releasing each liquidation-approval reservation. It does not accept the report as a new price.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"intentional-economic-tradeoffs","heading":"Liveness and exposure limits","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator has no notional exposure budget and no absolute settlement deadline; see excluded guarantees EG03 and EG04 and the OpenOracle explanation .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"dispute-escalation","heading":"Dispute escalation amounts","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"In this integration, WETH is the escalation variable. Before escalationHalt , OpenOracle requires min(⌊oldAmount1 × multiplier / 100⌋, escalationHalt) . With the configured multiplier of 115 , integer flooring leaves token1 amounts from one through six attoETH unchanged; seven attoETH is the first amount that grows. At or above the halt, each replacement instead requires oldAmount1 + 1 , adding one attoETH of WETH.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"attack-model","heading":"Stress model: external payoff and censorship","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"This section defines an analytical model, not contract behavior. It estimates the cost to an attacker who posts a manipulated REP/ETH report and censors corrections until settlement, receiving an outside payoff only if the accepted price makes a liquidation executable. It is a continuous approximation; the OpenOracle explanation states how far its results can be relied on. honestDisputeBarrierFraction is a model input, not a coordinator field: the cost, as a fraction of the honest price, that an honest corrector must overcome. Its 1.1% default is the fixed-fee floor, protocolFee plus feePercentage . executionErrorThreshold = max ( 0 , liquidationThresholdPrice honestPrice ⋅ ( 1 - minLiquidationPriceDistanceBps 10000 ) - 1 ) manipulatedPriceError = max ( 0 , manipulatedPrice - honestPrice honestPrice ) liquidationExecutable = manipulatedPrice > liquidationThresholdPrice ∧ manipulatedPriceError ≥ executionErrorThreshold attackerPayoff = liquidationExecutable ? externalPayoff : 0 censorshipRate = max ( 0 , manipulatedPriceError - honestDisputeBarrierFraction ) censorshipCost = censorshipDuration ⋅ censorshipRate ⋅ oracleReportLiquidity Price errors and the dispute barrier are fractions of the honest price. externalPayoff and oracleReportLiquidity use the same ETH-denominated unit. The liquidation design owns the exact integer threshold and distance checks. targetGriefRatio is the desired attacker loss net of externalPayoff , divided by that payoff; 1 targets censorship cost equal to twice the payoff. One model step is the interval over which censorshipRate accrues; the model does not tie it to a block, second, or dispute round. oracleLiquidityRatio = oracleReportLiquidity externalPayoff durationToTargetCost = { targetGriefRatio + 1 censorshipRate ⋅ oracleLiquidityRatio , liquidationExecutable ∧ censorshipRate > 0 ∞ , liquidationExecutable ∧ censorshipRate = 0 not applicable , otherwise durationToTargetCost is the number of model steps of censorship after which censorshipCost reaches (targetGriefRatio + 1) × externalPayoff . It is not a maximum protocol delay.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"binary-censorship-example","heading":"Binary censorship stress test","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Adjust the liquidation boundary, outside payoff, report liquidity, and censorship assumptions. Liquidation executable yes Censorship cost 11424.00 ETH Market boundary Honest price 100 Liquidation threshold 101 Liquidation distance 1000 bps Attacker inputs Manipulated price 113 External payoff 1000.00 ETH Oracle defense Report liquidity 4000.00 ETH Honest dispute barrier (model) 1.10% Censorship scenario Censorship duration (model steps) 24 steps Target excess-cost ratio 1.0 Execution error threshold 12.22% Manipulated price error 13.00% Attacker payoff 1000.00 ETH Oracle liquidity ratio 4.00 Duration to target cost (model steps) 4.20","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"parameters","heading":"OpenOracle parameters used","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A source constant is fixed in the Solidity source. Deployment configuration is the shared configuration that the deployment passes to the coordinator factory, named by its constant in shared/statoblast/ts/initialReport/oracleInitialReport.ts ; a deployed coordinator exposes each configured value through a public getter. The line under each value says where it is set. Parameter Value and source Use in Statoblast token1Address / token2Address WETH / REP The factory's WETH and the pool universe's REP token Defines the REP/ETH price pair used for security-pool solvency checks. minimumToken1ReportAttoEth() See Report sizing and correction incentives and the estimator . Derived per request Minimum initial WETH position for a coordinator report. OpenOracle initial currentAmount1 The greater of the minimum and the sponsor's requestedInitialAttoWeth Derived per request Initial WETH position; the sponsor may fund more than the minimum. escalationHalt See Report sizing and correction incentives . Derived per request Ends multiplicative escalation; see Dispute escalation amounts . settlerReward The committed bountyAttoEth ; at least the request cost Derived per request Paid to the account that settles the report. Sizing inputs: gasUnitsForOneDispute , openOracleSecurityMultiplierBps , targetPriceErrorForDispute , protocolFee , feePercentage , escalationHaltMultiplierBps , initialReportPriorityFeeAttoEthPerGas , OPEN_INTEREST_DIVIDER See Formula inputs . Size the report and the escalation halt. The two fees also set OpenOracle's dispute fee accounting. gasConsumedSettlement 1,000,000 gas Deployment configuration ORACLE_SETTLEMENT_GAS Per-operation component of the callback gas limit. SETTLEMENT_GAS_OVERHEAD 50,000 gas Source constant Per-operation allowance for coordinator bookkeeping. MAX_PENDING_SETTLEMENT_OPERATIONS 4 Source constant Price actions one settlement callback can attempt, counting each action inside a vault bundle. callbackGasLimit 4,200,000 gas ; see Funding and report ownership . Derived from the three rows above Gas forwarded to the settlement callback. Settlement also needs enough surrounding gas to satisfy OpenOracle's callback headroom check. gasConsumedOpenOracleReportPrice 100,000 gas Deployment configuration ORACLE_REPORT_GAS Added to the callback gas limit in the request cost . maxSettlementBaseFeeMultiplierBps 30,000 bps ( 3x ) Deployment configuration ORACLE_MAX_SETTLEMENT_BASE_FEE_MULTIPLIER_BPS Scales the base fee implied by the bounty into the settlement base-fee cap . minLiquidationPriceDistanceBps 1,000 bps ( 10% ) Deployment configuration ORACLE_MIN_LIQUIDATION_PRICE_DISTANCE_BPS Minimum price distance a liquidation must clear; see when a vault is liquidatable . settlementTime 480 seconds Deployment configuration ORACLE_SETTLEMENT_TIME Report settlement delay on the timestamp clock. A staged operation expires once this delay plus its validity window has passed since it was queued. disputeDelay 0 Deployment configuration ORACLE_DISPUTE_DELAY Allows disputes immediately after each report and strictly before its settlement deadline. At the deadline, settlement is valid and a dispute is too late. multiplier 115 ( 1.15x ) Deployment configuration ORACLE_MULTIPLIER Growth of the WETH amount per dispute before the halt; see Dispute escalation amounts . protocolFeeRecipient 0x000000000000000000000000000000000000dEaD Deployment configuration ORACLE_PROTOCOL_FEE_RECIPIENT Receives OpenOracle protocol fees for coordinator-created reports. timeType / trackDisputes true / true Deployment configuration; the constructor rejects any other value Timestamps let the coordinator measure freshness from settlement eligibility; dispute history lets settlement validate the final report's recorded base fee. callbackContract The pool's OpenOraclePriceCoordinator Set by the coordinator Routes settled amounts back into the price cache and staged-operation executor. PRICE_VALID_FOR_SECONDS / SEPOLIA_PRICE_VALID_FOR_SECONDS See Token pair and cached price . Source constant Freshness window of an accepted price. MAX_OPERATION_VALID_FOR_SECONDS 300 seconds Source constant Largest validForSeconds a staged operation may request.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"","heading":"","keywords":["Zoltar","question","registry","screenshots"],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Tutorial You will create a yes-or-no question in Zoltar's global registry and then find it again in the question browser. Every market and every fork starts from a question like this one.","title":"Your first Zoltar question","topic":"Zoltar","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Zoltar is the base layer: it records questions and keeps the REP ledger of each universe . Zoltar and branching universes explains the model. Run bun run app:serve:zoltar and open http://localhost:4153/?simulate=1&simScenario=deployed . That browser-local simulator has the contracts deployed and no questions yet; the screenshots below come from it. It never reflects live chain state.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"create","heading":"Write the question","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Create question and keep the Binary question type. Enter a Title , for example Will it rain in Lisbon on 1 June 2027? In Description , name the source and say when the answer is Invalid , for example Resolves Yes if IPMA reports measurable rain at its Lisbon station on 1 June 2027 (UTC). Invalid if IPMA publishes no reading. Enter an End time after the event. Leave Start time blank to start immediately. The question form. The draft preview shows exactly what will be recorded on chain. A question cannot be edited after it is created, so check the preview before you submit.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"submit","heading":"Create it","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Create question below the preview and confirm the transaction. The confirmation card shows the Question ID , the end time, and the Outcomes Yes, No, and Invalid. The new question. The question ID identifies the question in every universe.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"find","heading":"Find it in the registry","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Browse questions . Select Discover questions . The browser scans the registry and lists your question under Downloaded . The registry. Questions are global: any universe can use this one, and anyone can find it here. That is a complete question. To put collateral behind a question, follow Your first security pool ; on a live network you could choose Use a question ID there with this question's ID, while each simulator keeps its own chain. Use for fork instead starts a universe fork, which Zoltar and branching universes explains.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"","heading":"","keywords":["Statoblast","SecurityPool","vault","underwriting commitment","OpenOracle","screenshots"],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Tutorial You will create a yes-or-no question and its SecurityPool , back the pool with 1,000 REP, commit to underwrite 10 ETH of it, and mint the pool's first complete set . At the end the pool shows 1 ETH of open interest against a 10 ETH commitment.","title":"Your first security pool","topic":"Statoblast","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Statoblast is the market layer built on Zoltar , the forkable oracle: a SecurityPool holds the ETH behind one question's outcome shares, and vault owners back it with REP . How Statoblast works explains the model; this tutorial only walks through it. Run bun run app:serve:statoblast and open http://localhost:12347/?simulate=1&simScenario=deployed . That browser-local simulator has the contracts deployed, no pools yet, and a wallet holding ETH and REP; the screenshots below come from it. It never reflects live chain state.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"create","heading":"Create the question and pool","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Select Create pool . Keep Create a new question and the Binary question type. Enter a Title , for example Will it rain in Lisbon on 1 June 2027? , and an End time after the event. Leave Security multiplier at 2 and Initial report priority fee at 10. Select Create question and pool and confirm the transaction. The pool form. The security multiplier sets how much REP must back each ETH a vault commits; every binary market has the three outcomes in the preview. The confirmation card lists the new question and pool. Select Open pool . The new pool. One transaction created both the Zoltar question and its SecurityPool.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"deposit","heading":"Back the pool with REP","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"On the pool page, open Vaults and select My vault . The Vault operations form is shown there. Enter 1000 in REP deposit amount (optional) , select Review vault operations , then Approve 1k REP and confirm the approval. Select Submit vault operations and confirm. The panel shows REP deposit confirmed ; your vault is now created. The REP deposit. Approval and deposit are separate transactions.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"commit","heading":"Commit to underwrite","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"REP alone does not let the pool take collateral. Your underwriting commitment is the ETH amount you agree to cover, and raising it needs a valid REP/ETH price from OpenOracle . A new pool has no price yet, so this first commitment requests one. Stay in My vault . Enter 3 in Initial report price . On a live network, Fetch from Uniswap fills in a market price; the simulator has no Uniswap pricing. Enter 10 in Commitment limit . Select Review vault operations to review the transaction and its funding requirements. Approve WETH and REP with their separate buttons. Each approval has an editable amount; use the suggested amounts for this tutorial. Select Submit vault operations , shown with the ETH amount to send, and confirm that transaction. It funds a new price report and stages your change; the panel shows Vault operations queued · awaiting oracle settlement . The vault operations review. At 3 REP per ETH and a security multiplier of 2, 1,000 REP backs about 166 ETH, so 10 ETH leaves the vault healthy.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"settle","heading":"Settle the price report","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"The report can be settled once it has stood unchallenged for eight minutes, and your staged change runs when it settles. The change expires a few minutes after the report becomes settleable, so settle promptly; an expired change must be staged again. In the simulator, select Show details in the banner, open QA controls, prices, and time travel , and select +10 min . On a live network, wait instead. On the pool page, select View report next to the OpenOracle price . When the page says Ready to settle , select Settle report and confirm. Whoever settles collects the report's settlement bounty. A settleable report. Settling accepts the price and runs the staged commitment change in the same transaction. Return to the pool with the browser's Back button. In My vault , Commitment limit now reads 10.00 ETH and the panel shows Vault operations executed . The applied commitment. The pool can now accept up to 10 ETH of collateral.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"mint","heading":"Mint a complete set","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Select Open shares , then Mint complete sets . Enter 1 in ETH to mint with , select Mint complete sets , and confirm. Minting. Minting needs no oracle price; here it only has to fit within the pool's total commitments. Your wallet now holds the new Yes, No, and Invalid shares, and the pool summary's Open interest / commitment reads 1.00 ETH / 10.00 ETH. That is the whole underwriting loop: back a pool, commit capacity, and let collateral in. Open-interest fees explains what your commitment earns, and Your first Trading market opens a market for a pool like this one. The finished pool. One ETH of collateral now backs outstanding shares, inside the 10 ETH you committed.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"","heading":"","keywords":["Trading","liquidity","initialize","pair","screenshots"],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Tutorial You will open trading for a SecurityPool by creating its trading pool and seeding it at a 70% conditional Yes price (the Yes price if the market does not resolve Invalid) with 0.01 ETH. You finish with LP tokens (the trading pool's liquidity-provider tokens) and separately held Invalid shares in your wallet, and the market listed as open.","title":"Your first Trading market","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Trading is an exchange for Statoblast outcome shares: a trading pool swaps the Yes and No shares of exactly one SecurityPool, and a SecurityPool without one has no market yet. In the UI, creating the trading pool is called creating a market . To practise without a wallet, run bun run app:serve:trading and open http://localhost:4163/?simulate=1&simScenario=deployed#/create-market . That simulator scenario has one SecurityPool, at 0x5e4EDB416494DbB62DD8C76E849aDee8e3c44d49 , and no trading pool; the screenshots below come from it. For a live network, follow Configure the Trading UI , and if the UI opens the deployment screen, complete Deploy the Trading contracts first. Fund the wallet with the deposit plus gas.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"find-pool","heading":"Open a SecurityPool without a market","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Select the Create tab and paste the SecurityPool address into Search security pools . In the simulator, use the address above; on a live network, copy it from Statoblast. Select Open security pool . The form opens with the badge MARKET NOT CREATED and Create market selected, and the SecurityPool is saved as a favorite. The next section continues from this form. To check the SecurityPool first, select Create again: the list shows your favorite SecurityPools in the selected universe that have no trading market yet, and Create market returns you to the form. Pools without a market. Create market reopens the form; Details opens the details page. The details page tells you whether the SecurityPool can take a market. An enabled Create market button means it can, and selecting it returns you to the form. When it cannot, the button is disabled and names the reason, such as Question ended. This market can no longer be created. Minting capacity shows the collateral already minted against the SecurityPool's ceiling (used / ceiling); your deposit must fit in the difference. An eligible SecurityPool. The SecurityPool is operational, its universe has not forked, and it has capacity for new collateral.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"initialize","heading":"Create and seed the trading pool","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Enter 0.01 in Amount and 70 in Conditional Yes price . Read the estimate: You provide 0.01 ETH, You receive ≈ LP tokens, 0.01 Invalid, and the Yes shares the trading pool did not need. Select Create market and add liquidity and confirm the one transaction that creates and seeds the trading pool. It reverts if it would mint fewer LP tokens than the estimate allows after your slippage tolerance, which you set under Settings . Seeding at a 70% conditional Yes price. The LP tokens represent only the Yes and No left in the trading pool; the Invalid and spare Yes return to your wallet.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"check","heading":"Check the result","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Open the Markets tab. The market is listed with the badge TRADING OPEN and a conditional price of 70% Yes. Then open Portfolio : the market shows your LP tokens, your Invalid, and the spare Yes as separate holdings. Portfolio after seeding. The 0.01 ETH deposit returned 0.01 Invalid, 0.0057 spare Yes, and the LP tokens. At a 70% conditional Yes price, the trading pool holds roughly 30 Yes for every 70 No. The No reserve is the larger one because in a constant-product market the opposite reserve sets the price; Conditional pricing explains why. Next: make your first trade against the trading pool you just created.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","buy","sell","enterPosition","slippage"],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Tutorial In this tutorial you buy Yes shares in an open market and then sell part of them back for ETH. You will see one ETH purchase become a complete set plus a swap, leaving you Yes shares and Invalid shares, and you will see the sale spend some of that Invalid to pay out ETH.","title":"Your first trade","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Trading is an exchange for Statoblast outcome shares: each market trades the Yes and No shares of one SecurityPool in a constant-product trading pool . To practise without a wallet, run bun run app:serve:trading and open http://localhost:4163/?simulate=1#/market/0x5e4EDB416494DbB62DD8C76E849aDee8e3c44d49 . The browser-local simulator is labeled at the top of the page, starts with one funded market, and never reflects live chain state; the screenshots below come from it. To trade for real, open the UI on a supported network as described in Configure the Trading UI and connect a wallet.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"choose","heading":"Choose a market","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"The simulator link above opens the market directly. On a live network, paste a SecurityPool address into Search markets and select Open security pool , or follow a shared market link. Opening a market saves it as a favorite. The Markets tab lists your favorites in the selected universe with conditional price , liquidity, and closing time; select a title to reopen it. The star removes a market from favorites. Markets. Only markets whose badge reads TRADING OPEN accept new trades.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"protect","heading":"Set your protection","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Open Settings in the header. Under Trade settings , choose a Slippage tolerance (0.01% to 5%) and how long a transaction stays valid ( Transaction valid for , 1 to 1440 minutes). A transaction reverts if the price moves further than the tolerance or it is included after its deadline, so tighter values mean fewer surprises and more reverts. The defaults, 0.5% and 20 minutes, are fine for this tutorial. Trade settings. Every quote repeats the current values, for example Slippage 0.5% · valid up to 20 min .","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"buy","heading":"Buy Yes","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"In the market's Trade tab, select Buy and Yes . Enter 0.001 in You pay . The estimate appears below the field: You receive ≈ shows the Yes and its payout if the question resolves Yes (0 ETH if it resolves No), with your Invalid insurance beside it. Below them are Average price , Profit if the question resolves Yes , and Minimum received , and Trade details lists the Trading fee . Check the Price impact : it reads 4.52%, with a note that smaller trades get a better average price. Larger impacts need a confirmation or are refused; the Trading configuration lists the thresholds. Select Buy Yes and confirm the single enterPosition transaction in your wallet. The client checks the price again before the wallet opens. A Yes purchase. The bar at the top of the estimate shows how far the purchase moves the conditional price. When the transaction confirms, the Yes and Invalid balances under Your position on the market page go up. The ETH became complete sets; the router sold their No for more Yes and sent you all the Yes plus the Invalid. Your Invalid insurance equals the number of complete sets, not the larger Yes total, and you hold no new No.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"sell","heading":"Sell Yes","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Select Sell and Yes , then enter 0.001 in Shares to sell . The 25% , 50% , and Max buttons fill in larger amounts. Read the estimate: You sell , You receive ≈ in ETH, Average price , Minimum received , and Invalid used . Select Sell Yes and confirm. No approval is needed: the sale is one ShareToken transfer of your Yes and Invalid to the router . A Yes sale. Invalid used is the insurance the sale spends: it is burned with matching Yes and No as complete sets, which pay out the ETH. When it confirms, the ETH is in your wallet, your Invalid has dropped by the amount used, and any Yes the router did not need has come back. If you ask to sell more than your Invalid can insure, the ticket offers the largest amount you can sell now; Exit an insured position covers that case and Why early ETH exits are limited explains the bound.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","development","commands","Docker"],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"How-to guide Use this guide to get the Trading contracts, SDK, and UI compiled and running on your machine.","title":"Set up Trading development","topic":"Trading","weight":1},{"fragment":"build-and-run","heading":"Build and run","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"From the repository root, confirm dependencies with test -d node_modules . If they are missing, run bun install --frozen-lockfile && bun run setup ; setup installs every project from its lockfile, compiles the contracts, and builds the UI apps and UI tests. Run bun run trading:compile . It compiles the contracts, builds the shared packages, and runs the Trading vendor build, which generates ui/trading/ts/generated/contractArtifact.ts . Never edit generated files. Run bun run trading:test , which runs the SDK, contract-facing, and UI Trading tests, and bun run trading:ui:build . Start bun run app:serve:trading , then open http://localhost:4163/?simulate=1 for the browser-local simulator. Configure the Trading UI lists the Trading scenarios. The setup works when the tests pass and the simulator page loads. To run the standalone UI in Docker instead, complete the repository-root setup first, then from ui/trading : docker network inspect zoltar >/dev/null 2>&1 \\ || docker network create zoltar docker compose up --build --force-recreate Then open http://localhost:4163/#/market . On Windows, ui/trading/start.bat runs the same Compose command. The final image runs as an unprivileged user and exposes a health check at / . The Docker image copies the core deployment addresses from docs/mainnet-deployment-addresses.json and docs/sepolia-deployment-addresses.json .","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"external-node","heading":"Test transactions against an external node","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"To exercise the contracts on a local Anvil node, follow Use local Anvil ; for script and integration tests, Deploy for script and integration tests covers bun run trading:deploy:local .","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"commands","heading":"Other commands","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"bun run trading:check runs the tests plus the bigint-number-cast guard. bun run trading:coverage:contracts traces Solidity execution and requires at least 99% production-contract line coverage. bun run trading:gas-costs reports bytecode sizes and funded-fixture operation gas. cd ui/trading && bun run docker:build and docker:run build and run the standalone UI container without Compose. After a change that alters what the UI shows, run bun run docs:screenshots -- --app trading to recapture the documentation screenshots.","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","UI","simulate","RPC","settings"],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"How-to guide Use this guide to choose between live and simulated mode and to point the Trading UI at the network and RPC you need.","title":"Configure the Trading UI","topic":"Trading","weight":1},{"fragment":"modes","heading":"Choose a mode","keywords":[],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"With no mode parameter, the UI reads live RPC and wallet state. ?simulate=1 boots a browser-local simulator with seeded contracts and balances. Add &simScenario=deployed for a SecurityPool with no trading pool , &simScenario=baseline for a chain without Statoblast or Trading contracts, &simScenario=trading-forked for the funded market after its universe forks, or leave it out for the default trading-funded scenario with one funded market. A banner labels the page as a simulation. Set up Trading development lists the commands that serve the UI.","title":"Configure the Trading UI","topic":"Trading","weight":0},{"fragment":"network","heading":"Select a network and RPC","keywords":[],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"Open Settings in the header. Choose the RPC network , and optionally enter a Fallback RPC URL and select Save RPC . A custom RPC must use HTTPS, or HTTP on a loopback address, and must serve the selected chain. It is used only until a wallet is connected on the selected chain; after that, the wallet's own RPC serves reads and transactions. The UI then checks the RPC chain and the core contracts, and derives the Trading factory and router addresses for that network. If either is not deployed, the deployment screen opens; Deploy the Trading contracts covers it. The configuration works when the Markets tab opens. The configuration reference describes what the client derives and checks.","title":"Configure the Trading UI","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","deploy","factory","router","Anvil"],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"How-to guide Trading needs one factory and one router at addresses derived from the Statoblast deployment. Use this guide to deploy them from the browser on a network where Statoblast is installed, or with the testnet deployer on a local Anvil node.","title":"Deploy the Trading contracts","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The Statoblast core, including its SecurityPoolFactory , must already be deployed on the network. The manifests docs/mainnet-deployment-addresses.json and docs/sepolia-deployment-addresses.json list planned addresses; they do not prove the contracts are live, as the deployment status reference explains. Continue only after you have confirmed reviewed core code at those addresses. To install the core on a test network first, follow Deploy testnet contracts .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"deploy","heading":"Deploy from the browser","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"Serve the Trading UI as Set up Trading development describes, from source or in Docker. Open http://localhost:4163/#/deploy . To use another network or RPC URL, set it under Settings before connecting. Select Connect wallet . The Trading contracts panel shows the SecurityPoolFactory address and the status of the Trading factory ( TwoWayConstantProductFactory ) and Trading router ( TwoWayConstantProductRouter ). Select Deploy trading factory and confirm, then select Deploy trading router and confirm. Deployment progress reaches 2 / 2 once both contracts and their links are verified. If you leave and return with the same settings, the flow resumes at the first missing contract. A missing prerequisite. The SECURITY POOL FACTORY IS NOT DEPLOYED badge and the disabled deploy buttons mean Statoblast is not installed on this network yet. The factory's trading fee is fixed at 0.30% and cannot be changed after deployment. Creating a trading pool for a market is a separate step; see Your first Trading market .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"use-local-anvil","heading":"Use local Anvil","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The UIs do not offer Ethereum mainnet, so start Anvil with Sepolia's chain ID, 11155111 , and use the Sepolia address profile: bun run anvil -- --chain-id 11155111 --hardfork osaka Deploy to the node with the testnet deployer, following Deploy locally with --rpc-url=http://127.0.0.1:8545 and an Anvil account's key. It installs the core and the Trading factory and router. Its final explorer-verification step targets public Sepolia, so a failure there does not mean the local deployment failed. In your wallet, point the chain 11155111 network at http://127.0.0.1:8545 and import an Anvil account. Once a wallet is connected, the UI reads and sends through the wallet's RPC, so a wallet still on public Sepolia would use the real network. Start the Trading UI, connect the wallet, and open #/deploy . Deployment progress shows 2 / 2 .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"deploy-script","heading":"Deploy for script and integration tests","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The local deployment script deploys independent copies at ordinary CREATE addresses. The UI never finds them, because it looks only at the derived addresses; use them from scripts and integration tests only. The script needs a node whose chain ID equals the core manifest's, code at that manifest's SecurityPoolFactory , and an unlocked account on the node. For the Sepolia manifest below, complete step 1 of Use local Anvil first. ZOLTAR_DEPLOYMENT_MANIFEST=docs/sepolia-deployment-addresses.json \\ TRADING_RPC_URL=http://127.0.0.1:8545 \\ bun run trading:deploy:local The script deploys TwoWayConstantProductFactory(coreFactory, feeBps) and TwoWayConstantProductRouter(factory) , writes a manifest of its inputs, addresses, transaction hashes, and bytecode hashes to solidity/deployments/trading/local.json , and prints it. The configuration reference lists its environment variables and output.","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","odds","initialize","basis points"],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"How-to guide Use this guide when you call the trading pool contract (the pair) yourself and want a new trading pool to open at a specific Conditional Yes price rather than 50%.","title":"Seed alternative conditional odds","topic":"Trading","weight":1},{"fragment":"prerequisites","heading":"Before you call initialize","keywords":[],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"Creating the trading pool and initializing it directly are separate transactions, so anyone can initialize it first at another price. Prefer the router's createPairAndInitializeWithEth , which creates and seeds in one transaction and takes the price in basis points; the UI's Initialize form uses it, as Your first Trading market shows. Continue only if you must call initialize yourself. The question has not ended, its universe has not forked, and the SecurityPool is Operational and unresolved. The smaller deposit must exceed MINIMUM_LIQUIDITY (1,000 share base units). The trading pool mints that many LP base units to a lock address that no key controls, so you receive the smaller deposit minus 1,000. The pair reference lists the remaining preconditions of initialize .","title":"Seed alternative conditional odds","topic":"Trading","weight":0},{"fragment":"steps","heading":"Seed the trading pool","keywords":[],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"Create complete sets by sending ETH to the SecurityPool's createCompleteSet() . Let q be the Yes balance it minted to you, in share base units; the ETH-to-share rate is not fixed, so read the balance. Create the trading pool with the factory's createPair(securityPool) , unless it already exists. Choose the Conditional Yes price p in basis points with 0 < p < 10,000 and compute the deposits: If p ≥ 5,000 , deposit all q No and ⌊q × (10,000 − p) / p⌋ Yes. If p < 5,000 , deposit all q Yes and ⌊q × p / (10,000 − p)⌋ No. Approve the trading pool as an operator on the canonical ShareToken with setApprovalForAll ; initialize pulls both deposits from the caller. Call initialize(yesAmount, noAmount, minLiquidity, recipient) on the trading pool with those deposits. Set minLiquidity to the smaller deposit minus 1,000. Check the result: getReserves() returns your two deposits and tradingStatus() returns Open . If initialize reverted with Already initialized , someone else seeded the trading pool first. Conditional pricing works through the 70% example and explains why the larger reserve is the side you are betting against.","title":"Seed alternative conditional odds","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","exit","sell","maximumInsuredExit","Invalid"],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"How-to guide Use this guide to turn Yes or No shares back into ETH while the market's trading pool is open. The exit spends one Invalid share for each complete set it redeems, so your Invalid balance limits it.","title":"Exit an insured position","topic":"Trading","weight":1},{"fragment":"in-the-ui","heading":"Exit in the UI","keywords":[],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"Open the market, select Sell and the side you hold. Select Max to fill Shares to sell with the largest amount you can sell now, or enter a smaller amount. The hint under the field shows your holding and that limit. Check You receive ≈ , Minimum received , and Invalid used , then select Sell Yes (or Sell No ) and confirm. An insured Yes exit. The hint under the amount is the limit set by your Invalid, your Yes, and the trading pool's liquidity. If Invalid is the binding limit and you enter more than it covers, the ticket shows Not enough Invalid shares to insure this sale. and offers Sell … instead with the largest amount. The shares you do not sell stay in your wallet. Acquiring more Invalid helps only when Invalid is the binding limit; Why early ETH exits are limited works through the bounds. When the sale confirms, the Invalid balance under Your position has dropped by Invalid used and the ETH is in your wallet.","title":"Exit an insured position","topic":"Trading","weight":0},{"fragment":"through-the-sdk","heading":"Exit through the SDK","keywords":[],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"Call maximumInsuredExit from the SDK , a private workspace package in this repository, with your wallet balances and the trading pool's reserves and fee. It returns the largest number of complete sets q that your Invalid, your long shares , and the opposite reserve all allow. For a Yes position, q complete sets need q Invalid, q Yes to redeem, and enough extra Yes to buy exactly q No. Choose maxLongSharesIn , minEthOut , payoutRecipient , refundRecipient , and deadline explicitly, and encode the request with encodeReceiveRequest . Send a ShareToken safeBatchTransferFrom to the router carrying q Invalid and maxLongSharesIn long shares with the encoded request. Simulate it, simulate again immediately before submission, and submit only if the result still satisfies maxLongSharesIn and minEthOut . The router reference lists the request fields, their constraints, and what the router delivers. A successful exit emits PositionExitedByTransfer with the long shares used and refunded.","title":"Exit an insured position","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","liquidity","removeLiquidity","permit"],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"How-to guide Use this guide to withdraw an LP position from a trading pool .","title":"Remove liquidity","topic":"Trading","weight":1},{"fragment":"in-the-ui","heading":"Remove in the UI","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Open the market and select the Liquidity tab, then Remove . Enter the LP tokens to remove in Amount . You receive ≈ shows the Yes and No you get back. Select Remove liquidity and confirm. The transaction reverts if it would return less than the estimate allows after your slippage tolerance. Removing liquidity. The UI calls the trading pool directly, so it never asks for a router allowance.","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"through-the-pair","heading":"Remove through the trading pool contract","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Compute the outputs from getEffectiveReserves() : each reserve × liquidity ÷ LP total supply, rounded down. Removal first synchronizes the reserves, so donated shares count. Call the trading pool's removeLiquidity(liquidity, minYes, minNo, recipient, deadline) with minYes and minNo set from those outputs and your tolerance. The deadline is enforced on chain. After either path, your LP balance has fallen by liquidity , your Yes and No balances have risen by the outputs, and the trading pool has emitted LiquidityRemoved . Integrations that need router-based removal call the router's removeLiquidityWithPermit , whose bounds are named minYesOut and minNoOut . The router reference gives the values the permit must sign and the allowance fallback. Never grant a permanent or infinite allowance.","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"what-removal-does-not-do","heading":"What removal does not do","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Removal always returns raw Yes and No, before and after question end, resolution, and forks. It does not use your wallet Invalid, redeem complete sets, settle winning shares, choose a child branch, or migrate liquidity. For those, see Handle resolution and Handle a universe fork .","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","resolution","settlement","redeemShares","Invalid"],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"How-to guide A trading pool closes to swaps and added liquidity when its question ends; the market finalizes later, when its outcome is final. Use this guide from question end onward to turn LP tokens, complete sets, and winning shares back into ETH.","title":"Handle resolution","topic":"Trading","weight":1},{"fragment":"steps","heading":"Unwind after question end","keywords":[],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"Remove your LP tokens from the trading pool into Yes and No shares ( Remove liquidity ). Redeem matching Invalid, Yes, and No as complete sets while the SecurityPool is Operational and its universe has not forked. If the universe forks while the question is unresolved, follow Handle a universe fork . After the market finalizes, redeem the winning share through SecurityPool.redeemShares , which requires the SecurityPool to be Operational . Keep redeeming through this pool if its universe forks later; resolved shares cannot migrate. On an Invalid result, Invalid is the only winning share. Yes and No balances, including trading fees earned as LP, are worth nothing once they lose. Each redemption burns the redeemed shares and pays ETH at the SecurityPool's current collateral rate.","title":"Handle resolution","topic":"Trading","weight":0},{"fragment":"in-the-ui","heading":"In the UI","keywords":[],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"Open the market. A closed market opens on its Settlement tab. To redeem complete sets, select Redeem sets , enter an amount in ETH to redeem , check You receive ≈ , and select Redeem complete sets . Once the market finalizes, a Redeem Yes , Redeem No , or Redeem Invalid option appears for the winning outcome. It redeems your entire balance of that share through this exact SecurityPool. Before finalization the option is absent. Settlement after the question ends. The market has not finalized yet, so only complete-set redemption and fork migration are offered. Every settlement transaction is simulated again at the latest block before your wallet opens, and stops if it would now fail.","title":"Handle resolution","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","fork","migrate","ShareToken"],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"How-to guide A fork closes the parent trading pool for swaps and additions and leaves every migration decision to you. This guide walks through moving a position into the child universe or universes you choose.","title":"Handle a universe fork","topic":"Trading","weight":1},{"fragment":"steps","heading":"Migrate a position","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Check the market's outcome. If it has already finalized, follow Handle resolution to redeem winning shares through its SecurityPool. Continue below only while the question is unresolved. Remove parent LP into parent Yes and No shares ( Remove liquidity ). Decide the destination child universe or universes for each of your Invalid, Yes, and No balances. Nothing in Trading chooses a child universe or migrates LP for you. For every nonzero parent balance you intend to migrate, submit one ShareToken.migrate(fromId, targetOutcomeIndexes) call with that token ID and the explicitly chosen, strictly increasing target outcome indexes. Each call mints the matching child-universe share balance. The parent balance stays visible, but that source token ID is locked for the wallet and can no longer be transferred. After each call, verify the expected child token ID and balance, then refresh or discover the canonical child SecurityPool. Wait until migration and Truth Auction processing return the child SecurityPool to Operational , then create a new trading pool for it. A child SecurityPool can take a trading pool only if it is back to Operational before the question's end date. Parent and child token IDs and reserves stay separate.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"choosing-targets","heading":"Choose fork targets","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Source and destination are independent: a parent Invalid, Yes, or No share can migrate into any valid child universe of the fork question, and the child receives the same share outcome as the source. Migrating parent Yes into three scalar child universes, for example, produces child Yes shares in all three children. For a categorical fork, select Invalid or one or more labeled answers. For a scalar fork, select Invalid or add one or more exact scalar ticks. The UI displays the human value and derives the packed onchain outcome index. A single-target call may create a missing child SecurityPool. A multi-target call must reference children whose canonical pools already exist. To migrate one source share to several new scalar outcomes, submit each missing outcome by itself; locking prevents transfers but not later migration of the same source into a new child. Once those children exist, another source share can target all of them in one call. Every call must add at least one source-and-child entitlement the wallet has not migrated before.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"in-the-ui","heading":"In the UI","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Open the market's Settlement tab and select Migrate . Choose the Share to migrate (Invalid, Yes, or No). Pick one or more child universes from the fork question's categorical answers or scalar ticks. Tick the acknowledgment that the migration moves your entire balance and permanently locks that share's transfers in the parent universe. Select Migrate to N child universes . The transaction copies and locks your entire balance of the selected source share. Repeat for each source share you want to move. Forks and resolution explains why the trading pool behaves this way.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","constant product","complete set","Yes","No"],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"Explanation Trading is the two-reserve constant-product design from How To Build: Augur Constant Product with Invalid Insurance , adapted to Statoblast. This page explains what happens inside one entry.","title":"The two-way market","topic":"Trading","weight":1},{"fragment":"mental-model","heading":"Mental model","keywords":[],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"A SecurityPool is the Statoblast contract that holds ETH collateral for one question , universe , and pool configuration. Its canonical ShareToken is ERC-1155: creating one complete set mints equal Invalid, Yes, and No shares for that pool's universe-specific token IDs; redeeming a complete set burns those three shares and returns collateral at the pool's current dynamic rate. The Trading factory maps the exact SecurityPool address to one immutable-fee pair . The pair is both the Yes/No constant-product reserve and the transferable LP token; it never accepts Invalid shares. The router , which holds no balances or positions between calls, coordinates complete-set creation or redemption, pair swaps, and bounded asset delivery. Users and liquidity providers keep Invalid shares separately in their wallets. The invariant to remember is: shareToken.balanceOf ( pair , invalidTokenId ) = 0 Swaps and added liquidity are open only while the market is live; Forks and resolution lists what closes a pair. Parent and child SecurityPools are distinct markets and therefore use distinct pairs.","title":"The two-way market","topic":"Trading","weight":0},{"fragment":"one-entry","heading":"One entry, step by step","keywords":[],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"The pair maintains k = Yes reserve × No reserve . Entering Yes looks like this; entering No is the mirror image. User → Router: enterPosition(pair, YES) with ETH Router → SecurityPool: createCompleteSet{value: ETH}() SecurityPool → Router: q Invalid + q Yes + q No Router → Pair: swap q No for Yes Pair → Router: additional Yes Router → User: q Invalid + total Yes Entering a Yes position. The trader ends up holding the Invalid shares from the complete set; the pair never sees them. Suppose the reserves are 1,000 Yes and 1,000 No, the fee is zero, and 100 complete-set shares are created. Contract math uses attoShares, where one displayed share is 10 18 attoShares. Swapping 100 No therefore yields 90.909090909090909090 Yes after flooring to a whole number of attoShares. The wallet receives 190.909090909090909090 Yes and 100 Invalid; the reserves become 909.090909090909090910 Yes and 1,100 No. Flooring the output favors existing liquidity providers. A No purchase simply reverses the reserves. No position record is created anywhere: wallet Yes, No, Invalid, and LP balances are the complete accounting state.","title":"The two-way market","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","Invalid","insurance"],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Explanation Invalid shares are held, not traded. This page explains what that buys a trader and what it cannot tell them.","title":"Invalid insurance","topic":"Trading","weight":1},{"fragment":"how-it-works","heading":"How it works","keywords":[],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Each ordinary ETH entry returns one Invalid share for each complete set created. If the question resolves Invalid, the holder redeems those shares with the SecurityPool 's redeemShares() at the current collateral value. Keeping Invalid shares out of the pair removes the on-chain three-reserve quadratic and makes an ordinary entry insured against an Invalid result. The cost is that nothing in the AMM can detect a suspicious market from an Invalid price, because no such price exists.","title":"Invalid insurance","topic":"Trading","weight":0},{"fragment":"worked-example","heading":"A worked Invalid result","keywords":[],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Alice entered with enough ETH to mint 100 complete-set shares, received 190 Yes after her swap, and kept 100 Invalid. The market resolves Invalid. The pair's Yes and No balances do not become valuable merely because they are nonzero. Alice redeems her 100 winning Invalid shares through the SecurityPool. Because of protocol retention , the refund is the current net collateral value, not necessarily her original gross ETH. Liquidity providers hold Invalid shares separately in exactly the same way. Selling or transferring LP tokens never moves that insurance.","title":"Invalid insurance","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","price","conditional","oracle"],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"Explanation A two-reserve pair produces exactly two prices, and both are conditional on the market resolving validly.","title":"Conditional pricing","topic":"Trading","weight":1},{"fragment":"formula","heading":"What the prices are","keywords":[],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"The constant-product marginal relationship prices one outcome using the opposite reserve: conditionalYes = noReserve yesReserve + noReserve conditionalNo = yesReserve yesReserve + noReserve The two values sum to 100% because they partition the valid outcomes only. That does not imply Invalid has zero probability; there is no unconditional Yes or No probability in this AMM. At 428.571 Yes and 1,000 No, Conditional Yes is about 70% and Conditional No about 30%. The larger No reserve makes Yes the more expensive side, which is why initializing at 70% Conditional Yes deposits more No than Yes.","title":"Conditional pricing","topic":"Trading","weight":0},{"fragment":"not-an-oracle","heading":"Not an oracle","keywords":[],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"The displayed before-and-after price is a trade-impact aid, nothing more. Reserve spot values can be moved within a block, donated to, sandwiched, or go stale before inclusion. Protocol logic must never consume this price as an oracle; Trading includes no TWAP.","title":"Conditional pricing","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","LP","liquidity","minimum liquidity"],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"Explanation An LP token is a proportional claim on a pair 's Yes and No reserves and nothing else. This page explains how that claim is minted and what it does not cover.","title":"The liquidity-provider position","topic":"Trading","weight":1},{"fragment":"supply","heading":"How LP supply is scaled","keywords":[],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"Initial LP supply uses the smaller reserve as an accounting scale. The pair permanently mints 1,000 units to MINIMUM_LIQUIDITY_LOCK ( address(1) ), then mints min(Yes, No) − 1,000 to the initializer, so total initial supply is min(Yes, No) . At attoShare scales this avoids an overflowing geometric-mean multiplication. The absolute LP supply is arbitrary; wallet LP / total LP defines ownership. LP → Router: addLiquidityWithEth with ETH Router → SecurityPool: createCompleteSet() SecurityPool → Router: equal Invalid, Yes, No Router → Pair: add largest proportional Yes + No Pair → LP: LP tokens Router → LP: all Invalid + unused Yes/No Adding liquidity with ETH. The LP token covers only the Yes and No shares that entered the pair; the Invalid shares stay with the provider.","title":"The liquidity-provider position","topic":"Trading","weight":0},{"fragment":"what-it-claims","heading":"What the token claims","keywords":[],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"A holder of wallet LP / total LP can withdraw that fraction of both reserves as raw Yes and No shares at any time, including after trading closes. Swap fees are taken from the input and stay in the reserves, and direct Yes or No donations are synchronized into them, so both accrue to existing LPs. The claim is on shares, not ETH. Its mix of Yes and No shifts as trades move the price, and neither share redeems for anything if the question resolves Invalid. The pair cannot hold Invalid shares, so the Invalid minted with a provider's complete sets stays in the provider's wallet, outside the token; Invalid insurance explains what it covers.","title":"The liquidity-provider position","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","exit","bounds","Invalid"],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"Explanation Turning a directional position back into ETH means rebuilding complete sets. Three wallet and pair quantities cap how many you can rebuild.","title":"Why early ETH exits are limited","topic":"Trading","weight":1},{"fragment":"bounds","heading":"The three bounds","keywords":[],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"An insured exit of q complete sets from a wallet holding long Yes shares needs q Invalid shares, q Yes shares for the sets, and extra Yes shares to buy exactly q No shares from the pair : q ≤ wallet Invalid q + required Yes input(q) ≤ wallet Yes q < pair No reserve The SDK binary-searches these monotonic conditions; the chosen candidate is then simulated through the router . All three bounds also presume a live market: the swap reverts once the pair closes, and the SecurityPool redeems complete sets only while it is operational. Forks and resolution covers what closes a pair and how to settle afterwards. User → ShareToken: batch transfer of q Invalid + maximum Yes input to the router, with the encoded request ShareToken → Router: receive callback with the shares and request Router → Pair: exact-output swap for q No Pair → Router: q No Router → SecurityPool: redeemCompleteSet(q) SecurityPool → Router: current ETH value Router → User: measured ETH delta Router → User: unused Yes shares An insured exit. The exit starts with a share transfer to the router , not a router call. Pre-existing ETH in the router is never mixed into the delta the user receives.","title":"Why early ETH exits are limited","topic":"Trading","weight":0},{"fragment":"example","heading":"Example","keywords":[],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"A wallet holds 150 Invalid and 260 Yes shares. If buying 100 No requires 112 Yes, redeeming 100 sets needs 212 Yes and succeeds. Trying 150 might require 181 extra Yes, or 331 in total, and fails on Yes even though Invalid would cover it. If the wallet instead had only 60 Invalid, at most 60 sets are insured. Whatever Yes cannot be insured remains a valid directional asset; it has not disappeared.","title":"Why early ETH exits are limited","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","fork","resolution","lifecycle"],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Explanation A pair closes when its market can no longer be traded safely, but it never traps a position. This page explains which events close it and what a holder does next.","title":"Forks and resolution in Trading","topic":"Trading","weight":1},{"fragment":"what-closes","heading":"What closes a pair","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Swaps, initialization, and added liquidity close permanently at question end, when the universe forks, or when the SecurityPoolForker exposes a final outcome . They are also blocked while the SecurityPool is not operational or is awaiting fork continuation . LP removal deliberately has none of those guards. tradingStatus() reports which condition applies.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"after-a-fork","heading":"After a fork","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"LP → Parent pair: removeLiquidity() Parent pair → LP: parent Yes + No LP → ShareToken: migrate(fromId, chosen outcomes) ShareToken → LP: selected child shares Wait until migration and any Truth Auction return the child pool to Operational LP → Factory: createPair(exact child pool) Factory → LP: isolated child pair Carrying liquidity across a fork. Every step is the LP's own decision; nothing here happens automatically. A fork does not select a branch or migrate LP. A child pair can be initialized only if the child SecurityPool is back to Operational before the question's end date, which requires a fork caused by another question: pairs refuse initialization and swaps once the question has ended, and a fork caused by disputing this question always comes after its end date. Parent and child pools may share one ShareToken contract, but they have different universe-specific token IDs and different pair addresses. Handle a universe fork gives the step-by-step procedure.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"after-resolution","heading":"After resolution","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Pair → Forker: getQuestionOutcome(pool) Forker → Pair: current Yes / No / Invalid outcome Pair → Pair: swaps and additions closed Holder → Pair: removeLiquidity remains available Pair → Holder: raw Yes + No Holder → SecurityPool: redeemShares() for the winning token SecurityPool → Holder: current collateral value Settling after resolution. The pair only closes; value is redeemed at the SecurityPool, never at the pair. If the question resolves Invalid, the Invalid shares held in the wallet are the settlement insurance. Fee growth in the pair's Yes and No reserves creates no redemption value on an Invalid result. Handle resolution gives the procedure.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","security","permit","reentrancy","reporting"],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Reference Trading has not been audited. Tests and internal reviews are not substitutes for an independent security assessment. This page states what the contracts defend against, what they assume, and what they leave to the user.","title":"Trading security model","topic":"Trading","weight":1},{"fragment":"authorization","heading":"Signature and callback authorization","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"LP permits use the standard ERC-2612 nonce, deadline, chain-bound EIP-712 domain, owner, spender, and exact value. The LP ledger is the repository's vendored ERC20.sol , sourced from the MIT-licensed OpenZeppelin Contracts v5.2.0 release . Its local changes pin Solidity 0.8.35, use repository formatting and descriptive revert strings, and substitute Augur unit terminology in comments; its state-transition and allowance algorithms are unchanged. TradingLiquidityToken.sol adapts the MIT-licensed v5.2.0 ERC20Permit by using the repository's shared OpenZeppelin-derived EIP-712/ECDSA primitive, a fixed version 1 , descriptive revert strings, and the stable Zoltar Two-Way LP domain name. It omits Nonces , IERC20Permit , and EIP712 inheritance only because their exact storage and hashing behavior is implemented directly by the local nonce mapping and shared authorization primitive. No signature or curve algorithm is reimplemented in the pair. OpenZeppelin ERC-20 prohibits minting to the zero address. The pair therefore locks MINIMUM_LIQUIDITY at MINIMUM_LIQUIDITY_LOCK , address(1) , which no key controls, instead of treating the zero address as an LP holder. Only pair operations can invoke the inherited internal mint and burn functions. A signature is authorization, not transaction privacy: integrations should use short deadlines and exact amounts. The router reference gives the allowance alternative for signers without ECDSA permits. Receive-based ERC-1155 operations use no off-chain signature. The ShareToken call must be submitted by the owner, while the versioned payload binds all contract identities, operation inputs, recipients, slippage, and deadline. Copying an observed payload cannot redirect assets and cannot separately consume an allowance because the router requires operator == from .","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"custody","heading":"Custody and reentrancy","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"The pair rejects foreign ShareTokens, Invalid shares, and noncanonical universe IDs in both single and batch callbacks. A reentrancy lock covers every reserve-changing operation and every LP mint or burn; LP transfer , approve , and permit change no reserves and are not locked. Recipient callbacks can execute arbitrary code, so final reserves are read from authoritative balances after transfers. Recorded-balance deficits revert; valid Yes and No donations synchronize upward and accrue to current LPs. The router recognizes pairs only through its immutable factory, opens callback state only around one expected pool and share token, and restores its starting share balances. Its ETH receiver opens only around redemption from that pool. This prevents unsolicited callbacks and keeps forced ETH separate from exit proceeds. Factory checks prevent a malicious pool from borrowing another question's ShareToken or universe identity. CREATE2 plus one immutable fee gives one canonical pair per exact pool without privileged replacement. Because an ERC-1155 transfer to an address without code cannot invoke a receiver callback, an attacker can send shares to a predicted CREATE2 address before deployment. The factory's predeployment quarantine removes those canonical balances during pair construction, so initialization starts with zero canonical balances, including zero Invalid. Foreign token contracts cannot be enumerated and may still assign irrelevant balances to the address; the pair never recognizes or moves them.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"assumptions","heading":"Assumptions","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"The configured Statoblast SecurityPoolFactory , pool, ShareToken , forker , question data, and universe state are canonical and behave as implemented in the matching core release. Users set realistic slippage and deadlines and obtain a fresh simulation in the current block immediately before submission. Wallets and RPC endpoints accurately report account, chain, balances, approvals, and receipts.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"known-risks","heading":"Known risks","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Spot prices are not an oracle and expose users to front-running and sandwiches. A lifecycle transition, fork, resolution, reserve donation, retention update, or intervening trade can invalidate a quote; contract guards and slippage bounds make the transaction revert rather than promise execution. Initial liquidity determines the starting conditional price and should be initialized atomically. LP tokens cover only Yes/No reserves; separately held Invalid can be lost, transferred, or insufficient. A valid-resolution LP can suffer directional loss, and Yes/No reserves may have no redemption value after an Invalid result. Remaining risks also include first-price choice, stale simulation, lifecycle races, recipient denial of ETH or ERC-1155 reception, core-contract bugs, and approval misuse. Slippage and deadlines bound execution but do not remove MEV. The immutable factory fee is a deployment choice, not a claim of economic optimality.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"reporting","heading":"Reporting a vulnerability","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Report a suspected vulnerability through GitHub private vulnerability reporting . Include the affected commit, contracts and functions, prerequisites, a minimal reproduction, expected impact, and whether funds or deployment keys may be at immediate risk. If private reporting is unavailable, open a public issue asking maintainers to establish a private channel, but do not include vulnerability details. Do not exploit a live deployment or publish details before maintainers have had a reasonable opportunity to respond.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","design","limitations","non-goals"],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"Explanation Trading is deliberately small. This page records why each decision was made and which features are out of scope, so that future work does not weaken the pair's one hard invariant.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":1},{"fragment":"decisions","heading":"Decisions","keywords":[],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"Two reserves only. A pair holding Yes × No shares avoids the three-way quadratic and does not price Invalid . Exact SecurityPool identity. A pair is keyed by the pool address, so parent and child branch pools always map to different pairs even when they share one ShareToken . The factory's canonical validation stops a pool from borrowing another market's identity. One immutable fee per factory. There is no owner, protocol fee switch, or mutable parameter. Balance-delta integration. The router measures complete-set creation and redemption by observed share and ETH balance deltas because retention changes the ETH-to-share rate; it never assumes a fixed ratio. Its custody checks are listed in the router reference. Minimum-reserve LP scale. Initial LP supply follows the smaller reserve rather than a geometric mean, which would overflow at large share scales; only proportional ownership matters. The liquidity-provider position gives the rule. Donations accrue to LPs. Reserve-dependent operations first synchronize reserves up to actual balances, so unsolicited Yes or No shares benefit existing LPs instead of the next trader. The security model covers the related custody defenses. No automatic fork behavior. Parent liquidity is removed as parent shares. The user explicitly chooses migration targets and initializes distinct child pairs.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":0},{"fragment":"limitations","heading":"Limitations and non-goals","keywords":[],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"The MVP intentionally does not implement a three-way invariant, Invalid-share trading, an invalidity-probability oracle, weighted reserves, quadratic solvers, flash swaps, a protocol fee, governance controls, upgradeable proxies, automatic branch selection, automatic LP migration, an insured-position NFT, or per-user on-chain position accounting. It also has no TWAP, routing across markets, guaranteed deep liquidity, or mechanism to withdraw more early ETH than complete-set insurance and reserves permit. Trading is unaudited; the Trading security model states what it defends against and what it assumes. Future work may add separate Invalid markets, safer oracle observations, routing, or bounded convenience flows. Those are distinct designs and must not weaken the invariant that this pair never accepts or holds Invalid shares.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","factory","pair","tradingStatus","CREATE2"],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Reference All Trading contracts compile with Solidity 0.8.35 for Osaka. Revert strings are operational diagnostics, not stable compatibility commitments.","title":"Trading contracts","topic":"Trading","weight":1},{"fragment":"factory","heading":"TwoWayConstantProductFactory","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"constructor(ISecurityPoolFactory, uint256 feeBps) fixes the core factory and fee; feeBps < 10,000 . createPair(ISecurityPool) validates the exact canonical pool, deploys with CREATE2, and returns the existing canonical pair on duplicate calls. getPair(ISecurityPool) → pair maps exact pool identity to a pair. isPair(address) → bool recognizes router-eligible pairs. predictPair(ISecurityPool) → address calculates the CREATE2 address. securityPoolFactory() , feeBps() , and predeploymentShareSink() expose immutable configuration. Canonical validation requires the pool's own securityPoolFactory , the factory's (originId, universeId) lookup, and shareToken.canonicalPoolByUniverse(universeId) all to agree. CREATE2 pair addresses exist counterfactually before code is deployed, when ERC-1155 receiver checks cannot run. Each factory therefore deploys an ownerless PredeploymentShareSink . A pair constructor transfers any canonical Invalid, Yes, or No already present at its future address into that sink before returning. Those quarantined shares are permanently inaccessible; do not send shares to a predicted pair address.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"pair","heading":"TwoWayConstantProductPair","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Immutable accessors expose factory , securityPool , shareToken , universeId , questionId , invalidTokenId , yesTokenId , noTokenId , and feeBps . Constants are MINIMUM_LIQUIDITY (1,000) and MINIMUM_LIQUIDITY_LOCK ( address(1) ), which holds the locked minimum liquidity. LP ERC-20 accessors are name , symbol , decimals , totalSupply , balanceOf , allowance , approve , transfer , and transferFrom . ERC-2612 accessors are permit(owner, spender, value, deadline, v, r, s) , nonces(owner) , and DOMAIN_SEPARATOR() . constructor(factory, securityPool, feeBps, predeploymentShareSink) is called only by the factory. It requires nonzero addresses and feeBps < 10,000 , reads the ShareToken, universe, question, and token IDs from the SecurityPool, and quarantines any canonical shares already at its address, emitting PredeploymentSharesQuarantined . getReserves() returns the recorded Yes and No reserves as of the last pair mutation or sync() . getEffectiveReserves() returns the pair's current Yes and No balances, including unsynchronized donations, and reverts if either balance is below its recorded reserve or the pair holds Invalid shares. The router's enterPosition reads it for the before-trade Conditional Yes price. tradingStatus() returns Open , QuestionEnded , PoolInactive , AwaitingForkContinuation , UniverseForked , QuestionResolved , or Uninitialized . initialize(yesAmount, noAmount, minLiquidity, recipient) pulls the first reserves, locks MINIMUM_LIQUIDITY , and mints the remainder once. It requires an uninitialized pair ( Already initialized ), a nonzero recipient, zero Invalid, Yes, and No balances at the pair ( Nonzero initial balance ), min(yesAmount, noAmount) > MINIMUM_LIQUIDITY ( Initial liquidity too small ), and minted liquidity of at least minLiquidity ( Minimum liquidity ). addLiquidity(maxYes, maxNo, minLiquidity, recipient) synchronizes donations, selects the largest proportional amounts, pulls them, and mints LP. It reverts with Liquidity rounds to zero when either used amount is zero and with Minimum liquidity when the minted LP is zero or below minLiquidity . removeLiquidity(liquidity, minYes, minNo, recipient, deadline) burns caller LP and returns proportional raw shares when called at or before deadline . It has no lifecycle-close guard. It reverts with Liquidity slippage below minYes or minNo and with Liquidity output is zero when either output rounds to zero, so a dust LP amount cannot be removed on its own. swapExactInput(yesForNo, amountIn, minAmountOut, recipient) pulls the gross input and sends the floor-rounded output; it reverts with Swap slippage below minAmountOut . swapExactOutput(yesForNo, amountOut, maxAmountIn, recipient) pulls the ceil-rounded required input and sends the exact output; it reverts with Swap slippage above maxAmountIn . quoteExactInput(yesForNo, amountIn) → (amountOut, feeAmount) and quoteExactOutput(yesForNo, amountOut) → (amountIn, feeAmount) quote against effective reserves. sync() records current balances as reserves. It reverts when the pair is uninitialized, a balance fell below its reserve, or the pair holds Invalid shares. onERC1155Received , onERC1155BatchReceived , and supportsInterface implement receiver discovery. Only the canonical ShareToken 's exact Yes/No IDs are accepted. Pre-initialization transfers must be initiated by the pair's own pull. initialize , addLiquidity , and both swaps require an open lifecycle and otherwise revert with Question ended , Universe forked , Fork continuation pending , Pool inactive , or Question resolved ; all but initialize also revert with Uninitialized before the first deposit. tradingStatus() is a concise action blocker, not an authoritative settlement summary. The first matching condition wins in this order: Uninitialized , UniverseForked , AwaitingForkContinuation , PoolInactive , QuestionResolved , QuestionEnded , then Open . An uninitialized forked pair therefore reports Uninitialized , and a finalized question reports QuestionResolved even after its end time. Read SecurityPoolForker.getQuestionOutcome(pool) when the finalized outcome itself is required.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"sink","heading":"PredeploymentShareSink","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Accepts ERC-1155 transfers and has no withdrawal or administrative method. It exists only to preserve clean pair initialization and the zero-Invalid invariant after counterfactual-address poisoning attempts.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"math","heading":"TwoWayConstantProductMath","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"The internal library provides exact-input and exact-output quotes, ceil rounding through the repository's full-precision Math.mulDiv , proportional deposits, initial odds, and conditional price basis points. Production paths never multiply reserve products. Rounding directions are listed in Units and rounding .","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","router","enterPosition","receive request","permit"],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"Reference Trading deploys one canonical factory and one canonical router. The router handles entry and liquidity operations, share-transfer exits and complete-set redemption, and permit-assisted LP removal.","title":"Trading router","topic":"Trading","weight":1},{"fragment":"entrypoints","heading":"Entrypoints","keywords":[],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"TwoWayConstantProductRouter(factory) fixes the only eligible factory. All user mutations enforce a deadline and a reentrancy guard. The router's receiver callbacks accept only the active pool's canonical share token and universe IDs. receive() accepts ETH only during redemption and only from the expected SecurityPool. enterPosition(pair, longOutcome, minLongSharesOut, recipient, deadline) is payable. It creates actual complete-set shares from msg.value , verifies equal Invalid/Yes/No deltas, swaps all opposite shares, and delivers long shares plus Invalid. It reverts with Minimum long shares below minLongSharesOut . It returns EnterResult : ethSpent , completeSetShares , oppositeSharesSwapped , additionalLongShares , totalLongShares , invalidInsurance , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . createPairAndInitializeWithEth(pool, conditionalYesBpsValue, minLiquidity, recipient, deadline) creates or reuses the deterministic pair and requires it to be uninitialized ( Pair already initialized ) before atomically seeding it at a Conditional Yes price strictly between 0 and 10,000 basis points. initializeWithEth(pair, conditionalYesBpsValue, minLiquidity, recipient, deadline) initializes an already created canonical pair. addLiquidityWithEth(pair, maxYesUsed, maxNoUsed, minLiquidity, recipient, deadline) creates complete sets, deposits the authoritative proportional maximum, and returns Invalid and unused shares. It reverts with Liquidity price slippage when yesUsed > maxYesUsed or noUsed > maxNoUsed . minLiquidity alone does not bound the price: a swap toward even odds before the call raises both the deposit of the side with the smaller reserve and the minted LP. removeLiquidityWithPermit(pair, liquidity, minYesOut, minNoOut, recipient, deadline, v, r, s) calls the pair's permit for the caller as owner, the router as spender, exactly liquidity as value, and the same deadline ; the signature must cover those values. A failing permit is ignored when the router's allowance already covers liquidity ; otherwise the call reverts with LP permit or allowance . The router then pulls the LP and returns raw Yes/No directly to the recipient. factory() exposes the immutable factory. onERC1155Received , onERC1155BatchReceived , and supportsInterface exist only for the receive-based operations described below and for the pair callbacks inside an operation. The payable entrypoints require nonzero msg.value ( ETH input is zero ). Every entrypoint requires a recipient that is neither zero nor the router ( Invalid recipient ) and block.timestamp ≤ deadline ( Deadline expired ); those that take a pair require it to be the factory's canonical pair for its SecurityPool ( Unrecognized pair , Noncanonical pair ). The three liquidity entrypoints that take ETH return LiquidityResult : pair , completeSetShares , yesUsed , noUsed , yesReturned , noReturned , invalidInsurance , and liquidity . Every successful share-custody operation, including the receive-based operations below, asserts that the router's Invalid, Yes, and No balances equal their starting values, preserving pre-existing forced shares.","title":"Trading router","topic":"Trading","weight":0},{"fragment":"approval-free","heading":"Exits and complete-set redemption by share transfer","keywords":[],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"The router has no exitPosition or redeemCompleteSet entrypoint. Users exit and redeem by calling the ShareToken 's safeBatchTransferFrom with themselves as both caller and owner, the router as recipient, and an encoded request in the data field. No setApprovalForAll is required. The request is the ABI-encoded ReceiveRequest struct with fields in this order: version (must equal CALLBACK_VERSION , currently 1), operation (0 ExitPosition , 1 RedeemCompleteSet ), shareToken , securityPool , pair , universeId , questionId , invalidTokenId , yesTokenId , noTokenId , longOutcome , completeSetShares , maxLongSharesIn , minEthOut , payoutRecipient , refundRecipient , and deadline . encodeReceiveRequest produces it. The router accepts only owner-initiated top-level transfers ( operator == from ); internal pair callbacks are distinguished from top-level user callbacks. Insured exit . The transfer carries exactly two IDs in the order [invalidTokenId, long token ID] with the values [q, maxLongSharesIn] , where q is completeSetShares , and longOutcome is Yes (1) or No (2). The router buys exactly q opposite shares with an exact-output swap, redeems q complete sets at the pool, and returns any unused long shares to the bound refund recipient. It emits PositionExitedByTransfer . Complete-set redemption. The transfer carries exactly three IDs in the order [invalidTokenId, yesTokenId, noTokenId] , each with the value completeSetShares ; longOutcome must be None (3) and maxLongSharesIn zero. The router redeems them at the exact canonical SecurityPool and emits CompleteSetRedeemedByTransfer . Both operations require completeSetShares > 0 , a payoutRecipient and a refundRecipient that are neither zero nor the router, and a pair that is the factory's canonical pair for securityPool , with every identity field matching it. Complete-set redemption through the router therefore needs an existing pair; without one, call the SecurityPool's redeemCompleteSet directly. Both operations measure the ETH the redemption produced, require that delta to be positive and at least minEthOut , and forward exactly that delta to the payout recipient. Pre-existing forced ETH in the router is never mixed into a payout. For LP removal through the router, Safes and integrations without signature support may use ordinary exact allowances instead of a permit. The first-party UI calls the pair directly and needs no router allowance.","title":"Trading router","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","events","Swap","indexer"],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"Reference The factory and pair emit every reserve and LP state change. The router emits an event only for the two share-transfer operations it executes itself. Parameters prefixed with indexed are log topics.","title":"Trading events","topic":"Trading","weight":1},{"fragment":"factory","heading":"Factory","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"PairCreated(indexed securityPool, indexed shareToken, indexed universeId, pair, feeBps) identifies one exact branch market and its immutable fee.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"pair","heading":"Pair","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"LiquidityInitialized(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records the first reserve contribution and circulating LP minted; locked minimum liquidity is separate. LiquidityAdded(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records proportional reserve use. LiquidityRemoved(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records raw-share output. Swap(indexed sender, indexed recipient, yesForNo, exactOutput, amountIn, amountOut, feeAmount, resultingYesReserve, resultingNoReserve) provides authoritative direction, mode, amounts, fee, and resulting state. Sync(yesReserve, noReserve) records reserves after synchronization or mutation. PredeploymentSharesQuarantined(invalidAmount, yesAmount, noAmount) records canonical shares removed from a counterfactual pair address during construction. The destination is the factory's immutable predeploymentShareSink . Standard ERC-20 Transfer and Approval events describe LP ownership and allowances.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"router","heading":"Router","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"PositionExitedByTransfer(indexed owner, indexed pair, completeSetShares, longSharesUsed, longSharesRefunded, payoutRecipient) records an insured exit initiated by owner 's share transfer. CompleteSetRedeemedByTransfer(indexed securityPool, completeSetShares, payoutRecipient) records a complete-set redemption initiated by share transfer.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"attribution","heading":"Attributing router operations","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"For router-mediated operations, pair provider / sender fields and SecurityPool creator / redeemer fields identify the router, not the initiating wallet. Pair recipient identifies the explicit asset recipient only for direct pair calls and router liquidity operations; router entry and insured-exit swaps name the router, which then forwards the assets. Insured exits carry the owner in PositionExitedByTransfer . For complete-set redemptions, take the owner from the ShareToken TransferBatch log's from field, since CompleteSetRedeemedByTransfer records only the pool and payout recipient. Entry and liquidity operations emit no router event, so for those an indexer must combine the transaction sender, the called router method, pair and core logs, and the recipient from calldata or the ShareToken TransferBatch log; it must not infer wallet attribution from the immediate-caller fields alone. Router return tuples are available from authoritative call simulation only; they are not stored in a transaction receipt. Complete-set and ETH-flow evidence comes from the SecurityPool's CompleteSetCreated and CompleteSetRedeemed events plus transaction logs.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","SDK","quoteExactOutput","maximumInsuredExit","encodeReceiveRequest"],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Reference The private workspace package @zoltar/trading-shared holds the pure Trading math that the UI and the Solidity parity tests share. All chain quantities are bigint .","title":"Trading SDK","topic":"Trading","weight":1},{"fragment":"pure-math","heading":"Pure math","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/math mirrors the quote and price functions of TwoWayConstantProductMath . It has no counterpart of the library's initial-odds and proportional-deposit functions; the UI estimates those in ui/trading/ts/features/live/liquidityEstimate.ts . quoteExactInput(reserveIn, reserveOut, amountIn, feeBps) and quoteExactOutput(reserveIn, reserveOut, amountOut, feeBps) return a SwapQuote , { amountIn, amountOut, netInput, feeAmount } , with the contract's floor (exact input) and ceil (exact output) rounding. They throw on empty reserves, an out-of-range output, or feeBps ≥ 10,000 . conditionalYesBps(yesReserve, noReserve) returns the Conditional Yes price in basis points, floor-rounded.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"positions","heading":"Position quotes","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/positions takes { yesReserve, noReserve, feeBps } and a longOutcome of 'YES' or 'NO' : quoteEnterPosition(longOutcome, completeSetShares, reserves) mirrors enterPosition after minting and returns an EnterPositionQuote : longOutcome , completeSetShares , oppositeSharesSwapped , additionalLongShares , totalLongShares , invalidInsurance , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . quoteExitPosition(longOutcome, completeSetShares, reserves) mirrors the insured exit and returns an ExitPositionQuote : longOutcome , completeSetShares , longSharesSwapped , totalLongShares , invalidRequired , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . largestExitForLongShares({ ...reserves, longOutcome, longShares, completeSetCap? }) binary-searches the largest complete-set amount whose total long-share cost fits within longShares and stays below the opposite reserve. The optional completeSetCap bounds the result further. maximumInsuredExit({ ...reserves, longOutcome, longBalance, invalidBalance }) calls largestExitForLongShares with the long balance as longShares and the Invalid balance as completeSetCap .","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"receive-request","heading":"Receive request encoding","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/receiveRequest exports encodeReceiveRequest(request) , which ABI-encodes the data argument for a share transfer to the router. The request, typed ReceiveRequest , is a positional tuple in the field order of the router's ReceiveRequest struct, which the router reference lists.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"transaction-helpers","heading":"Transaction helpers","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Transaction-facing helpers live in the Trading UI at ui/trading/ts/protocol/tradeQuote.ts , not in the shared package: minimumAfterSlippage(amount, slippageBps?) floors and maximumAfterSlippage(amount, slippageBps?) ceils a bound; slippage defaults to UI_SLIPPAGE_BPS (50). requireTransactionSlippageBps throws outside MINIMUM_SLIPPAGE_BPS (1) to MAXIMUM_SLIPPAGE_BPS (500). stableSimulation(client, simulate) reads the latest block with latestBlockIdentity(client) and passes its blockNumber , blockHash , and blockTimestamp to simulate , whose reads must all use that block number. A reorg during those reads is not detected. simulateWithDeadline(client, expiry, simulate, resolveDeadline?) does the same and also resolves expiry , a TransactionExpiry that is either an absolute deadline or { validityMinutes } between 1 and 1,440 ( requireTransactionValidityMinutes ), against the pinned block's timestamp. The optional resolveDeadline(block, requestedDeadline) can replace that deadline, and simulate receives (block, deadline) . retainApprovedMinimum(approved, refreshed, label) and retainApprovedMaximum(approved, refreshed, label) return the approved bound, or throw when the submission-time simulation no longer satisfies it. Pure math is a responsive preview only. A quote does not expire when a new block arrives: immediately before wallet submission the client simulates the actual call again at the latest block, and submits with the bounds and deadline approved in the quote only if that simulation succeeds within them.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","configuration","manifest","environment"],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"Reference The local deployment script solidity/ts/trading/deploy/deploy-local.mts reads the environment variables below. No public trading deployment manifest is bundled; the client derives and checks its contracts at startup.","title":"Trading deployment configuration","topic":"Trading","weight":1},{"fragment":"environment","heading":"Environment variables","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"Name Meaning Default TRADING_RPC_URL JSON-RPC endpoint http://127.0.0.1:8545 TRADING_DEPLOYER Unlocked RPC account First eth_accounts entry ZOLTAR_DEPLOYMENT_MANIFEST Existing matching core manifest Required TRADING_FEE_BPS Immutable trading fee 30 TRADING_FEE_BPS must be a whole number from 0 to 9999. The script stops when the RPC chain ID differs from the core manifest's, when the manifest's SecurityPoolFactory has no code on that chain, or when the RPC exposes no account. Manifests must not contain secrets.","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"manifest","heading":"Deployment manifest","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"bun run trading:deploy:local writes solidity/deployments/trading/local.json for scripts and integration environments. The file is git-ignored because local addresses are ephemeral. A generated manifest contains: network : decimal and hexadecimal chain IDs plus the deployment RPC; core : the SecurityPoolFactory address, checked to have code on the RPC chain, and the source manifest path; trading : factory, router, and immutable feeBps ; transactions : factory and router objects shaped as { hash, blockNumber: \"\" } . blockNumber is a JSON string, not a JavaScript number, so large receipt block numbers remain exact; compilerProfiles : exact versions and settings from the main Solidity artifact; bytecodeHashes : creation-bytecode commitments; deployer and deployedAt . Pairs never appear as static deployment inputs. Discover them dynamically with getPair(pool) , verify with isPair , or derive the deterministic address with predictPair . Review a manifest before publishing it, and never copy local ephemeral addresses into a public-network file.","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"client","heading":"What the client derives","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"The standalone client reads no environment variables. At startup it uses: Networks: the build writes core-deployments.json from the mainnet and Sepolia deployment manifests in docs/ , with each network's default public RPC URL. Mainnet is listed but disabled in the UI build, and the default network is Sepolia. RPC override: Settings beside the wallet selects another supported network or accepts an optional HTTPS or loopback HTTP RPC URL. URL parameters: network ( sepolia ) pins the network instead of following the wallet, rpcUrl overrides the saved RPC URL, universe selects the universe shown, and simulate=1 with an optional simScenario selects the simulator . Trading contracts: the factory and router addresses are computed with the fixed 30 basis-point fee through the core deployment's canonical CREATE2 proxy, and each address is checked for code. If either contract is missing, the connected wallet can deploy it. Markets: the market and SecurityPool lists show favorites saved in the browser. Opening an address reads that SecurityPool and checks it against the canonical SecurityPoolFactory , Zoltar, and ShareToken; no market address is hard-coded. Mint capacity follows BAL-03 . Trade settings: slippage tolerance (1 to 500 basis points, default 50) and transaction validity (1 to 1,440 minutes, default 20) are kept in browser local storage under zoltar.trading.tradeSettings . Price impact: the trade ticket cautions above 2%, requires an explicit confirmation above 5%, and refuses the trade above 15%. Quote and simulation behavior is described in the Trading SDK .","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","invariants","custody","k"],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Reference These conditions are required at every successful external state transition. Reverting calls leave the prior state unchanged. Protocol-wide invariants are catalogued separately in Protocol invariants .","title":"Trading invariants","topic":"Trading","weight":1},{"fragment":"pair-custody","heading":"Pair custody","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"The pair's Yes balance is greater than or equal to its stored Yes reserve. The pair's No balance is greater than or equal to its stored No reserve. The pair's Invalid balance is exactly zero. An LP withdrawal cannot claim more Yes or No shares than the pair owns. Withdrawal amounts are proportional to synchronized reserves and the liquidity burned. Unsolicited Yes or No donations can make a balance greater than its stored reserve. Before reserve-dependent mutations, the pair synchronizes stored reserves upward to those effective balances. Invalid shares are never a trading asset and cannot be donated through an accepted ERC-1155 callback.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"router-custody","heading":"Router custody","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Every successful router operation ends with the same Invalid, Yes, and No balances with which that operation began. This deliberately preserves any pre-existing balances while preventing the operation from accumulating new share residue.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"swaps","heading":"Swaps","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"For every successful exact-input or exact-output swap, k_after ≥ k_before , where k is the synchronized effective Yes reserve multiplied by the synchronized effective No reserve. An exact-output swap delivers exactly the requested output amount. An exact-output swap never charges more than the caller's maxAmountIn . The product comparison starts from effective reserves so a donation cannot be mistaken for swap-created growth.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"lifecycle","heading":"Lifecycle","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Once the question has ended, the question has resolved, or the universe has forked, initialization, liquidity addition, and both swap forms revert permanently. While fork continuation is pending or the SecurityPool is not operational, the same operations also revert for as long as that state lasts. Proportional liquidity removal has no lifecycle guard, so LP tokens never become trapped.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","attoShares","rounding","token ID"],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"Reference Every Trading quantity is an integer in an atomic unit, and swap rounding always favors existing liquidity providers.","title":"Trading units and rounding","topic":"Trading","weight":1},{"fragment":"units","heading":"Units","keywords":[],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"ETH and collateral outputs use attoETH (10 −18 ETH). Shares and LP tokens use attoShares, the 18-decimal atomic uint256 unit: one displayed share is 10 18 attoShares. At an empty SecurityPool, one attoETH creates one attoShare of every outcome: 1 ETH creates one Yes, one No, and one Invalid share. Protocol retention makes the later collateral-to-share ratio dynamic, so clients must use the current mutation result rather than assuming this initial rate. Fees, slippage, initial conditional price, and displayed conditional price use basis points over 10,000 where applicable. Deadlines and question end times are Unix seconds. Universe IDs are uint248 . A token ID is (universeId << 8) | outcome , with local outcomes Invalid = 0, Yes = 1, No = 2.","title":"Trading units and rounding","topic":"Trading","weight":0},{"fragment":"rounding","heading":"Rounding","keywords":[],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"Exact input computes net = ⌊gross × (10,000 − fee) / 10,000⌋ and out = ⌊reserveOut × net / (reserveIn + net)⌋ . Exact output computes net = ⌈reserveIn × out / (reserveOut − out)⌉ and gross = ⌈net × 10,000 / (10,000 − fee)⌉ . These directions favor existing LPs. Liquidity deposits round reserve use down, and the LP minted is the smaller of ⌊yesUsed × supply / yesReserve⌋ and ⌊noUsed × supply / noReserve⌋ . Removal rounds each reserve output down. Initial alternative odds round the smaller deposited reserve down. Conditional Yes is NO / (YES + NO) and Conditional No is YES / (YES + NO) ; in basis points, Conditional Yes is ⌊10,000 × NO / (YES + NO)⌋ . Client slippage bounds round a minimum down and a maximum up.","title":"Trading units and rounding","topic":"Trading","weight":0}] +window.statoblastDocsSearch = [{"fragment":"","heading":"","keywords":["overview","lifecycle","market","components"],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Start here Zoltar and Statoblast are Ethereum protocols for prediction markets, designed to make outcome manipulation costly. This page assumes you know what Ethereum and an ERC-20 token are, and nothing else. It states the problem, defines the three words you will meet on every other page, introduces the four components, and follows one market from start to finish.","title":"System overview","topic":"Introduction","weight":1},{"fragment":"problem","heading":"The problem","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"A prediction market lets people trade on a question such as “Will the fictional Aurora spacecraft launch before 31 December 2030?” Its shares are worth something only after someone decides what actually happened. That decision is the weak point: whoever controls it controls the money. Zoltar and Statoblast make the decision expensive to corrupt in two ways. First, anyone who reports an outcome must stake REP, the protocol's reputation token, behind it, and the contracts settle in favour of the outcome with the most REP staked. Reporters whose outcome loses forfeit their stake, so backing an answer the rest of the market will not support is costly. Whether that pressure keeps reports honest depends on the participation assumptions in the security model. Second, when reporters cannot agree, the system does not pick a side. Its ledger, called a universe, splits into child universes, one per possible answer, and the market decides which child stays valuable. A dishonest majority of REP cannot stop honest participants from moving their REP into the child that records the honest answer; what that does and does not guarantee is covered with Zoltar.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"vocabulary","heading":"Three words you will see everywhere","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"REP The Reputation token . Holding REP lets you report outcomes and underwrite markets. It is also what you risk: a reporter loses REP when the outcome they supported loses. Universe A ledger that can branch . Markets and REP balances belong to a particular universe. Questions are registered globally, so the same question can have markets in multiple universes. When reporters split irreconcilably, the universe forks into children, one per possible answer, each with its own REP. SecurityPool The Statoblast contract for one question, universe, and pool configuration . It holds the ETH that backs the market's shares and keeps the books on who underwrites the market, who is disputing its outcome, and who is owed what. Vault owners lock REP in a vault , their account inside the pool, and lose REP if that vault is liquidated.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"components","heading":"Four components","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Zoltar The ledger. It records questions, universes, REP, and forks. It never judges which answer is true. Statoblast core The market. It deploys a SecurityPool for a question, universe, and pool configuration, mints and redeems shares, settles ordinary disputes locally, and moves markets into child universes after a fork. Trading An exchange for Statoblast shares. It is one of possibly many; it neither creates nor resolves markets. OpenOracle A price feed. It supplies a contestable REP/ETH exchange rate whenever the protocol must check that REP still covers ETH obligations. It has no say in market outcomes.","title":"System overview","topic":"Introduction","weight":0},{"fragment":"lifecycle","heading":"One market, start to finish","keywords":[],"path":"explanation/system-overview.html","sectionTitle":"Start here","summary":"A five-minute introduction to Zoltar, Statoblast, Trading, and OpenOracle.","text":"Alice registers the Aurora question in Zoltar and deploys its SecurityPool. Vault owners lock REP in their vaults to back the market. Traders send ETH to the pool and receive complete sets : one Yes share, one No share, and one Invalid share, the outcome used when the question cannot be validly resolved, for each unit of collateral at the pool's current rate. They trade those shares however they like. When the launch deadline passes, reporting begins. Register question Deploy SecurityPool Deposit vault REP Mint complete sets Trade shares Question ends First REP deposit starts the Escalation Game Local resolution or Zoltar fork Migrate into child pools Repair missing collateral through a Truth Auction Redeem Market lifecycle. The ordinary path resolves locally and skips the migration and repair steps. The fork path creates one child pool per answer and repairs each child's collateral separately. Reporters stake REP behind an answer in the pool's Escalation Game , a dispute round whose deadline moves later as the contested amount grows. When the deadline finally passes, the market resolves if exactly one answer holds more REP than every other, and winning shares redeem the pool's ETH. Usually that is the end of the story. If two answers each attract so much REP that neither can be called the winner, the pool forks : its universe splits into an Invalid, a Yes, and a No child. Vault owners choose a child for their vault. Shareholders can materialize their share claims in multiple children. ETH is not duplicated: each child receives only what migrates to it, and a child that comes up short holds a Truth Auction, selling its own REP for ETH to close the gap. Forks and migration follows both paths in detail, and what a fork does and does not promise is the single most important thing to understand about these protocols. Follow a market through Statoblast · Understand branching universes · Look up a term","title":"System overview","topic":"Introduction","weight":0},{"fragment":"","heading":"","keywords":["contracts","architecture","calls","assets"],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Start here Users call SecurityPools , the Statoblast contracts that hold each market's ETH. Pools rely on Zoltar for universes and REP , on a price coordinator for REP/ETH prices, and on the SecurityPoolForker after a fork. This map shows contract-to-contract calls and asset movement, not every public user entrypoint. Deployment-helper factories, delegate modules (helper contracts whose code a pool, an Escalation Game, or the SecurityPoolForker runs through delegatecall ), the coordinator's VaultOperations executor , event emitters, and external contracts such as WETH are omitted; the contract inventory lists them. Related reading: the generated transaction reference for exact caller and prerequisite rules, How Statoblast works for lifecycle context, and the invariant catalog for cross-contract safety properties.","title":"Contract architecture","topic":"Architecture","weight":1},{"fragment":"product-layers","heading":"Product layers","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Zoltar — questions, universes, REP, forks Statoblast core — pools, collateral, shares, resolution, migration Trading — one implementation of swaps and liquidity around shares OpenOracle — contestable REP/ETH prices augurScan and bots — indexing, evidence, and permissionless operations Product-layer map. These products share protocol data but retain separate responsibilities and deployment boundaries.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"conceptual-model","heading":"What each contract owns","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Statoblast separates identity, market accounting, price-sensitive execution, dispute escrow, and fork repair: ZoltarQuestionData stores question state and answer encoding; Zoltar manages universes, forks, and each universe's REP token. A SecurityPool tracks market collateral, vault accounting, open interest , and lifecycle state. The ShareToken tracks outcome-share balances for one lineage : an origin pool and every child pool forked from it. The OpenOraclePriceCoordinator queues vault operations that need a fresh REP/ETH price and runs them immediately while its cached price is valid, otherwise after OpenOracle settles a new report. An operation waiting for that report is a staged operation . The EscalationGame holds the REP that reporters stake in the pool's local dispute . The SecurityPoolForker creates child pools after a fork and repairs any ETH shortfall through a Truth Auction . Each lineage has at most one pool per universe. The table calls that registered pool the canonical pool. One complete-set path is: a trader calls SecurityPool , the pool accepts ETH collateral, and the pool calls ShareToken to mint one share for every outcome.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"overview","heading":"Primary interaction flow","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"Arrows point from the contract initiating an interaction to the contract receiving it. The map has three panels: Deploy & wire , Operate & resolve , and Fork & repair . A contract that takes part in more than one panel is drawn in each. Users and keepers enter through several of these contracts, but are omitted so the plot can focus on contract-to-contract boundaries. Contract interactions are separated into three panels. During deployment, the pool factory validates question and universe data before deploying the pool, share token, and price coordinator. During runtime, the pool manages claims and escalation escrow while guarded actions travel through the price coordinator and OpenOracle, and the coordinator reserves liquidation approvals in the Liquidation Approval Registry. During a fork, the share token enters the pool forker, which snapshots escalation, migrates REP through a proxy, creates and migrates child pools, and repairs backing through the Truth Auction. Contract Interaction Map Repeating a contract in each panel keeps unrelated lifecycle edges from crossing. Blue nodes are Zoltar, REP, price, and approval infrastructure, green nodes hold market state and claims, red nodes with a dashed outline mark local resolution, gold marks deployment or fork coordination, and dashed arrows depend on a price OpenOracle has settled. Short edge labels state the action; the table below supplies its exact contract-level meaning.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"edges","heading":"What each arrow means","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"The Step column names the step within a panel. Deployment and Universe lifecycle belong to Deploy & wire; Share migration , Fork snapshot , Fork migration , and Backing repair belong to Fork & repair; every other step belongs to Operate & resolve. Initiator Receiver Step Interaction SecurityPoolFactory ZoltarQuestionData Deployment Confirms that the question exists and is the required Yes/No categorical shape before reserving the canonical pool identity. SecurityPoolFactory Zoltar Deployment Checks the universe and resolves its REP token for the new pool and price coordinator. SecurityPoolFactory SecurityPool Deployment Deploys and records the canonical origin pool. Forker-requested child deployment copies the lineage and fork state. SecurityPoolFactory ShareToken Deployment Deploys the origin lineage token and authorizes the canonical pool; child pools reuse that same token. SecurityPoolFactory OpenOraclePriceCoordinator Deployment Deploys the REP/WETH price coordinator and wires it to the newly created pool. Zoltar ReputationToken Universe lifecycle Deploys child-universe REP with its theoretical supply , mints it during migration, and burns REP during fork initiation, migration, and burnRep burns. Genesis REP cannot be burned, so Zoltar sends it to a burn address instead. SecurityPool ShareToken Market runtime Mints complete sets, burns complete sets or winning shares, and authorizes canonical child pools to continue the same lineage claims. SecurityPool EscalationGame Resolution Deploys the local game on first use and transfers vault REP into outcome-specific escrow. Settlement returns winning value or carries proofs across a fork. SecurityPool OpenOraclePriceCoordinator Risk operations Reads the coordinator's last valid REP/ETH price. Vault owners and liquidation operators queue withdrawals, underwriting-commitment changes, and liquidations on the coordinator, which executes them on the pool with a valid price. Owners may also set their underwriting commitment directly at the pool: an increase requires the coordinator's cached price to be valid, a reduction does not. REP deposits add backing without changing the commitment. OpenOraclePriceCoordinator OpenOracle Price discovery Funds a REP/WETH report and later withdraws the settled reporter balances that it validates and returns to the report sponsor. OpenOracle OpenOraclePriceCoordinator Price settlement Calls openOracleCallback after settlement so the coordinator can validate the final report, update its cached price, and attempt bounded staged-operation execution. OpenOraclePriceCoordinator SecurityPool Risk execution Once a fresh price is accepted, calls the executor-only liquidation, REP-withdrawal, or underwriting-commitment entrypoint through its VaultOperations executor , the only caller the pool accepts for them. A liquidation proceeds only if the target vault's REP backing and underwriting commitment are unchanged since it was queued, and moves part or all of that commitment with matching REP backing to the receiver vault, the vault that takes over the commitment . A withdrawal keeps the commitment and must leave it fully backed. OpenOraclePriceCoordinator LiquidationApprovalRegistry Risk operations When an operator queues a liquidation into another owner's receiver vault, reserves that owner's approval. After execution it consumes the debt actually moved; a failed, stale, or expired operation releases the reservation. ShareToken SecurityPoolForker Share migration Initiates a source-pool fork when needed and asks the forker to create a missing canonical child before migrating a holder's shares. SecurityPoolForker EscalationGame Fork snapshot Reads the game's Merkle commitments to individual deposits, its outcome balances, timing, and parameters so an unresolved dispute can continue in child pools. SecurityPoolForker SecurityPoolMigrationProxy Fork migration Deploys and controls the pool-specific adapter, transfers parent REP to it, and instructs it to lock, fork, split, and sweep child REP. SecurityPoolMigrationProxy Zoltar Fork migration Acts as the literal Zoltar caller whose stable address holds the migration balance while parent REP is locked and split into child-universe REP. SecurityPoolForker SecurityPoolFactory Fork migration Requests canonical child-pool deployment for selected child universes. SecurityPoolForker SecurityPool Fork migration Copies or recomputes financial state, migrates vaults and collateral, and activates the selected child lifecycle. SecurityPoolForker UniformPriceDualCapBatchAuction Backing repair Starts, finalizes, and settles the child Truth Auction when migrated REP and inherited ETH collateral do not arrive in the required proportions.","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"sources","heading":"Source contracts","keywords":[],"path":"explanation/contract-architecture.html","sectionTitle":"Start here","summary":"Which Zoltar and Statoblast contracts call each other, deploy each other, and move assets.","text":"ZoltarQuestionData.sol Zoltar.sol and ReputationToken.sol SecurityPoolFactory.sol SecurityPool.sol and ShareToken.sol EscalationGame.sol and SecurityPoolForker.sol OpenOraclePriceCoordinator.sol , LiquidationApprovalRegistry.sol , and OpenOracle.sol UniformPriceDualCapBatchAuction.sol","title":"Contract architecture","topic":"Architecture","weight":0},{"fragment":"","heading":"","keywords":["glossary","terms","REP","universe","underwriting commitment","haircut","trading"],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Reference Canonical, plain-language definitions for terms used throughout the documentation.","title":"Protocol glossary","topic":"Introduction","weight":1},{"fragment":"universes-and-rep","heading":"Universes and REP","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Universe A Zoltar ledger and identity for universe-specific REP and application state. Universe 0 is the initialized root; later universes are descendants created through forks. Child universe A deterministic descendant that represents one valid answer to its parent's fork question. In a binary-market example, a Statoblast fork on its own question creates Invalid, Yes, and No children. If an unrelated fork interrupts that market, its children instead follow the unrelated categorical or scalar fork question's valid answers. Question A global Zoltar object that identifies a proposition, its end time, and its answer options. Outcome One possible answer to a question. Statoblast binary markets use Invalid, Yes, and No. Invalid The legitimate third outcome for ambiguous, malformed, or otherwise unanswerable market wording. REP Universe-specific reputation tokens used as reporting, dispute, and security capital. Theoretical REP supply Zoltar's per-universe REP supply figure, from which it derives the fork and non-decision thresholds. Burns reduce it, and each child universe starts from its parent's supply after the fork threshold burn plus the fork initiator's migration balance. Fork threshold The amount of parent-universe REP that a fork initiator supplies and burns to begin a fork, derived by getForkThresholdAttoRep from that universe's theoretical REP supply. See migration accounting . Fork haircut The part of the fork threshold that Zoltar burns without crediting to the initiator's migration balance: ⌊fork threshold ÷ forkBurnDivisor ⌋, at most 20%. Contract comments call it the burn haircut. REP added to a migration balance after the fork starts is credited in full. Migration balance A parent-universe credit ( migrationRepBalanceAttoRep ) created when REP is burned or committed for a fork. The same credited amount can be minted independently in each valid child, while per-child accounting prevents an account from consuming more than that amount in any one child. Child REP REP minted for one child universe. Its ledger and economic value are separate from parent and sibling REP.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"security-pools","heading":"SecurityPools, shares, and vaults","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"SecurityPool The Statoblast contract for one question, universe, and pool configuration (its security multiplier, which sets the REP-to-ETH backing it requires, and the gas priority fee it budgets for oracle price reports); each lineage has at most one pool per universe. It holds settlement collateral and coordinates shares, vaults, resolution, migration, and repair. Lineage An origin SecurityPool and every child pool forked from it. Pools in one lineage share an origin ID and one outcome-share token contract. Origin pool A SecurityPool deployed for a question with no parent pool ( deployOriginSecurityPool ). Child pools created by forks descend from it and form its lineage. Settlement collateral The ETH a SecurityPool records as backing its outcome shares ( settlementCollateralAttoEth ). Complete sets and winning shares redeem against it pro rata, and fees decay out of it into the fee reserve. Open interest The ETH exposure of outstanding complete sets that vaults underwrite. The contracts measure it with settlement collateral: getVaultOpenInterestAttoEth returns a vault's share of settlement collateral in proportion to its underwriting commitment. When a forked child holds less settlement collateral than its inherited shares claim, the gap is a shortfall for a Truth Auction to repair, not open interest. Complete set One matching unit each of Invalid, Yes, and No shares, minted against ETH and redeemable together while the pool is operational. Outcome share An ERC-1155 token representing one outcome claim in one universe-specific SecurityPool. Vault A SecurityPool account that records a participant's REP backing, underwriting commitment, obligations, and fees. Backing units Accounting units that represent a proportional claim on REP held for SecurityPool vaults. Underwriting commitment A vault owner's standing ETH underwriting amount, separate from REP backing. The code field is underwritingLimitAttoEth ; liquidation parameters and events name the same quantity debt or securityBondDebt . Its share of the pool total determines proportional settlement obligations and fee rights. Security multiplier A pool's required ratio, in basis points, of a vault's REP value to its underwriting commitment ( statoblastSecurityMultiplierBps ). It is fixed when the origin pool is deployed and must exceed 10,001 BPS. Vault health Whether a vault's REP backs its whole underwriting commitment at the cached REP-per-ETH price ( isVaultHealthy ). An unhealthy vault can be liquidated; see when a vault is liquidatable for the two constraints. Health factor A multiplier in basis points applied to both vault-health requirements of the receiver in a liquidation. 10,000 BPS is the protocol minimum; a liquidation approval can demand more through minPostLiquidationHealthFactorBps . The targetHealthFactorBps of a REP deposit is a separate value that must be at least the pool's security multiplier. Bad debt An ETH amount recorded against a vault ( vaultBadDebtAttoEth ) and summed for the pool ( totalBadDebtAttoEth ). A vault that carries any can be neither the target nor the receiver of a liquidation. Fork migration moves it to the child pool with its vault, and it is cleared when the pool's last share is redeemed. Liquidation itself records none. Minting capacity The ceiling on a pool's settlement collateral: its total underwriting commitments while no Escalation Game exists, and zero afterwards ( getCurrentMintingCapacityAttoEth ). Utilization Settlement collateral divided by minting capacity. It sets the retention rate. Fee reserve ETH that has decayed out of settlement collateral as fees and is not yet assigned to a vault ( unallocatedAccruedFeesAttoEth ). A vault checkpoint moves the vault's share into its claimable fees. Retention The per-second fraction of a SecurityPool's outstanding complete-set collateral that stays with complete-set holders; the remainder moves continuously into the pool's fee reserve. Because retention is below one, the ETH backing one complete set falls over time; see open-interest fees .","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"escalation","heading":"Escalation Game","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Escalation Game The local Statoblast dispute mechanism in which REP-backed balances accumulate behind Invalid, Yes, and No. Start bond The minimum Escalation Game deposit: the larger of 1 REP and the universe's theoretical REP supply when the pool was deployed ÷ 10 7 . Origin-pool deployment requires it to be below the non-decision threshold; a game started with a bond at or above that threshold is clamped to one atto-REP below that threshold. A smaller deposit is accepted only when it fills an outcome exactly to that threshold. A child pool continuing a forked game keeps its parent's start bond. Binding capital The median of the three outcome balances that determines the Escalation Game's scheduled deadline. Required support The REP an outcome must hold to stay in contention, called attrition cost in the contracts ( totalCostAttoRep ). It is zero for the three-day activation delay, then rises from the start bond to the non-decision threshold over 49 days. The game's deadline is the moment it passes binding capital. Non-decision threshold The balance that two outcomes must each reach for the Escalation Game to enter non-decision: half of the universe's fork threshold, rounded up, read when the game opens and fixed for that game and any game carried from it. Non-decision The Escalation Game state in which two outcomes have each reached the non-decision threshold ( NonDecisionState.Local ). The game picks no winner, and anyone can fork the universe on the pool's own question. Reward-eligible cap One and a half times binding capital. Only the portion of winning Escalation Game deposits up to this cap earns a bonus; deposits beyond it return principal only. See the EscalationGame reference . Escalation haircut Two fifths of binding capital, burned at Escalation Game settlement instead of being paid to winners as a bonus, unless the pool's own fork already paid it through the fork haircut. The contracts call it the winner haircut ( burnEscalationWinnerHaircut ).","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"forks-and-repair","heading":"Forks and repair","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"SecurityPoolForker The shared Statoblast contract that runs a SecurityPool through a fork: it snapshots the parent pool, migrates its REP and vaults into child pools, and runs each child's Truth Auction. Migration window The eight weeks ( MIGRATION_TIME ) after a parent pool enters fork mode, during which its vaults and REP can move into child pools. A child's Truth Auction can start only after it closes. Carried game An Escalation Game that a child pool continues from its parent's unresolved game, with the parent's balances and elapsed time. The game's forkContinuation flag marks it permanently, and it never accepts deposits from a wallet. The reference pages also call it a continuation game. Fork continuation The temporary state of a child pool whose carried game has not yet been resumed ( awaitingForkContinuation ). While it is pending, the pool rejects complete-set minting and Escalation Game deposits. Truth Auction A Statoblast auction that sells child REP to repair a child pool's ETH collateral shortfall. It does not select truth. Clearing tick The price tick at which a Truth Auction clears ( clearingTick ). In a funded auction, bids above it win in full, bids below it lose, and bids at it fill in arrival order, all at its price. Underfunded threshold The ETH-per-REP price at which selling the whole REP sale cap raises exactly the ETH raise cap, rounded up ( underfundedThreshold ). In an underfunded auction, where bids never reach either cap at their own prices, only bids at or above it buy REP, and together they receive the whole REP sale cap.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"liquidation","heading":"Liquidation","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Target vault The unhealthy vault whose underwriting commitment a liquidation reduces ( targetVault ). Receiver vault The vault that accepts the transferred commitment and the REP award ( receiverVault ). It must stay healthy on its whole resulting commitment. Operator The account that stages a liquidation ( operator ). It is the receiver unless the receiver approved it through the LiquidationApprovalRegistry, and it receives no protocol payment.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"prices","heading":"Prices","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"OpenOracle An economically contestable price-reporting contract used by Statoblast for fresh REP-per-ETH prices (written REP/ETH elsewhere in these pages), not market outcomes. Price coordinator The per-pool contract that requests OpenOracle prices, caches accepted reports, and queues solvency-sensitive SecurityPool operations. Sponsor lane The rule that, while a price report is pending, only the account that opened it ( pendingReportSponsor ) can add operations to that settlement. Other callers wait until the report finishes. VaultOperations executor The VaultOperations contract each price coordinator deploys. It stores a vault owner's bundle of up to four actions and is the only caller a SecurityPool accepts for price-checked REP withdrawals and liquidations.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"trading","heading":"Trading","keywords":[],"path":"reference/glossary.html","sectionTitle":"Start here","summary":"Canonical definitions for protocol assets, states, and mechanisms.","text":"Trading pool The constant-product pair ( TwoWayConstantProductPair , called the pair in the Trading reference) that trades one SecurityPool's Yes and No shares against each other. The Trading factory creates at most one per SecurityPool. Trading router The TwoWayConstantProductRouter contract that turns ETH into a position and a position back into ETH by combining SecurityPool complete-set calls with trading-pool swaps. Long shares The Yes or No shares a trader holds on the side they expect to win. Entering through the trading router also leaves the trader one Invalid share for each complete set it minted, fewer than the long shares received. Insured exit A trading-router exit that swaps some long shares for the opposite outcome, then redeems them with the trader's Invalid shares as complete sets for ETH.","title":"Protocol glossary","topic":"Introduction","weight":0},{"fragment":"","heading":"","keywords":["ABI","transactions","callers","events"],"path":"reference/contracts.html","sectionTitle":"Reference","summary":"Index of the per-contract interaction reference.","text":"Open a contract to see its read surface, any security assumptions or trust boundary, and each state-changing entrypoint with its caller, prerequisites, effects, and primary signals. The entrypoint count is the number of state-changing function signatures a contract answers, counting each overload, each selector its fallback() routes to a delegate, and receive() .","title":"Contract interactions","topic":"Contracts","weight":1},{"fragment":"table-columns","heading":"Table columns","keywords":[],"path":"reference/contracts.html","sectionTitle":"Reference","summary":"Index of the per-contract interaction reference.","text":"Every contract page uses the same five columns. Transaction : the function name with its parameter names in ABI order. Overloads appear as separate signatures. Caller : the addresses the contract accepts as msg.sender . Main prerequisites : the conditions the call requires, quoting a revert string where a caller needs it to tell failures apart. State or asset effect : what a successful call changes. Primary signals : the events a successful call emits, each with the condition under which it is emitted, including events emitted by contracts the call reaches. A row says so when a call can succeed without emitting an event. Contract Purpose State-changing entrypoints ZoltarQuestionData Creates immutable, content-addressed scalar or categorical questions and exposes their display metadata. 1 Zoltar Registers universe forks, charges the fork haircut , and mints branch-specific child REP . 6 ReputationToken Implements universe-specific ERC-20 REP, ERC-2612 permits, and ERC-3009 transfers while enforcing the supply ceiling maintained by Zoltar. 10 SecurityPoolFactory Creates and canonically registers origin and child security pools with their share token, oracle coordinator, and optional Truth Auction. 2 SecurityPool Holds ETH settlement collateral and REP underwriting, accounts for vaults and fees, mints outcome shares , and routes local escalation. 38 SecurityPoolForker Freezes parent pools, creates selected child pools, migrates vault and escalation state, and settles collateral-repair Truth Auctions . Child-game trust boundary 14 EscalationGame Escrows outcome REP, raises the running resolution cost, detects non-decision , and settles local or carried deposits. 22 LiquidationApprovalRegistry Stores coordinator-local, bounded authorization for a receiver vault to accept liquidation debt from an exact operator. 8 OpenOraclePriceCoordinator Obtains a fresh REP-per-ETH price and coordinates withdrawals, delegated liquidation routing, approval reservations, and terminal cleanup. 11 VaultOperations Accepts a wallet bundle of vault actions for one security pool, stores the price-dependent actions, and is the only caller that pool accepts for executor-gated vault entrypoints. 4 ShareToken Stores universe-aware ERC-1155 outcome shares and materializes a holder's persistent source entitlement in selected fork branches. 10 UniformPriceDualCapBatchAuction Collects ETH bids under ETH-raise and REP-sale caps, computes one clearing result, and supports paged settlement. 7","title":"Contract interactions","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["questions","categorical","scalar","encoding"],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Creates immutable, content-addressed scalar or categorical questions and exposes their display metadata. ZoltarQuestionData source contract","title":"ZoltarQuestionData","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Use getQuestionId before submission; questionCreatedTimestamp and questions for direct lookup; getQuestionCount and getQuestions for indexed or paged discovery; and getQuestionEndDate , getOutcomeLabels , splitUint256IntoTwoWithInvalid , hasNonZeroScalarReservedBits , isMalformedAnswerOption , and getAnswerOptionName when validating or displaying answers. In the QuestionData tuple, startTime and endTime are uint48 , while numTicks is uint120 ; clients must use these exact widths because they determine the getQuestionId and createQuestion selectors.","title":"ZoltarQuestionData","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/zoltarquestiondata.html","sectionTitle":"Reference","summary":"Read surface and the createQuestion entrypoint.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals createQuestion(questionData, outcomeOptions) Anyone Question ID not already created; end time is on or after start time. Scalar questions use no labels, require display maximum greater than minimum, and positive ticks. Categorical questions require nonempty labels whose keccak256(abi.encode(label)) values are strictly descending. Stores the question at its deterministic content hash, records the creation timestamp, appends it to discovery order, and stores categorical labels when supplied. QuestionCreated","title":"ZoltarQuestionData","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["fork","universe","migration","child REP"],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Registers universe forks, charges the fork haircut , and mints branch-specific child REP . Zoltar source contract","title":"Zoltar","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Use universes , forkThresholdDivisor , forkBurnDivisor , zoltarQuestionData , genesisReputationToken , childReputationTokenCount , getForkTime , forkQuestionMatches , getRepToken , getForkThresholdAttoRep , getNonDecisionThresholdAttoRep , getUniverseTheoreticalSupplyAttoRep , getChildUniverseId , getDeployedChildUniverses , getMigrationRepBalanceAttoRep , and getChildMigrationRepAmountsAttoRep to reconstruct universe and migration state. The child migration getter accepts an array of child universe IDs and returns cumulative amounts in the same order, with zero for unused IDs. The fork threshold is the live universe theoretical supply divided by forkThresholdDivisor , rounded up, so every nonzero-supply universe has a positive fork cost. Construction requires a deployed genesis REP token with the REPv2 getTotalTheoreticalSupply() selector, theoretical supply from one attoREP through 11 million REP, forkThresholdDivisor > 1 , and forkBurnDivisor >= 5 , which caps the uncredited fork haircut at 20% of the threshold. The constructor emits UniverseInitialized once, for genesis universe 0 ; deployChild does not emit it, so child universes are discovered through DeployChild and ChildReputationTokenInitialized . Genesis REP uses ordinary ERC-20 approvals because the configured mainnet REPv2 token does not implement ERC-2612 or ERC-3009.","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"These calls depend on A15 intended question selection and A25 safe immutable parameters .","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/zoltar.html","sectionTitle":"Reference","summary":"Read surface and the forkUniverse, burnRep, deployChild, and migration-balance entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals forkUniverse(universeId, questionId) Any address able to fund the current fork threshold Initialized and unforked universe; existing ended question; sufficient caller REP. Genesis REP requires allowance; child REP is burned directly without allowance. Records the fork, removes threshold REP from the parent universe, and credits the caller with the threshold minus the uncredited fork haircut. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then UniverseForked burnRep(universeId, amountAttoRep) Any REP holder; the caller can burn only its own balance Initialized universe; positive amount; sufficient caller REP and theoretical supply. Genesis REP requires allowance. Permanently removes REP without creating migration credit; escalation settlement uses this to burn the escalation haircut when its own fork has not already paid it. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then RepBurned deployChild(universeId, outcomeIndex) Anyone Parent forked; outcome is well formed; child is not already deployed. Deploys the deterministic child REP token and initializes the child universe. TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized addRepToMigrationBalance(universeId, amountAttoRep) Parent REP holder Universe forked; sufficient caller REP. Genesis REP requires allowance; child REP is burned directly without allowance. Burns or sinks additional parent REP and increases the caller's reusable migration balance. The REP burn events (genesis REP Transfer to the burn address, or child REP Transfer and Burn ), then MigrationRepAdded prepareAndSplitMigrationRep(universeId, amountAttoRep, outcomeIndexes, preparationAttoRep) Parent REP holder Forked universe; positive split amount; nonempty valid outcomes; sufficient parent REP for the exact preparationAttoRep supplied and sufficient migration credit for every split. Outcome order is unrestricted. Genesis REP requires allowance for preparation; child REP needs no allowance. Adds the supplied preparation amount to migration credit, then splits the requested REP into the supplied outcomes using the existing migration checks. Both steps revert together on failure. Callers compute any preparation shortfall from cumulative child migration amounts, rather than current child token holdings. The addRepToMigrationBalance signals when preparationAttoRep is positive; TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized when children are deployed; child REP Transfer , Mint , and MigrationRepSplit for each destination splitMigrationRep(universeId, amountAttoRep, outcomeIndexes) Migration-balance holder Universe forked; positive split amount; nonempty list of well-formed outcomes; the cumulative amount per child must not exceed the caller's migration balance. Mints amountAttoRep of child REP into every selected branch, deploying missing children lazily. TheoreticalSupplySet , ReputationTokenInitialized , DeployChild , and ChildReputationTokenInitialized when children are deployed; child REP Transfer and Mint , then MigrationRepSplit , per selected branch","title":"Zoltar","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["REP","ERC-20","permit","supply"],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Implements universe-specific ERC-20 REP, ERC-2612 permits, and ERC-3009 transfers while enforcing the supply ceiling maintained by Zoltar. ReputationToken source contract","title":"ReputationToken","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Use getTotalTheoreticalSupply , zoltar , universeId , and repNumber to identify the token and its supply ceiling; the standard ERC-20 reads name , symbol , decimals , totalSupply , balanceOf , and allowance for balances; and nonces , DOMAIN_SEPARATOR , and authorizationState to build and check ERC-2612 and ERC-3009 signatures.","title":"ReputationToken","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/reputationtoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-20, ERC-2612 permit, and ERC-3009 authorization entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals initialize(universeId, totalTheoreticalSupplyAttoRep, repNumber) Zoltar only Called once by Zoltar as part of child-universe creation; universe, REP number, and theoretical supply are nonzero; supply does not exceed 11 million REP. Atomically assigns the child universe, global display sequence, name, symbol, and theoretical-supply ceiling used to bound migration mints. TheoreticalSupplySet and ReputationTokenInitialized mint(account, valueAttoRep) Zoltar only account is nonzero; resulting ERC-20 supply does not exceed theoretical supply. Mints branch REP to an account. Mint and ERC-20 Transfer burn(account, valueAttoRep) Zoltar only account is nonzero and has sufficient REP; theoretical supply covers the burn. Burns account REP and reduces both actual and theoretical supply by the same amount. Burn and ERC-20 Transfer transfer(to, value) REP holder Destination is nonzero; caller has sufficient balance. Moves REP from the caller without changing actual or theoretical supply. Transfer approve(spender, value) Any REP account setting its own allowance Spender is nonzero. Replaces the named spender allowance without moving REP. Approval transferFrom(from, to, value) A spender with sufficient allowance from from Source and destination are nonzero; source has sufficient balance; caller has sufficient allowance, including when caller equals source. Moves REP from from ; a finite allowance decreases by value , while an infinite allowance remains unchanged. Neither allowance path emits Approval . Transfer only permit(owner, spender, value, deadline, v, r, s) Anyone presenting the owner's valid ERC-2612 signature Deadline has not passed; signature matches the current chain, token domain, owner, spender, value, and nonce. Sets the signed allowance and advances the owner's permit nonce. Approval transferWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s) Anyone presenting the source's valid ERC-3009 signature The strict validity window is open; the nonce is unused; signature fields and source balance are valid. Consumes the authorization nonce and transfers the exact signed amount to the signed recipient. AuthorizationUsed and Transfer receiveWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s) The signed recipient presenting the source's valid ERC-3009 signature Caller equals the signed recipient; the strict validity window is open; the nonce is unused; signature fields and source balance are valid. Consumes the authorization nonce and transfers the exact signed amount to the caller-bound recipient. AuthorizationUsed and Transfer cancelAuthorization(authorizer, nonce, v, r, s) Anyone presenting the authorizer's valid ERC-3009 cancellation signature The nonce is unused and the cancellation signature matches the authorizer. Marks the authorization nonce as consumed without transferring tokens. AuthorizationCanceled","title":"ReputationToken","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["factory","deployment","registration","CREATE2"],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Creates and canonically registers origin and child security pools with their share token, oracle coordinator, and optional Truth Auction. SecurityPoolFactory source contract","title":"SecurityPoolFactory","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Use minimumSecurityBondDebtAttoEth and minimumVaultRepDepositAttoRep for immutable deployment floors. Each pool derives its start bond at construction from Zoltar’s universe theoretical REP supply ( getUniverseTheoreticalSupplyAttoRep ) as max(1 REP, theoretical REP supply / 10,000,000) . A zero configured vault REP floor selects the default theoretical REP supply / 100,000 ; a nonzero constructor value is the exact override. The security-bond debt floor is the exact nonzero constructor value; the repository deployment configuration uses 1 ETH. Construction rejects a zero or code-less operations delegate. Use securityPoolDeploymentCount with the strict securityPoolDeploymentsRange(startIndex, count) pager, which reverts rather than truncating when the requested range exceeds the array. Use getOriginId , getPoolId , getSecurityPool , getSecurityPoolOriginId , and getSecurityPoolHasInheritedForkOutcome for canonical lookup.","title":"SecurityPoolFactory","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypoolfactory.html","sectionTitle":"Reference","summary":"Read surface and the origin and child pool deployment entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals deployOriginSecurityPool(universeId, questionId, statoblastSecurityMultiplierBps, initialReportPriorityFeeAttoEthPerGas) Anyone statoblastSecurityMultiplierBps > 10_001 , which makes the halfway migration component strictly greater than one; the effective pool-held vault REP backing multiplier separately floors that component at the 10,500-BPS liquidation-award reserve described by the liquidation design . initialReportPriorityFeeAttoEthPerGas > 0 and remains within the coordinator-computed OpenOracle uint128 report/escalation-halt capacity bound; question exists, the transaction timestamp is strictly before its end time, and it has exactly the categorical labels Yes , then No ; universe is unforked and has a REP token; the non-decision threshold exceeds the construction-time start bond max(1 REP, theoretical REP supply / 10,000,000) ; no pool has already been claimed for this question, multiplier, priority fee, and universe ( Security pool origin and universe already claimed ). Creates the canonical origin pool, its lineage-wide share token, and its price coordinator with the configured initial-report priority fee, then wires and registers them atomically. SecurityPoolRegistered , then DeploySecurityPool deployChildSecurityPool(parent, shareToken, universeId, questionId, statoblastSecurityMultiplierBps, currentRetentionRate, settlementCollateralAttoEth) SecurityPoolForker only ( Only security pool forker ) Parent is the canonical pool for its lineage; supplied share token equals the parent share token; no pool has already been claimed for the parent origin in the target universe; deployment arguments satisfy downstream constructors and wiring. Creates and registers a canonical child pool with a coordinator that inherits initialReportPriorityFeeAttoEthPerGas from the parent coordinator and a forker-owned Truth Auction, while retaining the parent lineage share token. SecurityPoolRegistered , then DeploySecurityPool","title":"SecurityPoolFactory","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["collateral","vault","complete set","fees","liquidation"],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Holds ETH settlement collateral and REP underwriting, accounts for vaults and fees, mints outcome shares , and routes local escalation. SecurityPool source contract","title":"SecurityPool","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Relationship and configuration getters, all set at construction, are questionId , universeId , initialEscalationGameDepositAttoRep , zoltar , parent , shareToken , repToken , openOraclePriceCoordinator , openOracle , escalationGameFactory , eventEmitter , questionData , securityPoolForker , truthAuction , securityPoolFactory , and statoblastSecurityMultiplierBps ; the current game is escalationGame . The start bond is derived at construction from live universe theoretical REP supply rather than copied from factory configuration. Accounting getters include totalUnderwritingLimitAttoEth , settlementCollateralAttoEth , totalRepBackingUnits , shareTokenSupplyAttoShares , securityVaults , minimumSecurityBondDebtAttoEth , minimumVaultRepDepositAttoRep , totalBadDebtAttoEth , and vaultBadDebtAttoEth . Aggregate and per-vault bad debt describe only the current collateral-claim generation; getPoolAccountingSnapshot exposes its badDebtGeneration . Exhausting the remaining claim supply clears aggregate debt and advances the generation before later collateral can be minted. Use getVaultUnderwritingLimitAttoEth for the standing owner-authorized ETH commitment, separate from REP deposits. Use getVaultCapacityBackingFactorsBps for current associated and pool-held REP-per-capacity ratios, getCurrentMintingCapacityAttoEth for total standing commitments (zero once an escalation game exists), and getVaultOpenInterestAttoEth for a vault’s live proportional obligation. Other derived and paged reads are getVaultCount , getVaults , attoSharesToAttoEth , attoEthToAttoShares , attoRepToBackingUnits , backingUnitsToAttoRep , getTotalPoolHeldAttoRep , totalAccruedFeesAttoEth , getPoolAccountingSnapshot , getFeeEpochEndTime , getVaultFeeRemainder , and isEscalationResolved . The backing-factor ratios are not current vault health: associated REP includes dispute-staked principal as at-risk security, while current health also depends on the full underwriting commitment, REP-per-ETH price, the security multiplier, and both protocol constraints. The vault registry is append-only and newest-registered first. Registration requires only a nonzero address and can occur without economic state; consumers filter current positions from securityVaults , escalation stake, and bad debt. isEscalationResolved() is true when the pool inherits a fixed fork outcome, or when a local escalation game is configured and the forker routes a non- None outcome. An operational fixed-outcome child remains available for settlement and redemption but rejects new collateralized operations. getFeeEpochEndTime() returns the effective fee cutoff, or type(uint256).max for an open child epoch. A resolved child without a continuation game fixes its cutoff at activation. Lifecycle and fee getters are totalClaimableVaultFeesAttoEth , lastUpdatedFeeAccumulator , feeIndex , currentRetentionRate , awaitingForkContinuation , and systemState .","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Price-sensitive withdrawal, commitment-increase, and liquidation calls depend on A16 timely inclusion , A21 genesis REP and WETH behavior , A19 observable correctable price , and A06 lifecycle executors . User-initiated pool calls additionally depend on A28 account authority .","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Rows marked \"through fallback() \" are not in the compiled ABI: the pool forwards exactly those four selectors to SecurityPoolOperationsDelegate by delegatecall and rejects every other unknown selector with Unsupported pool operation . Transaction Caller Main prerequisites State or asset effect Primary signals burnEscalationWinnerHaircut(amountAttoRep) This pool's EscalationGame only Caller is the configured escalation game; amount is positive and the game has already transferred enough REP to the pool. Burns REP the game has just transferred to the pool: a winning deposit's escalation haircut, or a fork-continuation game's terminal residual. RepBurned and ERC-20 Transfer ; child REP also emits Burn setUnderwritingLimit(limitAttoEth) Vault owner Operational pool ( Pool inactive ) in an unforked universe ( Forked ); a resolved operational pool may still reduce a commitment after an unrelated late fork. Increases require open admission, a fresh price ( Stale price ), and both full-commitment backing checks ( Vault backing insufficient ). Reductions, including a zero exit, must leave total commitments at least equal to tracked settlement collateral ( Commitments below collateral ). Checkpoints the vault fees, then changes the underwriting commitment independently of REP ownership and recalculates retention. A call that repeats the current value returns before the checkpoint and changes nothing. Fee-accrual and retention-change PoolAccountingCheckpoint events when due; then UnderwritingLimitSet , VaultAccountingCheckpoint , and PoolAccountingCheckpoint ; no event for a call that repeats the current value setVaultUnderwritingLimit(vault, limitAttoEth) through fallback() This pool's VaultOperations executor only ( Unauthorized ) The setUnderwritingLimit prerequisites, evaluated for vault . Applies the setUnderwritingLimit change to vault . The executor calls it for a coordinator SetVaultUnderwritingLimit operation and for the commitment change in a vault bundle. The setUnderwritingLimit signals, with UnderwritingLimitSet naming vault depositRepToVault(amountAttoRep, targetHealthFactorBps) Vault owner Operational and unforked; isEscalationResolved() is false; the transaction timestamp is strictly before the question end time unless the pool has an inherited fork-continuation game; amountAttoRep is positive ( Zero REP ); targetHealthFactorBps is at least statoblastSecurityMultiplierBps ( Target below pool minimum ); resulting vault REP is at least minimumVaultRepDepositAttoRep ( Vault REP below minimum ). targetHealthFactorBps is only checked against that floor; it neither is stored nor authorizes a commitment. Checkpoints the vault fees, prices proportional REP backing units before receiving the transfer, pulls amountAttoRep from the caller through the caller's allowance to this pool, then credits only those units. Depositing REP never changes the underwriting commitment. Fee-accrual checkpoints when due; REP Transfer ; RepDepositedToVault , VaultAccountingCheckpoint , then PoolAccountingCheckpoint depositRepToVaultWithPermit(amountAttoRep, targetHealthFactorBps, deadline, v, r, s) through fallback() Vault owner The pool universe is not genesis ( Genesis REP does not support permit ); the permit succeeds or the caller allowance to this pool is at least amountAttoRep ( Vault permit and allowance insufficient ); the depositRepToVault prerequisites. Calls the REP token permit for amountAttoRep from the caller to this pool, ignores a failed permit when the existing allowance already covers the amount, then performs the depositRepToVault deposit. REP Approval when the permit succeeds, then the depositRepToVault signals depositRepToVaultWithAuthorization(owner, amountAttoRep, targetHealthFactorBps, validAfter, validBefore, nonce, v, r, s) through fallback() Anyone relaying the owner's ERC-3009 signature The pool universe is not genesis ( Genesis REP does not support authorization ); the depositRepToVault prerequisites for owner ; the signature authorizes the token nonce keccak256(abi.encode(nonce, operationHash, owner)) , where operationHash is keccak256(abi.encode(depositRepToVaultWithAuthorization.selector, owner, universeId, questionId, amountAttoRep, targetHealthFactorBps)) . Runs the depositRepToVault checks for owner , pulls amountAttoRep from owner to this pool through the REP token receiveWithAuthorization , then credits owner 's vault. Fee-accrual checkpoints when due; REP AuthorizationUsed and Transfer ; RepDepositedToVault , VaultAccountingCheckpoint , then PoolAccountingCheckpoint depositRepToVaultFromExecutor(owner, amountAttoRep) through fallback() This pool's VaultOperations executor only ( Only vault operations executor ) The depositRepToVault prerequisites for owner , other than the target check, which always passes. Performs the depositRepToVault deposit for owner , pulling REP through owner 's allowance to this pool, with the target fixed at statoblastSecurityMultiplierBps . The depositRepToVault signals redeemFees(vault) Anyone; any nonzero ETH payment is always sent to vault A nonzero payment path requires vault to accept ETH. First accrues the vault's fees. If resulting claimable fees are zero, returns without payment; otherwise clears and pays the full amount. Accrual checkpoints only when accrual state changes; both VaultAccountingCheckpoint and PoolAccountingCheckpoint for a nonzero redemption; no event when fees and accrual state are unchanged createCompleteSet() with ETH Trader Operational and unforked; no escalation game, pending continuation, or inherited fixed outcome; positive ETH converts to at least one complete-set unit. Resulting tracked collateral must not exceed total commitments; no oracle price or REP backing is checked. A contract trader must accept onERC1155BatchReceived under A22 asset-recipient compatibility . Adds collateral and mints one Invalid , Yes , and No share per complete-set unit, then invokes the ERC-1155 batch-receiver callback for a contract trader. Callback rejection rolls back the ETH, pool accounting, events, and share mint. Accrual PoolAccountingCheckpoint when due; CompleteSetCreated , PoolAccountingCheckpoint , then ERC-1155 TransferBatch on a successful callback; retention PoolAccountingCheckpoint when the rate changes redeemCompleteSet(amountAttoShares) Anyone; positive redemption requires the caller to hold the complete set Operational and unforked; caller holds every outcome amount requested; caller accepts the resulting ETH call, including zero value. Zero is accepted without a token balance. Burns equal balances of all three outcomes and pays amountAttoShares * settlementCollateralAttoEth / shareTokenSupplyAttoShares using the pool's remaining economic claim supply as its collateral denominator. Complete-set issuance adds to that denominator, while complete-set and winning-share redemption consume it; fork-time source entitlements materialize without changing it because their claims are already reserved. When the remaining supply reaches zero, aggregate bad debt is cleared and per-vault bad-debt reads advance to an empty collateral generation. Zero passes the token and accounting checks and follows the normal zero-value event, checkpoint, and ETH-send path; rejection of that ETH call reverts the transaction. CompleteSetRedeemed and PoolAccountingCheckpoint redeemShares() Anyone; a positive payout requires the caller to hold winning shares Operational pool with a final outcome; caller accepts the resulting ETH call, including zero value. Burns the caller's full winning balance and pays its pro-rata remaining collateral. When the remaining supply reaches zero, aggregate bad debt is cleared and per-vault bad-debt reads advance to an empty collateral generation. A zero winning balance passes token and accounting checks and follows the normal zero-value event, checkpoint, and ETH-send path; rejection of that ETH call reverts the transaction. SharesRedeemed and PoolAccountingCheckpoint redeemRepFromVault(vault) Vault owner; caller must equal vault , and REP is sent to vault Operational pool with a final outcome; the specified vault has no escalation escrow, has redeemable REP, and has exited its underwriting commitment by setting it to zero ( Exit commitment before REP redemption ) under the limit-reduction rules . Burns the vault's REP backing units and returns its proportional vault REP backing. Fee-accrual checkpoints when due; REP Transfer , RepRedeemedFromVault , then VaultAccountingCheckpoint depositWalletRepToEscalationGame(outcome, maximumDepositAttoRep) REP holder with a token allowance for the pool Question end time reached ( block.timestamp >= endTime ) before starting a game; pool operational in an unforked universe, without an inherited fixed outcome or pending fork continuation; game is not a fork continuation; outcome and amount accepted; sufficient wallet REP and pool allowance. No existing vault or oracle price is required. Starts an ordinary game if needed and transfers the accepted REP directly from the caller into game escrow. Records the caller as depositor without minting vault backing units or underwriting commitments. Also accepts deposits if another reporter has already started the ordinary game. GameStarted , then EscalationGameSet , when the call deploys the game; REP Transfer ; game LocalDepositAppended and DepositOnOutcome ; game NonDecisionReached when the deposit reaches non-decision depositToEscalationGame(outcome, maximumDepositAttoRep) Vault owner Question end time reached ( block.timestamp >= endTime ); pool operational in an unforked universe, without an inherited fixed outcome, and not awaiting continuation. On the first deposit, the live non-decision threshold must exceed one attoREP; outcome and amount accepted; the remaining vault and aggregate pool totals each preserve both full-commitment backing requirements; the vault keeps either no REP or at least minimumVaultRepDepositAttoRep ( Vault REP below minimum ); a fresh price is required when total underwriting commitment is nonzero. Deploys the local game on the first deposit. The game factory uses the configured start bond while it is below the live non-decision threshold; if tracked REP supply later makes it too large, the factory uses nonDecisionThresholdAttoRep - 1 instead. Repeat deposits use the existing game's stored startBondAttoRep and nonDecisionThresholdAttoRep . Every accepted deposit removes enough REP backing units and escrows dispute-staked REP on the selected outcome. GameStarted , then EscalationGameSet , when the call deploys the game; REP Transfer ; game LocalDepositAppended and DepositOnOutcome ; game NonDecisionReached when the deposit reaches non-decision; then DepositToEscalationGame and VaultAccountingCheckpoint withdrawFromEscalationGame(outcome, depositIndexes) Anyone; a nonempty list must select deposits belonging to one original depositor Game configured; operational pool; valid final outcome. If an external fork interrupted the game, parent withdrawal stays unavailable ( Migrate deposits first ): winners settle in the child by carried proof, inherited losers require no transaction, and unresolved parent escalation-deposit accounting cleanup is optional. A nonempty list additionally requires valid local indexes and one common depositor. A nonempty list settles local deposits and pays winning REP to the immutable depositor recorded by each deposit. Liquidation cannot change that payout address. An empty list returns after the outer lifecycle checks without settlement, state change, or event. Per processed deposit, escalation-game CarryDepositConsumed and VaultEscrowUpdated ; additionally ClaimDeposit for a winning deposit. No event for an empty list withdrawForkedEscalationDeposits(outcome, proofs) Anyone; a nonempty list must name one original depositor across all proofs Game configured; operational child pool; valid final outcome. A nonempty list additionally requires an initialized and fully resumed continuation game, valid unconsumed winning proofs, and one common depositor. A nonempty list verifies and consumes carried proofs, then pays winning child REP to the immutable depositor committed in each leaf. Stable continuation identities retain the creating game. Allocations follow the source-game chain and apply each auction REP removal through cumulative interval rounding; read cost grows with fork depth. An empty list returns after the outer lifecycle checks without proof verification, state change, or event. Per processed proof, escalation-game CarryDepositConsumed and ClaimDeposit . No event for an empty list updateSettlementCollateral() Anyone No caller or lifecycle restriction. When the accumulator is already at or beyond the clamped timestamp, it leaves the accumulator unchanged and emits no event, though it still caches the current fee-epoch cutoff. For an initial pool, accrues elapsed fees through question end while its universe remains unforked; if its question remains unresolved when the universe forks, the fork timestamp replaces question end as the cutoff, including a later question-end-to-fork interval. A question finalized before the fork retains its question-end cutoff. Finalizing an activated child starts a separate epoch at that finalization timestamp, which runs until the child game resolves or the child universe subsequently forks. An inherited fixed-outcome child without a continuation game fixes its cutoff at finalization and accrues no later fees. Accumulator timestamps prevent charging an interval twice. It moves whole credited fees from settlement collateral into the unallocated accrued-fee reserve and advances the accumulator. With positive elapsed time but zero fee-eligible underwriting commitment it clears denominator-specific remainder and advances the timestamp without charging fees. PoolAccountingCheckpoint whenever positive elapsed time is processed, including the zero-commitment branch; no event for an unchanged timestamp updateRetentionRate() Anyone No caller restriction. It returns unchanged when the pool is not Operational ; otherwise it first accrues fees, then stores the rate only if it differs. Zero minting capacity (no standing commitments or an escalation game) selects the maximum retention rate. Recalculates the retention rate from current collateral and total underwriting commitment. Accrual PoolAccountingCheckpoint when due; an additional PoolAccountingCheckpoint only when the stored retention rate changes updateVaultFees(vault) Anyone for any address No caller, nonzero-vault, or lifecycle restriction. A vault accounting checkpoint: first updates pool accrual, then advances the vault fee index and fractional remainder, moves whole assigned fees from reserve to the vault, registers any previously unseen nonzero vault address regardless of economic state, and returns leftover reserve to settlement collateral once a forked pool has checkpointed all fee-eligible underwriting commitment. It never changes an underwriting commitment, including in an empty pool. Accrual PoolAccountingCheckpoint when due; VaultAccountingCheckpoint when the vault index, remainder, or claimable fee balance changes; an additional PoolAccountingCheckpoint when pool accounting changes; no event when neither accrual nor vault or pool accounting changes withdrawRepFromVault(vault, amountAttoRep) This pool's VaultOperations executor only ( Unauthorized ) Fresh coordinator price; operational pool in an unforked universe; isEscalationResolved() is false; no vault REP escrow. The remaining vault backing must meet both upward-rounded associated-REP and pool-held-REP requirements for its full underwriting commitment, with equality healthy. The remaining aggregate backing must also cover the entire total underwriting commitment under both backing constraints. A withdrawal cannot implicitly exit a commitment. Removes the requested proportional REP backing units, or all backing units when the requested remainder would fall below the REP minimum; preserves the vault and aggregate underwriting commitments; recalculates retention; and transfers the resulting withdrawable REP to vault . REP Transfer ; RepWithdrawnFromVault ; VaultAccountingCheckpoint ; and applicable fee-accrual or retention PoolAccountingCheckpoint events performLiquidation(request) This pool's VaultOperations executor only ( Unauthorized ) In ABI order, request contains operationId , operator , receiverVault , targetVault , requestedDebtAttoEth , snapshot , minimumReceiverHealthFactorBps , and minLiquidationPriceDistanceBps . The nested snapshot contains only targetBackingUnits and targetUnderwritingLimitAttoEth . Fresh settled coordinator price; operational pool in an unforked universe; isEscalationResolved() is false; receiver differs from target; neither participant has current-generation bad debt. A bad-debt-bearing vault becomes eligible again after the current collateral claims are exhausted, which clears aggregate debt and advances the bad-debt generation. The two target snapshot fields must match, while execution reads current pool totals. After target and receiver fee checkpoints, the liquidation delegate requires live target backing, dispute-staked REP, and full underwriting commitment to remain at least minLiquidationPriceDistanceBps beyond the liquidation threshold and requires the live target state to remain unhealthy. When debt moves, the receiver must satisfy the protocol backing checks multiplied by its approved minimum health factor, using live post-liquidation state and upward-rounded requirements; its resulting commitment must meet the configured debt floor and its REP must meet the vault floor. The target resulting commitment must be zero or meet the commitment floor; partial awards reserve the target REP floor when available. Transfers up to the requested ETH commitment from target to authorized receiver, conserving total commitments. REP awards are capped by available target backing. A sufficiently backed receiver can accept the full commitment even when the nominal award is underfunded. Fees checkpoint first and remain with their earners; escalation claims remain with their owners. Residual commitments remain visible and continue earning fees. Liquidation creates no write-off. Fee-accrual checkpoints when due; VaultLiquidated only when a positive commitment moves, identifying operation, operator, receiver, and target, with the moved commitment in both securityBondDebtMovedAttoEth and underwritingLimitMovedAttoEth and zero badDebtAttoEth ; target VaultAccountingCheckpoint always; receiver VaultAccountingCheckpoint only when a positive commitment moves; then PoolAccountingCheckpoint setStartingParams(currentRetentionRate, settlementCollateralAttoEth) SecurityPoolFactory only Caller is the factory ( Only factory ). The pool has no internal one-shot or lifecycle guard; the factory exposes it only through atomic deployment wiring. Sets the fee timestamp and initial question-end epoch cutoff, retention, and collateral, seeds the coordinator with zero for an origin or the parent's last price for a child, then checkpoints initialization. Coordinator RepEthPriceSet and CoordinatorStateCheckpoint , then pool PoolAccountingCheckpoint , even for zero or repeated values if the factory were to call again activateForkMode() SecurityPoolForker only The pool has no inherited fixed outcome, so a fixed child cannot reopen for a later universe fork. There is no current-state guard otherwise. A configured game's drain must succeed or the entire activation reverts with the game's reason. Sets PoolForked , accrues through the fork clamp, transfers the pool's entire REP balance to the forker, then makes the pool drain its configured escalation game's entire REP balance to the forker. Repeated calls are not lifecycle-guarded and transfer any balances replenished since the prior call before repeating the checkpoints. Pool-held REP Transfer always, including at zero; configured-game REP Transfer only for a positive game balance; accrual checkpoint when due; always PoolForkModeActivated and fork-activation PoolAccountingCheckpoint initializeForkedEscalationGame(startBondAttoRep, nonDecisionThresholdAttoRep, elapsedAtFork, fixedQuestionOutcome) SecurityPoolForker only No game is configured (otherwise it reverts without reason data); downstream startFromFork parameters are valid. Deploys and starts the pool's paused fork-continuation game with inherited timing and optional fixed outcome, and reopens vault admission after question end. Escalation GameContinuedFromFork , then pool EscalationGameSet initializeForkCarrySnapshotWithResolutionBalances(sourceGame, snapshotId, inheritedCarryPeaks, inheritedCarryLeafCounts, inheritedCarryTotals, inheritedResolutionBalances, inheritedNullifierRoots) SecurityPoolForker only A game is configured; it is a fork continuation with no prior snapshot; leaf counts fit the MMR; supplied or computed snapshot ID matches the data. Installs the continuation game's immutable carry peaks, counts, totals, resolution balances, and normalized nullifier roots. ForkCarryCheckpoint resumeForkedEscalationGame() Anyone Pool is operational, awaiting a configured fork continuation, and the game has not resumed. Checks aggregate REP funding of the carry commitment installed during child initialization, clears the pool wait flag, records the resume timestamp, and starts the continuation's remaining escalation clock in one bounded call. ForkContinuationResumed and AwaitingForkContinuationSet(false) setAwaitingForkContinuation(shouldAwait) SecurityPoolForker only No lifecycle or value-change guard. Stores whether complete-set minting must wait for continuation initialization. AwaitingForkContinuationSet , including for a repeated value setSystemState(newState) SecurityPoolForker only No transition or value-change guard. Replaces the pool lifecycle state directly. SystemStateSet , including for a repeated state configureVault(vault, repBackingUnits, underwritingLimitAttoEth, vaultFeeIndex, newVaultBadDebtAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only vault is nonzero; no lifecycle or value-change guard. Replaces the vault REP backing units, price-independent underwriting commitment, fee index, vault bad debt, and aggregate pool bad debt, clears pooled fee-index remainder when underwriting commitment changes, and registers the nonzero vault address regardless of the supplied state. Always VaultAccountingCheckpoint and PoolAccountingCheckpoint , including when all supplied values repeat current state activateRecoveredCommitment(vault, commitmentAttoEth) SecurityPoolForker only Operational, unforked pool, fresh price and both backing checks on the receiver’s entire resulting underwriting commitment. Activates prospective fee eligibility for an orphaned commitment after the forker checkpoints and assigns its backing and commitment. Total commitments remain unchanged. PoolAccountingCheckpoint configureFinalizedAuctionVault(vault, repBackingUnits, underwritingLimitAttoEth, vaultFeeIndex, newVaultBadDebtAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only vault is nonzero; the forker has already included the sold underwriting commitment in the pool fee denominator at auction finalization. Assigns finalized-auction REP backing and already-fee-eligible underwriting commitment to the winning vault without clearing the pool-wide fee-index remainder, then replaces the vault fee index, bad debt, and aggregate pool bad debt and registers the vault. Always VaultAccountingCheckpoint and PoolAccountingCheckpoint , including when all supplied values repeat current state setTotalRepBackingUnits(newTotalRepBackingUnits) SecurityPoolForker only No lifecycle or value-change guard. Replaces the REP backing units denominator. TotalRepBackingUnitsSet , including for zero or a repeated value setShareTokenSupplyAttoShares(newShareTokenSupplyAttoShares) SecurityPoolForker only No lifecycle or value-change guard. Replaces stored shareTokenSupplyAttoShares , the denominator used by attoSharesToAttoEth and complete-set redemption. ShareTokenSupplySet , including for zero or a repeated value setPoolFinancials(newSettlementCollateralAttoEth, newTotalUnderwritingLimitAttoEth, newFeeEligibleUnderwritingLimitAttoEth, newTotalBadDebtAttoEth) SecurityPoolForker only Fee-eligible underwriting commitment does not exceed total underwriting commitment. Actual ETH covers the supplied collateral plus all accrued fee liabilities. Installing inherited liabilities does not require current REP solvency. Replaces settlement collateral, both price-independent underwriting-commitment totals, and aggregate pool bad debt, resets the fee timestamp to the current block, opens the finalized child fee epoch unless the child has a fixed outcome and no continuation game, and clears fee-index rounding carry. PoolAccountingCheckpoint , including for repeated financial values authorizeChildPool(pool) SecurityPoolForker only This parent pool is already authorized; candidate reports this share token; candidate universe has no different canonical pool. No pool-lifecycle guard. Asks the lineage share token to establish pool as the canonical authorized pool for its universe; reauthorizing the same pool is a no-op. AuthorizationUpdated only on first authorization; no event when already authorized transferEth(receiver, amountAttoEth) SecurityPoolForker only Fee liabilities are covered; amountAttoEth fits both unreserved pool ETH and tracked settlement collateral; receiver accepts the ETH call, including zero value. Reduces tracked settlement collateral by amountAttoEth , checkpoints the reconciliation, and calls receiver with that ETH. At zero amount it reduces no settlement collateral but still emits the checkpoint and performs a zero-value call; callback rejection rolls back the transaction and checkpoint. PoolAccountingCheckpoint , including at zero amount; no dedicated ETH-transfer event assignFinalizedAuctionFees(vault, amountAttoRep, auctionFeeIndexAtFinalization) SecurityPoolForker only Despite its name, amountAttoRep is the claimed underwriting commitment in attoETH: the pool uses it as the fee weight and subtracts it from its uncheckpointed fee-eligible commitment. The supplied finalization index does not exceed the current fee index ( Fee index ); the forker credit workflow has already checkpointed the vault and added the claimed underwriting commitment. Assigns to the claiming vault the fees its auctioned underwriting commitment accrued from Truth Auction finalization through the current fee index, combines fractional carry with the vault remainder, and removes whole assigned fees from the unallocated reserve. The ownership was already included in the fee denominator and total ownership at finalization. This call preserves aggregate fees and settlement collateral; after every eligible ownership is reconciled on a forked pool, a subsequent permissionless updateVaultFees checkpoint returns any reserve that no vault can individually claim to settlement collateral. VaultAccountingCheckpoint and auction-claim PoolAccountingCheckpoint ; the calling forker emits ClaimAuctionProceeds only after the broader credit workflow completes Direct ETH transfer to receive() Forker, this pool's Truth Auction, or parent pool only ( Bad ETH sender ) Sender is one of the three authorized protocol addresses. Forced ETH bypasses this ordinary-call guard. Accepts protocol-routed ETH used by migration and auction settlement. Forced ETH remains raw, unaccounted surplus rather than settlement collateral or fees. EthReceived identifies the authorized sender and amount received; forced ETH bypasses receive() and emits no such event","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"retention-rate-and-annualized-fee","heading":"Retention rate and annualized fee","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"SecurityPoolUtils.calculateRetentionRate returns a per-second retention factor scaled by PRICE_PRECISION ( 1e18 ). It equals MAX_RETENTION_RATE at zero utilization, declines linearly until utilization reaches RETENTION_RATE_DIP (80% of minting capacity, which is total underwriting commitments outside an escalation game), and stays at MIN_RETENTION_RATE above that. Zero minting capacity selects MAX_RETENTION_RATE . MAX_RETENTION_RATE = 999_999_996_848_000_000 , about a 9.5% yearly fee. MIN_RETENTION_RATE = 999_999_977_880_000_000 , about a 50.2% yearly fee. Clients annualize a retention rate for display as follows; the contract never computes this value. annualFee = 1 − ( retentionRate PRICE_PRECISION ) SECONDS_PER_YEAR","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"liquidation-transfer-rounding","heading":"Liquidation transfer rounding","keywords":[],"path":"reference/contracts/securitypool.html","sectionTitle":"Reference","summary":"Read surface, security assumptions, and the vault, complete-set, escalation, executor-only, forker-only, and fallback-routed entrypoints, with accounting examples.","text":"A liquidation request bounds the underwriting commitment transferred, capped by the target’s underwriting commitment. The nominal REP award includes LIQUIDATION_REP_BONUS_BPS = 500 (5%). REP and backing units round upward before the award is capped at available units. The receiver is checked against its entire resulting underwriting commitment and backing-unit position. Total underwriting commitments remain constant, including at zero settlement collateral. Target claims and earned fees remain with their owners. No liquidation writes off a commitment. An untransferred residual stays visible and continues earning fees. A fully backed receiver can accept the target’s entire underwriting commitment even when the nominal REP award is not fully funded. Partial transfers reserve available target REP for the minimum balance, and the remaining commitment must be zero or meet the commitment floor.","title":"SecurityPool","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["fork","migration","child pool","auction"],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Freezes parent pools, creates selected child pools, migrates vault and escalation state, and settles collateral-repair Truth Auctions . SecurityPoolForker source contract","title":"SecurityPoolForker","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Use zoltar , forkData , getUnassignedPosition , isEscalationDepositClaimedDirectly , getEscalationDepositId , getDirectlyClaimedEscalationPrincipal , isEscalationWinnerHaircutPaidByFork , getEscalationMigrationEntitlementStatus , getOwnForkRepBuckets , getOwnForkMigrationStatus , getMigrationProxyAddress , getQuestionOutcome , attoRepToBackingUnits , and backingUnitsToAttoRep to reconstruct fork progress and preview migration conversions. forkData includes cumulative migrated REP and the fork-activation timestamp. getUnassignedPosition returns pending REP backing units, underwriting commitment, raw auction bad debt, that debt’s generation, and the auction-finalization fee index; consumers count the debt only while its generation equals the pool snapshot’s current badDebtGeneration .","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"child-game-trust-boundary","heading":"Child-game trust boundary","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Fork entrypoints and child setup may receive contracts through unauthenticated pool lineages. External-universe initiation requires the supplied pool to be authorized by its declared share token, but that relationship alone does not prove factory registration; own-game initiation does not perform that authorization check. Canonicality comes from the configured SecurityPoolFactory registry. A game relationship check is point-in-time: the reported nonzero game address must return the supplied pool or child from securityPool() when validated. This does not prove that an arbitrary game getter is immutable or that the address was factory-deployed. Child setup captures one reported game address, validates it before privileged use, and reuses that exact address for continuation backing and escrow work. When unresolved escalation requires a continuation and setup initially reports no game, initialization creates one; the forker then captures and validates it before continuation use. Combined vault migration passes the captured child/game pair into unresolved cleanup without reading the child getter again. Truth Auction completion performs a fresh point-in-time validation of the game reported then before checking continuation readiness. Genuine factory-deployed EscalationGame instances store their pool immutably, but safety on unauthenticated paths does not assume arbitrary contracts do.","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/securitypoolforker.html","sectionTitle":"Reference","summary":"Read surface, the child-game trust boundary, and the fork initiation, child creation, vault migration, and Truth Auction entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. claimForkedEscalationDeposits and migrateVaultWithUnresolvedEscalation revert without reason data when one of the prerequisites marked \"no reason data\" fails; the forker omits those reason strings to stay within the contract code-size limits. Transaction Caller Main prerequisites State or asset effect Primary signals initiateSecurityPoolFork(securityPool) Anyone Pool operational with no inherited fixed outcome; the pool is authorized by its declared share token; its universe already forked; pool not already PoolForked ; if an escalation game exists, it reports the supplied pool from securityPool() when validated and the universe fork occurred before that game settled. Declared-token authorization is not configured-factory registration; see the child-game trust boundary . Freezes the supplied pool after an external universe fork, drains its pool and game REP, and records a migration snapshot keyed by that address. The snapshot is canonical only when the supplied pool is already registered by the configured SecurityPoolFactory . SecurityPoolForkSnapshot and ParentRepLocked ; additionally DisputeStakedRepDrainedAtFork when unresolved escalation exists forkZoltarWithOwnEscalationGame(securityPool) Anyone Pool operational with no inherited fixed outcome; its escalation game reports the supplied pool from securityPool() when validated and canTriggerOwnFork() is true because it recorded a local non-decision or inherited a threshold tie without a game-level fixed outcome ( Need game ); pool not already PoolForked ( Forked ) and Operational ( Inactive ); universe not already forked; the pool and game REP released to the forker reaches the Zoltar fork threshold ( Fork threshold not reached ). The game-local predicate does not bypass the pool guard. Unlike external-universe initiation, this entrypoint does not require declared-share-token authorization; neither path authenticates the supplied address against the configured pool factory. See the child-game trust boundary . Uses the supplied pool game's non-decision to fork Zoltar, freezes that pool, and records own-fork REP buckets and snapshot state keyed by its address. The snapshot is canonical only when the supplied pool is already registered by the configured SecurityPoolFactory . SecurityPoolForkSnapshot , ParentRepLocked , and Zoltar fork events; additionally DisputeStakedRepDrainedAtFork when unresolved escalation exists migrateRepToZoltar(securityPool, outcomeIndices) Anyone Migration proxy exists and the pool is PoolForked . Only a positive migration amount with at least one selected outcome checks the eight-week window, existing child ForkMigration state, outcome validity, and cumulative split bound. A zero amount skips those checks even when outcome values are supplied. For a positive migration amount and nonempty list, ensures that the forker's recorded pool migration amount has been split into each selected child REP branch. A zero migration amount or empty list returns after the proxy and pool-state guards without per-outcome validation or events. MigrationRepSplit and ChildRepSplit when a selected branch requires a new split; no event for a zero amount, empty list, or already-satisfied branch createChildUniverse(securityPool, outcomeIndex) Anyone Parent in migration window; selected fork outcome is well formed; child pool is not already deployed. The returned auction is nonzero, deployed, and has never been trusted by this forker; the child's fork-data slot is unused; and the child reports the expected parent, universe, source factory, forker, and auction. The selected child's reported nonzero escalation game passes the child-game trust boundary . These relationship checks do not independently prove configured-factory registration. Loads an already deployed child universe and REP token or deploys them when absent, then lazily deploys the selected child pool, coordinator, and auction; authorizes and links the child; captures and validates the child's escalation game; and initializes any continuation snapshot and materializes or sweeps child backing through that validated game. DeployChild only when child REP was absent; always SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , ChildPoolLinked , and TotalRepBackingUnitsSet ; AwaitingForkContinuationSet , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , MigrationRepSplit , ChildDisputeStakedRepMaterialized , and PoolHeldRepSweptToChild as continuation and backing state requires migrateVault(securityPool, outcomeIndex) Vault owner for their non-escrowed position Migration window open; the selected child's reported nonzero escalation game passes the child-game trust boundary . The optional unresolved parent escalation-deposit accounting cleanup wrapper calls this function first to migrate transferable vault state. Converts the caller's parent REP backing-unit claim to REP at the fork snapshot and credits that REP amount as child-local backing units; transfers the underwriting commitment and any tracked vault bad debt into one child pool; checkpoints but retains claimable fees in the parent vault; and separately routes proportional pool-level settlement collateral while preserving aggregate bad debt. The underwriting commitment migrates separately from REP backing. Repeat calls can have no additional REP backing units, underwriting commitment, or vault bad debt to move. VaultBadDebtMigrated and VaultMigrationCheckpoint migrateVaultWithUnresolvedEscalation(securityPool, vault, childOutcomeIndex) The named vault owner The migrateVault prerequisites. No reason data: caller equals vault ; migration window open; the fork recorded unresolved escalation ( unresolvedEscalationAtFork ); selected child not already recorded for this vault's cleanup; the selected child has an escalation game. First runs migrateVault(securityPool, childOutcomeIndex) for the caller, with that row's effects, and keeps the child and the validated escalation game that call captured, without reading the child's game again. It then clears that vault's unresolved parent escalation-deposit accounting in constant-size work and records it; the cleanup neither funds dispute-staked REP backing nor authorizes carried proofs. The migrateVault signals; EscalationMigrationEntitlementInitialized on the first cleanup for the vault; EscalationMigrationEntitlementMaterialized for the selected child claimForkedEscalationDeposits(securityPool, vault, outcomeIndex, depositIndexes) The named vault owner ( Vault ) Caller equals vault . No reason data: unresolved escalation existed when the pool initiated its own fork and the parent game still satisfies canTriggerOwnFork() by having either a local non-decision or an inherited threshold tie without a fixed outcome; the selected child remains in ForkMigration , is inside the eight-week claim window, and has a continuation game; every listed deposit commits vault as its immutable depositor. The selected child can be created or loaded and its game passes the child-game trust boundary . A nonempty list additionally requires the matching winning outcome and unclaimed deposit identities. First gets or lazily deploys the selected child universe, REP token, pool, coordinator, and auction, then captures and validates the child's escalation game and uses that same game for continuation backing and escrow payment. A nonempty list claims winning own-fork parent deposits and records their stable identities against descendant replay. An empty list still performs child setup and emits a zero-valued claim summary. DeployChild , SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , ChildPoolLinked , TotalRepBackingUnitsSet , AwaitingForkContinuationSet , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , MigrationRepSplit , ChildDisputeStakedRepMaterialized , and PoolHeldRepSweptToChild as setup requires; per claimed deposit, CarryDepositConsumed and ClaimDeposit ; escrow record/export events when REP is paid; always ClaimForkedEscalationDepositsToWallet , including for an empty list startTruthAuction(securityPool) Anyone Child migration window ended; pool is in fork migration; required child REP is available. If unresolved escalation existed at fork, any game reported during immediate completion passes the child-game trust boundary . Copies the frozen parent's remaining economic claim supply into the child, closes migration accounting, and either reopens a fully backed child or starts its repair auction. ShareTokenSupplySet , then TruthAuctionStarted when an auction starts; immediate no-auction completion instead emits TruthAuctionFinalized , pool accounting checkpoints, and ForkContinuationResumed for an unresolved continuation finalizeTruthAuction(securityPool) Anyone msg.value is zero ( No repair ETH ); the Truth Auction started and its one-week window has passed ( Auction open ). Actual child ETH covers the installed settlement collateral plus accrued fee liabilities. Installing these inherited liabilities does not require current REP backing. If unresolved escalation existed at fork, the game reported at completion passes the child-game trust boundary . Finalizes the ended auction, accounts migration-routed settlement collateral plus accepted bid ETH, and records every unmigrated REP backing unit, commitment unit, and the unmigrated remainder of the parent’s fork-time bad debt in an explicit nonwithdrawable unassigned position. It activates the child and saves the fee index. For positive existing-owner REP residue, total backing units are P × H / (H − Q), rounded up to a whole unit, where P is fork-time pool-held REP for all existing owners including unmigrated vault owners, H is finalization pool-held REP including sold escrow REP, and Q is purchased REP. The bidder backing-unit budget is total units minus P. If H − Q is zero, bidder units use H × PRICE_PRECISION (1e18) while migrated units remain in the total. Underwriting commitment has a separate budget. Positive-purchase auction ownership becomes fee eligible immediately; after a zero-purchase auction, the unassigned underwriting commitment remains outside fee eligibility. TruthAuctionFinalized , auction AuctionFinalized , and pool accounting checkpoints; TruthAuctionHaircutApplied when purchased REP removes a positive escalation allocation; ForkContinuationResumed for an unresolved continuation settleAuctionBids(securityPool, vault, claimTickIndices, refundTickIndices) Anyone on behalf of the named bidder vault At least one index ( Need action ). Before finalization the claim list must be empty ( Not final ) and the refund indexes must satisfy the refundLosingBidsFor prerequisites. After finalization, the claimAuctionProceeds prerequisites apply to the combined list. Before finalization, refunds the listed provably losing bids through the auction refundLosingBidsFor . After finalization, appends the refund list to the claim list and performs the claimAuctionProceeds settlement on the combined list. Before finalization, auction BidSettled per refunded bid and one aggregate EthRefundCredited when total credited ETH is positive. After finalization, the claimAuctionProceeds signals takeOverUnassignedCommitment(securityPool, maximumCommitmentAttoEth) Receiving vault owner Positive residual commitment within the caller’s explicit maximum; no auction purchases; fresh price; operational, unforked pool; receiver fully backs its entire resulting underwriting commitment. Sold entitlements are never available for takeover. Assigns all residual ETH commitment, unassigned REP backing, and unclaimed auctioned bad debt from a finalized zero-purchase auction to the caller; the bad debt is assigned only while the recorded auction bad-debt generation is current. Conserves total commitments and backing units. Preserves earned fees and starts recovered fee rights at the takeover checkpoint. UnassignedCommitmentTakenOver and vault/pool accounting checkpoints claimAuctionProceeds(securityPool, vault, tickIndices) Anyone on behalf of the named bidder vault Auction finalized ( Not final ). A nonempty list additionally requires every index to belong to the named vault owner and remain unsettled. For a nonempty list, withdraws finalized bid settlements and transfers each claim's proportional REP backing units, underwriting commitment, and finalization-to-claim fees from the unassigned position to the bidder vault. Its bad-debt share transfers only while the auction's recorded debt generation is still current; after those collateral claims are exhausted, the old debt expires while raw claimed-auction counters continue to settle deterministically. Commitment and bad-debt division dust follows each bid's deterministic cumulative ETH position, so claim order cannot change individual or aggregate settlement. The transfer does not change total underwriting commitment, fee eligibility, active open interest, total bad debt, retention, or aggregate accrued fees. A winning dust bid can receive underwriting commitment when its REP allocation rounds to zero. The call's aggregate positive refund is credited to the named bidder's pull-payment balance without calling recipient code. For an empty list, the wrapper exits after the finalization guard without validating bids or the named beneficiary, changing state, or emitting events. For processed bids, underlying auction BidSettled ; one aggregate EthRefundCredited per call when total credited ETH is positive; ClaimAuctionProceeds when REP backing, underwriting commitment, or raw auction bad-debt settlement advances. Its cumulative claimed and total auctioned bad-debt fields are raw counters; effective vault debt still requires the recorded auction generation to match the pool’s current generation; no event for an empty list initializeChildForkedEscalationGameIfNeeded(parent, child, childEscalationGame) This SecurityPoolForker contract only ( Only self ), through its migration delegate callback External caller is the forker itself, so parent and child come from its own migration path; a supplied nonzero game passes the child-game trust boundary . Allows delegated migration code to initialize a child continuation while preserving the forker as the authoritative caller and the already captured child-game identity. When unresolved escalation requires a continuation and no game existed, it captures and validates the game created by initialization before any continuation use. EscalationGameSet and GameContinuedFromFork when a continuation game is created; ForkCarryCheckpoint when the carry snapshot is installed; ForkContinuationResumed and AwaitingForkContinuationSet only when the child is already operational Direct ETH transfer to receive() A child-pool Truth Auction trusted by this forker during ChildPoolLinked ( Only trusted auction ) trustedAuctionAddresses[msg.sender] was set when the forker linked the child and emitted ChildPoolLinked ; configured-factory registration determines whether that lineage is canonical. Accepts auction ETH during forker-controlled auction finalization. No dedicated receive event; auction AuctionFinalized is followed by forker TruthAuctionFinalized and pool accounting checkpoints","title":"SecurityPoolForker","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["escalation","dispute","deposit","non-decision"],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Escrows outcome REP, raises the running resolution cost, detects non-decision , and settles local or carried deposits. EscalationGame source contract","title":"EscalationGame","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Base getters are securityPool , repToken , activationTime , nonDecisionThresholdAttoRep , startBondAttoRep , nonDecisionTimestamp , nonDecisionState , forkContinuation , forkElapsedAtStart , forkResumedAt , fixedQuestionOutcome , nodes , disputeStakedRepByVaultAttoRep , totalDisputeStakedAttoRep , truthAuctionRepBeforeAttoRep , and truthAuctionRepRemainingAttoRep . The fallback forwards every selector other than the two signed deposits to EscalationGameClaimDelegate , which provides the reads rootClaimSourceGame , getInheritedClaimAllocation , and getUnresolvedClaimInterval . The allocation read returns source principal, retained principal, reward-interval length, and the cumulative reward endpoint after per-generation auction rounding. The reward interval is the deposit’s range within its outcome’s cumulative deposits: its start is the returned endpoint minus the returned length. It determines which portion enters the reward calculation; the length is not a payable reward. Exported principal intervals compact consumed prefixes, while reward positions remain unshifted by prior claims. Allocations within a game stay fixed in every claim order. disputeStakedRepByVaultAttoRep is locally attributed current-game escrow used for health; inherited carry remains aggregate commitment state until proof settlement. Use previewDepositOnOutcome , computeIterativeAttritionCostAttoRep , computeTimeSinceStartFromAttritionCostAttoRep , totalCostAttoRep , getEscalationGameEndDate , getQuestionResolution , getFinalQuestionResolution , hasReachedNonDecision , canTriggerOwnFork , getBindingCapitalAttoRep , getOutcomeBalancesAttoRep , getDepositsByOutcome , getDepositsByOutcomeLength , forkCarrySnapshotInitialized , getOutcomeState , getForkCarrySnapshot , getForkCarryRoots , isForkCarryFundingComplete , getCarryLeafPageByOutcome , getProofConsumedCarriedDepositIndexesByOutcome , getLocalUnresolvedPrincipalByVaultAndOutcome , and getForkedEscrowByVaultAndOutcome for calculations, lifecycle authorization, pages, carry state, and escrow. Vault-funded deposits and ordinary withdrawals route through SecurityPool , while own-fork direct claims route through SecurityPoolForker ; after an ordinary game starts, wallet-funded deposits use depositRepOnOutcome , depositRepOnOutcomeWithPermit , or depositRepOnOutcomeWithAuthorization and mint no pool backing units.","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Rows marked \"through fallback() \" are not in the compiled ABI: the fallback forwards the two signed deposit selectors to EscalationGameDepositDelegate and every other unknown selector to EscalationGameClaimDelegate by delegatecall , and returns or reverts with the delegate output. A call restricted to the owning pool or its forker reverts without reason data for any other caller. Transaction Caller Main prerequisites State or asset effect Primary signals start(startBondAttoRep, nonDecisionThresholdAttoRep) Immutable owner, the EscalationGameFactory , only ( Only owner ), during atomic deployment Game not already started, and nonDecisionThresholdAttoRep > startBondAttoRep > 0 ( Invalid game start ). Initializes a local game and sets activation three days after deployment. For ordinary pool games, the factory lowers an oversized configured bond to nonDecisionThresholdAttoRep - 1 before this call. GameStarted startFromFork(startBondAttoRep, nonDecisionThresholdAttoRep, elapsedAtFork, fixedQuestionOutcome, winnerHaircutPaidByFork, forkCarryInitialBackingAttoRep) Immutable owner, the EscalationGameFactory , only ( Only owner ), during atomic continuation deployment Game not already started, and nonDecisionThresholdAttoRep > startBondAttoRep > 0 ( Invalid game start ); elapsedAtFork is at most seven weeks ( Invalid fork elapsed time ). Initializes a paused continuation with inherited elapsed time, an optional fixed matching child outcome, and immutable fork-time escalation-haircut and backing accounting. It does not start the remaining clock until resumeFromFork . GameContinuedFromFork resumeFromFork() Owning SecurityPool only ( Only pool ) Fork-continuation mode; not previously resumed; aggregate REP funding complete ( isForkCarryFundingComplete ). The game does not itself require an installed snapshot; the forker installs it during child initialization. An unrelated fork requires one-to-one backing of effective unresolved principal. For an own-fork continuation, recorded initial backing must be at least R - ⌊R / 5⌋ , where R is the sum of inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep across all three outcomes before direct-claim deductions, and 5 is the fixed Constants.MINIMUM_FORK_BURN_DIVISOR rather than the configured fork burn divisor. The live balance must cover that initial backing minus child REP already exported by valid direct pre-resume claims, scaled down by any REP applyTruthAuctionHaircut removed. Records the resume timestamp once carry funding is complete. The new deadline is max(rebasedCurveEnd, forkResumedAt + 3 days) , so even an exhausted inherited clock receives a fresh response period. After that deadline, getFinalQuestionResolution returns the fixed outcome when the continuation has one. ForkContinuationResumed applyTruthAuctionHaircut(repToRemoveAttoRep) The child pool's SecurityPoolForker only ( Only forker ) Paused fork continuation; no prior auction haircut; the requested amount is below the game's live REP balance. Transfers sold REP to the pool, proportionally reduces escrow and outcome balances, and rebases curve time. If an unfixed continuation inherited two threshold-full outcome balances and the auction REP removal leaves them below the current game threshold, ordinary pool-mediated deposit checks apply after the pool resumes the game. Fixed outcomes and local non-decisions retain their state. The game stays paused until the pool resumes it. TruthAuctionHaircutApplied and REP Transfer ; InheritedThresholdTieReopened when an unfixed inherited tie reopens depositRepOnOutcome(outcome, maximumDepositAttoRep) Any REP holder Current game is the pool's ordinary unresolved game; pool operational; universe unforked; outcome non- None ; caller allowance to this game covers the accepted REP; preview accepts a positive amount within the remaining threshold room. Transfers the accepted REP directly from the caller into dispute escrow, appends a local deposit, and records its carry leaf without minting pool backing units. REP Transfer , LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision depositRepOnOutcomeWithPermit(outcome, maximumDepositAttoRep, deadline, v, r, s) through fallback() Any child-universe REP holder The depositRepOnOutcome game, pool, and preview prerequisites; the pool universe is not genesis ( Genesis REP does not support permit ); the permit succeeds or the caller allowance to this game covers the previewed amount ( Game permit and allowance insufficient ). Calls the REP token permit for the previewed amount from the caller to this game, ignores a failed permit when the existing allowance already covers that amount, then performs the depositRepOnOutcome deposit. REP Approval when the permit succeeds, then the depositRepOnOutcome signals depositRepOnOutcomeWithAuthorization(owner, outcome, maximumDepositAttoRep, validAfter, validBefore, nonce, v, r, s) through fallback() Anyone relaying the owner's ERC-3009 signature The depositRepOnOutcome game, pool, and preview prerequisites; the pool universe is not genesis ( Genesis REP does not support authorization ); the signature authorizes the token nonce keccak256(abi.encode(nonce, operationHash, owner)) , where operationHash is keccak256(abi.encode(depositRepOnOutcomeWithAuthorization.selector, owner, securityPool, universeId, questionId, outcome, maximumDepositAttoRep, previewedAmount)) . Pulls the previewed amount from owner to this game through the REP token receiveWithAuthorization and records the deposit for owner . REP AuthorizationUsed and Transfer , LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision recordDepositFromSecurityPool(depositor, outcome, amountAttoRep, expectedCumulativeAttoRep) Owning SecurityPool only ( Only pool ) Explicit non-decision state is None ; game unresolved; valid outcome; preview and accepted cumulative amount match; room remains below threshold. Appends an accepted local deposit, updates outcome and vault escrow, and records its carry leaf. LocalDepositAppended , DepositOnOutcome , and NonDecisionReached when the deposit reaches non-decision withdrawDeposit(depositIndex, outcome) , the uint256 overload Owning SecurityPool only ( Only pool ) Explicit non-decision state is None ; non- None supplied outcome; game final; game and pool final outcomes match; valid unsettled local deposit index. Consumes one local deposit after resolution. A winner pays the deposit's immutable depositor after its escalation haircut; a loser only retires its escrow accounting. CarryDepositConsumed and VaultEscrowUpdated ; for a winner, ClaimDeposit , positive REP payout Transfer , and escalation-haircut burn signals when nonzero initializeForkCarrySnapshotWithResolutionBalances(sourceGame, snapshotId, snapshotPeaksInput, snapshotLeafCountsInput, snapshotCarryTotalsAttoRep, snapshotResolutionBalancesAttoRep, snapshotNullifierRoots) Owning SecurityPool only Fork-continuation mode; no prior snapshot; each leaf count fits the MMR; supplied nonzero snapshot ID equals the hash of the normalized data. Installs the immutable inherited peaks, leaf counts, carry totals, resolution balances, and normalized nullifier roots; zero snapshot ID selects the computed ID. Two or more threshold-full inherited balances set nonDecisionState to InheritedThresholdTie without creating a local timestamp. ForkCarryCheckpoint ; additionally InheritedThresholdTie when the installed balances meet the non-decision threshold initializeForkClaimCheckpoint(sourceGame) through fallback() Owning SecurityPool only ( Only pool ) sourceGame equals the source game recorded by the installed carry snapshot ( Claim source ); no Truth Auction haircut has been applied ( Haircut applied ). Records the root claim source game: the value sourceGame reports from rootClaimSourceGame() , or sourceGame itself when that value is zero. The game runs the same step internally while installing a carry snapshot with a nonzero source game, and no pool function calls this selector. No event claimDepositForWinning(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Non- None supplied outcome and valid unsettled local deposit with sufficient escrow. This entrypoint itself does not check final resolution or that the supplied outcome won; its trusted caller selects that path. Consumes a selected local deposit as a winner, consumes its vault escrow, burns the computed escalation haircut when nonzero, and transfers the remaining positive REP payout to the deposit's immutable depositor. CarryDepositConsumed , VaultEscrowUpdated , ClaimDeposit with transferredRep = true ; REP payout Transfer and escalation-haircut burn signals only when their amounts are positive claimDepositForWinningWithoutTransfer(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Valid in-range supplied outcome and unsettled local deposit with sufficient escrow. Unlike the transferring form, it has no explicit non- None guard; neither form checks final resolution or that the outcome won. Consumes a selected local deposit and its vault escrow. The depositor's raw escrow backing decreases by the inverse-retention claim units corresponding to the deposit's original principal: the principal itself with no local auction checkpoint, or ⌈originalPrincipal × truthAuctionRepBeforeAttoRep / truthAuctionRepRemainingAttoRep⌉ after a local auction REP removal. Other unconsumed deposits by the same depositor remain backed. The game returns the computed winner amount to the trusted caller but deliberately neither transfers REP nor burns the computed escalation haircut. CarryDepositConsumed , VaultEscrowUpdated , and ClaimDeposit with transferredRep = false ; no REP transfer or escalation-haircut burn exportUnresolvedDeposit(depositIndex, outcome) Owning SecurityPool or its SecurityPoolForker Non- None outcome and a valid unsettled local deposit. Final resolution is not required. Returns deposit identity and amount to the trusted caller while consuming the local deposit from unresolved/escrow accounting without transferring REP. CarryDepositConsumed and VaultEscrowUpdated ; no ClaimDeposit or REP transfer withdrawDeposit(proof, outcome) , the CarriedDepositProof overload Owning SecurityPool or its SecurityPoolForker Non- None supplied outcome; game final and matching the pool final outcome; supplied outcome is the winner; parent deposit was not directly claimed; valid unconsumed Merkle/nullifier proof. Consumes an inherited proof, transfers any positive winning payout, and burns the positive escalation haircut unless the fork already paid it. CarryDepositConsumed and ClaimDeposit with transferredRep = true ; REP payout Transfer and escalation-haircut burn signals only when positive exportVaultUnresolvedTotals(vault, repReceiver) Owning SecurityPool or its SecurityPoolForker vault is nonzero and has not exported before. There is no explicit nonzero-receiver guard: a zero receiver succeeds when the total is zero but the token rejects it when a positive transfer is attempted. Marks the vault's local unresolved totals exported exactly once, clears each outcome amount, consumes aggregate unresolved and escrow accounting when positive, and transfers the positive total to repReceiver . Always VaultUnresolvedTotalsExported , including when every amount is zero; VaultEscrowUpdated and REP Transfer only for a positive total exportVaultUnresolvedTotalsWithoutTransfer(vault) Owning SecurityPool or its SecurityPoolForker vault is nonzero and has not exported before. Marks the vault's local unresolved totals exported exactly once, clears each outcome amount, and consumes aggregate unresolved and escrow accounting when positive, but leaves token movement to its caller. Always VaultUnresolvedTotalsExported with transferredRep = false , including when every amount is zero; VaultEscrowUpdated only for a positive total; no REP transfer drainAllRep(receiver) Owning SecurityPool only ( Only pool ) receiver is nonzero; no positive-balance requirement. The protocol reaches this call from the owning pool after activateForkMode enters PoolForked . Transfers the game's full REP balance to receiver . A zero balance returns zero without a transfer or event. REP Transfer for a positive balance; no event at zero balance recordForkedEscrowForOutcome(depositor, outcome, sourcePrincipalAttoRep, childRepAmountAttoRep) Owning SecurityPool or its SecurityPoolForker Outcome is not None ; depositor is nonzero. Source principal and child REP may independently be zero; when both are zero, the call is a no-op. Accumulates source principal and child REP escrow for the depositor and outcome. The depositor remains the immutable payout owner; inherited claims remain in the carry commitment and are not copied into child-local ownership state. When both amounts are zero, returns without changing state or emitting an event. ForkedEscrowRecorded for a nonzero record; no event when both amounts are zero exportForkedEscrowByOutcome(vault, repReceiver) Owning SecurityPool or its SecurityPoolForker vault and repReceiver are nonzero. Marks every remaining per-outcome escrow amount exported and transfers its positive child REP. When all outcomes were already empty or exported, returns zero arrays without state change, token transfer, or event. ForkedEscrowExported when any source principal or child REP remains; VaultEscrowUpdated and REP Transfer when positive child REP is transferred; no event for an already-empty export exportForkedEscrowByOutcomeWithoutTransfer(vault) Owning SecurityPool or its SecurityPoolForker vault is nonzero. Marks every remaining per-outcome escrow amount exported without transferring child REP. When all outcomes were already empty or exported, returns zero arrays without state change or event. ForkedEscrowExported with transferredRep = false when any source principal or child REP remains; VaultEscrowUpdated when positive child REP remains; no REP transfer; no event for an already-empty export sweepResidualRepToSecurityPool() Anyone Final outcome; no unresolved principal; no vault escrow; positive residual balance. Returns ordinary-game residual REP to the owning pool. Burns fork-continuation residual so pre-child capital cannot accrue to late or nonexistent child owners. ResidualRepSweptToSecurityPool for an ordinary game; ForkContinuationResidualRepBurned for a fork continuation","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"required-support-threshold","heading":"Required support threshold","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"The contract waits ACTIVATION_DELAY (3 days) after start() before the escalation clock begins. From day 3 the cumulative binding-capital requirement rises from the configured start bond S to the non-decision threshold T over the 49-day ESCALATION_TIME_LENGTH , reaching T on day 52. The contract evaluates a fixed-point curve; this expression is its readable idealization. A ( d ) = 0 for 0 ≤ d ≤ 3 = S × exp ( ln ( T S ) × d − 3 49 ) for 3 < d < 52 = T for d ≥ 52","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"winning-deposit-payout","heading":"Winning-deposit payout","keywords":[],"path":"reference/contracts/escalationgame.html","sectionTitle":"Reference","summary":"Read surface and the start, deposit, withdrawal, claim, fork-carry, escrow export, and fallback-routed entrypoints, with accounting examples.","text":"Binding capital is the median outcome balance at settlement; no outcome balance can exceed the non-decision threshold. The reward-eligible cap is binding capital plus binding capital divided by EXCESS_REWARD_WINDOW_DIVISOR (2), so only the portion of winning deposits up to 1.5 × binding capital participates in the bonus. Of the binding capital, 3 / 5 funds the reward pool and 2 / 5 funds the escalation-haircut pool; both are shared pro rata across the reward-eligible principal, which is the smaller of the winning outcome balance and that cap. Let binding capital be 10 REP , so the reward-eligible cap is 15 REP , the reward pool is 6 REP , and the escalation-haircut pool is 4 REP . If the winning outcome holds 15 REP and one deposit contributed 5 REP inside the eligible range: Principal returned: 5 REP . Bonus: 5 × 6 / 15 = 2 REP . Winning payout: 5 + 2 = 7 REP . Haircut burned: 5 × 4 / 15 = 1.333333333333333333 REP at attoREP precision. A winning deposit position above 15 REP returns its principal without a bonus. When Zoltar's fork threshold at settlement is below the game's non-decision threshold, the whole withdrawal is scaled by their ratio. If this game's non-decision threshold were 20 REP and the fork threshold 16 REP , the 7 REP payout becomes 7 × 16 / 20 = 5.6 REP , rounded down to attoREP. Fork scaling can therefore reduce the final transfer below principal.","title":"EscalationGame","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["liquidation","approval","receiver","operator"],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Stores coordinator-local, bounded authorization for a receiver vault to accept liquidation debt from an exact operator. LiquidationApprovalRegistry source contract","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Use coordinator to identify the validating coordinator and implied security pool. LIQUIDATION_APPROVAL_TYPEHASH , DOMAIN_SEPARATOR , and liquidationApprovalDigest define the chain- and registry-bound EIP-712 message. getLiquidationApproval reports parameters plus available, reserved, consumed, and revoked state; minimumLiquidationApprovalNonce reports receiver invalidation state; liquidationReservations and minimumHealthFactorBps expose operation reservation state and its execution-time health floor.","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals initialize(coordinator) Anyone while the registry remains uninitialized; normal factory deployment initializes the clone atomically Coordinator is nonzero and the registry has not been initialized. Binds this registry clone to one coordinator and therefore one security pool. RegistryInitialized identifies the configured coordinator. setLiquidationApproval(params) The receiver vault named by params Correct local pool; nonzero receiver and operator; positive cumulative and per-operation limits with per-operation no greater than cumulative; health factor at least 10,000 BPS; live ordered validity window; unused, non-invalidated nonce. Installs explicit onchain bounded approval state and consumes the receiver-scoped nonce. LiquidationApprovalSet permitLiquidationApproval(params, signature) Anyone relaying the receiver vault signature Signature is valid for params.receiverVault ; the chain ID, registry address, stable name/version, pool, receiver, operator, target scope, limits, health factor, window, and nonce are bound by the digest; direct-install validation rules also pass. Validates an EIP-712 EOA or ERC-1271 signature immediately, installs explicit approval state, and consumes the receiver-scoped nonce. LiquidationApprovalSet revokeLiquidationApproval(approvalId) Approval receiver vault only Approval exists and is not already revoked. Prevents new reservations while leaving reservations already attached to staged operations intact. LiquidationApprovalRevoked with available, reserved, and consumed totals invalidateLiquidationApprovalNonce(newNonce) Receiver vault invalidating its own older nonce range New nonce is greater than the receiver current minimum. Raises the minimum nonce accepted for new approval installation or reservation. LiquidationApprovalNonceInvalidated reserve(operationId, approvalId, receiverVault, targetVault, operator, requestedDebtAttoEth, snapshotTargetDebtAttoEth, latestExecutionTimestamp) Bound coordinator only ( Only coordinator ) Approval matches local pool, receiver, exact operator, and exact or wildcard target; it is active, unrevoked, non-invalidated, valid through latest execution, and has positive reservable quota. Moves quota from available to pending reserved at staging, bounded by requested debt, target snapshot debt, per-operation limit, and available cumulative quota. LiquidationApprovalReserved release(operationId) Bound coordinator only ( Only coordinator ) Coordinator terminal cleanup path. Returns an unsettled delegated reservation to available quota. A missing, self-route, or already settled reservation is a no-op. LiquidationApprovalReleased when quota is returned consume(operationId, debtMovedAttoEth) Bound coordinator only ( Only coordinator ) For a delegated reservation, it is unsettled and moved debt does not exceed reserved debt. A self route is a no-op. Permanently consumes exactly moved debt, releases unused reservation, and settles the reservation once. LiquidationApprovalConsumed","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"minimum-post-liquidation-health-factor","heading":"Minimum post-liquidation health factor","keywords":[],"path":"reference/contracts/liquidationapprovalregistry.html","sectionTitle":"Reference","summary":"Read surface and the approval, permit, revoke, reserve, release, and consume entrypoints.","text":"minPostLiquidationHealthFactorBps is applied to both vault-health branches at execution. 10,000 ( BPS_DENOMINATOR ) means exactly the protocol minimum; a larger value multiplies both REP requirements by that ratio, so 12,000 requires 1.2 times each requirement, rounded up, after the receiver accepts the position. The factor is checked against live post-liquidation state, not the queue-time preview.","title":"LiquidationApprovalRegistry","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","price","coordinator","staged operation"],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Obtains a fresh REP-per-ETH price and coordinates withdrawals, delegated liquidation routing, approval reservations, and terminal cleanup. OpenOraclePriceCoordinator source contract","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Configuration getters are MAX_PENDING_SETTLEMENT_OPERATIONS , SETTLEMENT_GAS_OVERHEAD , OPEN_INTEREST_DIVIDER , reputationToken , securityPool , openOracle , weth , liquidationApprovalRegistry , vaultOperations (the VaultOperations executor this coordinator deploys in its constructor), gasConsumedOpenOracleReportPrice , gasConsumedSettlement , gasUnitsForOneDispute , initialReportPriorityFeeAttoEthPerGas , targetPriceErrorForDispute , openOracleSecurityMultiplierBps , settlementTime , disputeDelay , protocolFee , feePercentage , multiplier , timeType , trackDisputes , protocolFeeRecipient , escalationHaltMultiplierBps , maxSettlementBaseFeeMultiplierBps , and minLiquidationPriceDistanceBps . Current report and operation getters are pendingReportId , pendingReportSponsor , pendingOperationSlotId , lastSettlementTimestamp , lastPrice , pendingReportMaxSettlementBaseFeeAttoEthPerGas , stagedOperationCounter , and stagedOperations . lastSettlementTimestamp records when the accepted final report reached settlement eligibility (report timestamp plus settlementTime ), not when settle was called, and isPriceValid measures freshness from it: it is true while lastPrice > 0 , lastSettlementTimestamp is nonzero, and lastSettlementTimestamp + 5 minutes > block.timestamp . On chain ID 11155111 (Sepolia) the window is 1 hour instead of 5 minutes. Use isPriceValid , minimumToken1ReportAttoEth , getRequestPriceCostAttoEth , getQueuedOperationCostAttoEth , getSettlementCallbackGasLimit , getPendingOperationSlot , getActiveStagedOperationCount , getActiveStagedOperations , getPendingSettlementWork , getPendingSettlementOperationCount , and getPendingSettlementOperationIds for derived or paged state.","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"security-assumptions","heading":"Security assumptions","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Report and staged-operation liveness depends on A16 timely inclusion , A17 corrector capability , A18 independent correction incentive , A19 observable correctable price , and A06 lifecycle executors . When lastPrice is zero, the official client currently needs an offchain market quote to propose the first report; quote availability is a client limitation rather than a protocol security assumption. Proposals copied from a nonzero cached price do not use that quote path.","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/openoraclepricecoordinator.html","sectionTitle":"Reference","summary":"Read surface and the price request, staged operation, recovery, and openOracleCallback entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals requestPriceIfNeededAndStageLiquidation(targetVault, receiverVault, requestedDebtAttoEth, approvalId, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) Liquidation operator; a delegated receiver must have approved this exact operator Receiver differs from target; delegated approval matches pool, receiver, operator, and target scope, has available cumulative and per-operation quota, and remains valid through latest execution. Stages explicit operator, receiver, target backing, and target underwriting commitment and reserves bounded receiver quota before any oracle work. The queue event retains the full historical observation for indexing, while live execution inputs are not duplicated in persistent operation storage. The self-receiving operator path uses a zero approval ID. LiquidationRouteStaged ; LiquidationApprovalReserved on a delegated route; staged-operation lifecycle events requestPriceIfNeededAndStageOperation(operation, targetVault, operationValue, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with funding when stale Vault owner for self withdrawal or a target change; self-receiving liquidation callers are also supported. While a report is pending, only that report sponsor may stage more operations. securityPool.isEscalationResolved() is false; valid self-target for withdrawal or underwriting-commitment change; liquidation and withdrawal require positive amounts, and a withdrawal whose previewed REP is zero reverts with Withdraw amount has no effect , while an absolute underwriting commitment may be zero to request an exit; and validForSeconds is from 1 second through 5 minutes. A committed bounty of at least getRequestPriceCostAttoEth() covered by msg.value , buffered report funding, matching REP, and token approvals are required only when this call opens a new report. The caller must accept any positive unused-ETH refund. Records the operation with operationValue in the unit of its OperationType ( 0 Liquidation , transferred commitment in attoETH; 1 WithdrawRep , withdrawal in attoREP; 2 SetVaultUnderwritingLimit , absolute underwriting commitment in attoETH), executes immediately with a fresh price; otherwise it attaches it to the pending settlement batch while that batch has room, opening a report when none is pending and the batch was empty, or leaves it active outside the batch for a later executeStagedOperation . A target change cannot supersede an active dependent bundle. Otherwise, a newly accepted target change consumes any older active target change for the same vault with success=false and Backing target superseded , freeing its settlement slot. When a report opens, the whole committed bountyAttoEth is retained as the settler reward regardless of the inclusion-block cost. If unused ETH is positive, the final caller refund uses a low-level callback; rejection rolls back the entire transaction, including any queueing, immediate execution, or newly opened report. StagedOperationQueued ; PriceRequested when this call opens a report; ExecutedStagedOperation for immediate fresh-price execution or a superseded target change; LiquidationRouteStaged for operation 0 ; authoritative CoordinatorStateCheckpoint records stageVaultOperations(owner, changeCommitment, actionCount, validForSeconds, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) The VaultOperations executor only ( Only vault operations executor ); wallets enter through its submitVaultOperations function validForSeconds is from 1 second through 5 minutes; escalation is unresolved; a pending report belongs to the owner; a commitment change has no active preceding commitment operation. Stale-price bundles must fit the remaining weighted callback capacity and satisfy report funding when opening a report. Targets are distinct, nonzero other vaults with a positive commitment; liquidation bundles require a receiver health factor of at least 10,000 BPS. All liquidation snapshots and pool safety checks must still pass at execution, and a withdrawal whose resulting REP is zero fails with Withdraw amount has no effect . Records OperationType 3 ( VaultOperations ) with the submitting wallet as owner and report sponsor. A fresh-price bundle executes commitment changes, other-vault liquidations, and withdrawal atomically; a failure reverts the submission and its deposit. With a stale price, deposits complete immediately and dependent actions queue together. Any change to a queued liquidation target's backing units or underwriting commitment fails the whole bundle, rolling back the owner's commitment change and withdrawal. The failed bundle is consumed while its earlier deposit remains. Each action uses one of four settlement slots; the deposit uses none. StagedOperationQueued , PriceRequested when opening a report, ExecutedStagedOperation , and CoordinatorStateCheckpoint ; the executor emits VaultLiquidationStaged per target and VaultOperationsStaged before this call requestPrice(proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with report funding Anyone when no fresh price or report is pending Cached price stale; no pending report; nonzero proposed REP-per-ETH price, a committed bounty of at least getRequestPriceCostAttoEth() covered by msg.value , and funding and approvals for at least the configured priority report plus the larger of the base-fee and open-interest WETH reports, plus matching REP. Zero requested WETH uses the minimum; a larger request voluntarily increases the initial report. The caller must accept any positive excess-ETH refund. Opens and atomically funds a fresh WETH/REP report without staging a new operation, retains the whole committed bounty as the settler reward, then refunds any ETH above the bounty through a low-level caller callback. Callback rejection rolls back the report and initial position. PriceRequested and CoordinatorStateCheckpoint executeStagedOperation(operationId) Anyone Operation exists ( Staged operation unavailable ). Expired cleanup requires no valid price; a non-expired operation requires a fresh coordinator price ( Valid oracle price required ). Lifecycle failures are emitted rather than retried. Consumes an expired operation and releases its delegated reservation without requiring a valid price. Otherwise, consumes and attempts the active operation using the current fresh price. Price-report funding is independent of the operation's notional; the downstream operation applies its own protocol bounds. ExecutedStagedOperation , either LiquidationApprovalConsumed or LiquidationApprovalReleased for a delegated liquidation, and CoordinatorStateCheckpoint expireStagedOperation(operationId) Anyone Operation exists ( Staged operation unavailable ) and block.timestamp is after queuedAt + settlementTime + validForSeconds ( Staged operation active ). Permissionlessly consumes an expired operation and releases its liquidation reservation without requiring a valid oracle price. ExecutedStagedOperation , LiquidationApprovalReleased for a delegated liquidation, and CoordinatorStateCheckpoint recoverSettledPendingReport() Anyone A pending report ID exists and its stored OpenOracle storedGame(reportId).settlementTimestamp is nonzero. Clears a pending report whose normal callback path did not clear coordinator state, consumes every live operation attached to that report, and releases each delegated-liquidation reservation. Operations that were active but outside the bounded pending callback batch remain active. PendingReportRecovered , failed ExecutedStagedOperation for each live attached operation, LiquidationApprovalReleased for each attached delegated liquidation, and CoordinatorStateCheckpoint openOracleCallback(reportId, amount1, amount2, uint256, address, address) ; the last three parameters are unnamed and ignored Configured OpenOracle only ( Only OpenOracle ) Callback report matches the pending report; excessive settlement basefee, a saturated uint24 report counter, an uneconomic final history record at its recorded base fee plus configured priority fee, a stale report, or zero values reject the price after clearing pending report state. A valid settlement updates the price and auto-executes the bounded pending batch. A terminally rejected settlement consumes the pending batch and releases every liquidation reservation. PriceReported or PriceReportRejected ; operation execution events; authoritative CoordinatorStateCheckpoint records setLiquidationApprovalRegistry(registry) The PriceCoordinatorDeploymentWorker that deployed the coordinator only, invoked by OpenOraclePriceCoordinatorFactory during deployment Registry is nonzero and no registry was previously installed ( Registry setup invalid for any failed condition, including the caller). Binds the coordinator-local approval registry once. LiquidationApprovalRegistrySet identifies the configured registry. setSecurityPool(securityPool) Anyone while securityPool remains zero; normal factory deployment calls atomically Current securityPool is zero ( Security pool already set ); the argument itself is not required to be nonzero. A nonzero value binds the pool permanently. A zero value emits and checkpoints zero but leaves the setter callable. SecurityPoolFactory supplies the nonzero canonical pool in the same deployment transaction, immediately after deploying the pool. SecurityPoolSet and CoordinatorStateCheckpoint setRepEthPrice(lastPrice) Configured nonzero SecurityPool only ( Only pool ) Caller equals the configured pool. Seeds the coordinator's price value, including zero, for inherited child state. RepEthPriceSet and CoordinatorStateCheckpoint","title":"OpenOraclePriceCoordinator","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["vault","bundle","executor","submitVaultOperations"],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Accepts a wallet bundle of vault actions for one security pool, stores the price-dependent actions, and is the only caller that pool accepts for executor-gated vault entrypoints. VaultOperations source contract","title":"VaultOperations","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Use MAX_ACTIONS (4) for the limit on price-dependent actions in one bundle. getBundle(operationId) returns a stored bundle: owner , changeCommitment , commitmentAttoEth , withdrawAttoRep , minimumReceiverHealthFactorBps , and each liquidation targetVault and requestedDebtAttoEth with its queue-time targetBackingUnits and targetUnderwritingLimitAttoEth snapshot. previewWithdrawRep(pool, vault, amountAttoRep) returns the REP a withdrawal would send: zero for a zero request, otherwise the requested backing or the whole vault backing when the remainder would fall below minimumVaultRepDepositAttoRep . The coordinator address is a private immutable set to the deployer; each OpenOraclePriceCoordinator deploys one instance in its constructor and exposes it as vaultOperations .","title":"VaultOperations","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/vaultoperations.html","sectionTitle":"Reference","summary":"Read surface and the submitVaultOperations, execute, executeSingle, and release entrypoints of the vault bundle executor.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. The input of submitVaultOperations contains, in ABI order, depositAttoRep , changeCommitment , commitmentAttoEth , liquidations (each a targetVault and a requestedDebtAttoEth ), withdrawAttoRep , minimumReceiverHealthFactorBps , and validForSeconds . Transaction Caller Main prerequisites State or asset effect Primary signals submitVaultOperations(input, proposedRepPerEthPrice, requestedInitialAttoWeth, bountyAttoEth) with ETH Vault owner; the caller becomes the bundle owner No submission is already in progress ( Vault submission already active ). The bundle contains a deposit or a price-dependent action ( Choose a vault action ); a commitment change, each liquidation, and a positive withdrawal are price-dependent actions, at most four in total ( Choose one to four price actions ). With liquidations, minimumReceiverHealthFactorBps is at least 10,000 BPS ( Receiver health factor below one ); each target is nonzero and differs from the caller ( Choose another vault ), requests a positive amount ( Liquidation amount zero ), is listed once ( Duplicate liquidation target ), and has positive backing units and underwriting commitment ( Target vault has no commitment ). A deposit requires the pool depositRepToVaultFromExecutor prerequisites; price-dependent actions require the coordinator stageVaultOperations prerequisites; a deposit-only caller accepts the ETH refund ( Vault operation refund failed ). Deposits a positive depositAttoRep immediately through the pool depositRepToVaultFromExecutor . When price-dependent actions exist, stores the bundle under the next coordinator operation ID with a snapshot of each target's backing units and underwriting commitment, then forwards msg.value and the three price arguments to the coordinator stageVaultOperations , which executes the bundle at a fresh price or queues it. A deposit-only call returns operation ID zero and refunds msg.value to the caller. The pool depositRepToVault signals for a positive deposit; VaultLiquidationStaged per liquidation, then VaultOperationsStaged , when price-dependent actions exist; then the coordinator stageVaultOperations signals. A deposit-only call emits only the deposit signals execute(operationId) Bound coordinator only ( Only coordinator ) A bundle is stored for operationId ( Bundle unavailable ); a positive withdrawal previews to a positive amount ( Withdraw amount has no effect ); each pool call meets its own prerequisites. Runs the stored bundle in order: sets the owner's underwriting commitment through the pool setVaultUnderwritingLimit when the bundle changes it; performs each liquidation through the pool performLiquidation with the owner as operator and receiver and the stored target snapshot; then withdraws through the pool withdrawRepFromVault . A failed step reverts the whole call. The bundle stays stored until release . The signals of each pool call it makes; no event of its own executeSingle(operationId, operation) Bound coordinator only ( Only coordinator ) The operation type is Liquidation , WithdrawRep , SetVaultUnderwritingLimit , or VaultOperations ( Unsupported single operation ); the pool call meets its own prerequisites. Dispatches one staged coordinator operation by its OperationType . VaultOperations runs execute(operationId) and returns zero. Liquidation calls the pool performLiquidation and returns the moved commitment: a self route uses operationValue and a 10,000 BPS minimum receiver health factor, while a delegated route uses the reserved debt and the approval registry minimumHealthFactorBps(operationId) . WithdrawRep calls the pool withdrawRepFromVault and SetVaultUnderwritingLimit calls the pool setVaultUnderwritingLimit , each for the operator with operationValue . The signals of the pool call it makes; no event of its own release(operationId) Bound coordinator only ( Only coordinator ) No prerequisite beyond the caller. Deletes the stored bundle for operationId . Releasing an ID without a bundle changes nothing. No event","title":"VaultOperations","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["shares","ERC-1155","migrate","outcome"],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Stores universe-aware ERC-1155 outcome shares and materializes a holder's persistent source entitlement in selected fork branches. ShareToken source contract","title":"ShareToken","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Base and relationship getters are name , symbol , zoltar , canonicalPoolByUniverse , _balances , _supplies , and _operatorApprovals . Standard ERC-1155 reads are supportsInterface , balanceOf , totalSupply , balanceOfBatch , and isApprovedForAll ; protocol-specific reads are isAuthorized , totalSupplyForOutcome , maximumOutcomeSupply , balanceOfOutcome , balanceOfShares , getMigratedShareAmountAttoShares , getTokenId , getTokenIds , and unpackTokenId .","title":"ShareToken","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/sharetoken.html","sectionTitle":"Reference","summary":"Read surface and the ERC-1155 transfer, migrate, authorize, and complete-set entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals setApprovalForAll(operator, approved) Any token account setting its own operator approval The operator differs from the caller. Sets or clears the operator's authority over all of the caller's outcome-token balances. ApprovalForAll safeTransferFrom(from, to, id, value) and safeTransferFrom(from, to, id, value, data) Share holder or approved ERC-1155 operator Caller holds the source balance or has operator approval; the source account has not materialized that token into any child branch; destination is nonzero; the source balance is sufficient; under A22 asset-recipient compatibility , a contract recipient accepts the ERC-1155 callback. Transfers one outcome-token balance without changing supply. TransferSingle safeBatchTransferFrom(from, to, ids, values) and safeBatchTransferFrom(from, to, ids, values, data) Share holder or approved ERC-1155 operator for a nonempty batch; any caller for an empty batch ID and value array lengths match. A nonempty batch also requires holder or operator authority, no listed source token that the source account has already materialized into a child branch, a nonzero destination, sufficient source balances, and, under A22 asset-recipient compatibility , an accepting ERC-1155 callback from a contract recipient; the empty-batch no-op performs none of those checks. A nonempty batch transfers each listed outcome-token balance without changing supply. Equal empty ID and value arrays return as a no-op without an event. TransferBatch for a nonempty batch; no event for an empty batch migrate(fromId, targetOutcomeIndexes) Holder of the source token ID Source universe forked; canonical source pool is Operational or PoolForked , and an Operational source has no inherited fixed outcome because auto-fork activation rejects one; positive source balance; nonempty, strictly increasing, well-formed outcomes; every target in a multi-target call already has a canonical child pool; after the branch-creation window, a single target must also already exist; at least one selected child has an unmaterialized balance; under A22 asset-recipient compatibility , a contract holder accepts onERC1155Received for every target mint. If needed, first freezes the operational source pool and records its fork snapshot. A single-target call may lazily create that child while the branch-creation window is open. It keeps and locks the holder's source entitlement, then mints each selected child-universe token ID up to the current source balance. Later source additions materialize only the unminted delta. A contract holder receives the ERC-1155 single-receiver callback for each mint; rejection rolls back the mint and preceding fork or child setup. PoolForkModeActivated , PoolAccountingCheckpoint , SecurityPoolForkSnapshot , ParentRepLocked , and optionally DisputeStakedRepDrainedAtFork when auto-forking; SecurityPoolRegistered , DeploySecurityPool , AuthorizationUpdated , and ChildPoolLinked when lazily deploying, plus DeployChild , ChildRepSplit , PoolHeldRepSweptToChild , EscalationGameSet , GameContinuedFromFork , ForkCarryCheckpoint , and ChildDisputeStakedRepMaterialized as applicable; then one ERC-1155 mint TransferSingle and Migrate per materialized target on successful callbacks authorize(securityPoolCandidate) Initially authorized SecurityPoolFactory for an origin pool; an authorized parent SecurityPool for a child pool Caller is already authorized; the candidate reports this exact share token; its universe has no different canonical pool. Establishes the candidate as canonicalPoolByUniverse for its universe and adds it to the set allowed to mint, burn, and authorize descendants. Reauthorizing the same candidate is a no-op. AuthorizationUpdated on first authorization; no event when the same candidate is already authorized mintCompleteSets(universeId, account, amountAttoShares) An authorized SecurityPool Caller is authorized; account is nonzero; amountAttoShares is positive; under A22 asset-recipient compatibility , a contract account accepts onERC1155BatchReceived . Mints amountAttoShares each of Invalid, Yes, and No to account , then invokes its ERC-1155 batch-receiver callback when it is a contract. Rejection rolls back the mint and the authorized pool's surrounding transaction. TransferBatch on a successful callback burnCompleteSets(universeId, owner, amountAttoShares) An authorized SecurityPool Caller is authorized; owner is nonzero and has at least amountAttoShares of every outcome. Burns amountAttoShares each of Invalid, Yes, and No from owner ; global outcome supplies may differ. TransferBatch burnTokenIdAndGetRemainingSupply(tokenId, owner) An authorized SecurityPool owner is nonzero; caller is authorized. Burns owner 's full balance of tokenId and returns the burned amount and that token ID's remaining supply. TransferSingle , including when the burned balance is zero","title":"ShareToken","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["truth auction","bids","clearing","settlement"],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Collects ETH bids under ETH-raise and REP-sale caps, computes one clearing result, and supports paged settlement. AVL, cumulative-allocation, and refund-prefix mechanics live in UniformPriceDualCapBatchAuctionStorage , an internal storage library. UniformPriceDualCapBatchAuction source contract","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":1},{"fragment":"read-surface","heading":"Read surface","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Auction summary getters are maxAttoRepBeingSold , attoEthRaiseCap , finalized , clearingTick , ethFilledAtClearingAttoEth , attoEthRaised , totalAttoRepPurchased , auctionStarted , minBidSizeAttoEth , owner , underfunded , underfundedThreshold , underfundedWinningAttoEth , and activeTickCount . pendingEthRefundsAttoEth reports ETH credited during settlement and available for the bidder to pull. Use computeClearing , previewFinalization , tickToPrice , getTickSummary , getTickCount , getTickPage , getActiveTickPage , getBidCountAtTick , getBidPageAtTick , getBidderBidCount , and getBidderBidPage before finalizing or submitting settlement indexes.","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"interactions","heading":"State-changing interactions","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Each call lists its parameter names in ABI order. The contract index defines the columns. Transaction Caller Main prerequisites State or asset effect Primary signals startAuction(attoEthRaiseCap, maxAttoRepBeingSold) Auction owner ( SecurityPoolForker ) only Auction not previously started; both caps are positive; the REP cap does not exceed 11 million REP; the ETH cap fits in uint128 ; the block timestamp fits in uint48 . Starts the one-week auction and fixes its two caps and minimum bid. AuctionStarted submitBid(tick) with ETH Any bidder Auction active and unfinalized; before one-week deadline; bid meets minBidSizeAttoEth ; tick maps to nonzero price; the individual bid and the resulting cumulative ETH at that tick each fit in uint128 . Adds ETH demand at the selected positive-price tick while extending that tick's append-only cumulative bid and refund history, including when a fully refunded tick becomes active again. BidSubmitted refundLosingBids(tickIndices) Bidder for its own bids Auction started and unfinalized; auction has reached a clearing price. Nonempty indexes additionally belong to the caller and are strictly losing and unrefunded. A nonempty list marks the caller's bids already provably below the current clearing tick and credits their ETH to pendingEthRefundsAttoEth without calling the bidder. An empty list changes no bids. BidSettled per refunded bid; one aggregate EthRefundCredited per call when total credited ETH is positive refundLosingBidsFor(bidder, tickIndices) Auction owner ( SecurityPoolForker ) only; public callers use settleAuctionBids bidder is nonzero; the refundLosingBids prerequisites, with the indexes belonging to bidder . Performs the refundLosingBids refund for the bids of bidder instead of the caller. The refundLosingBids signals finalize() Auction owner ( SecurityPoolForker ) only; users reach it through finalizeTruthAuction Auction started, not finalized, and one-week deadline reached; owner accepts the proceeds ETH call, including zero value. Fixes the clearing mode, clearing tick, ETH totals, and aggregate REP allocation, then calls the owner with the resulting proceeds, including when zero. A rejected call reverts finalization and its event. AuctionFinalized withdrawBids(withdrawFor, tickIndices, proRataTotal, secondaryProRataTotal, repBackingUnitsTotal) Auction owner ( SecurityPoolForker ) only; public callers use claimAuctionProceeds or settleAuctionBids Auction finalized; caller is owner. Nonempty indexes belong to withdrawFor and remain unsettled. Returns five uint256 values in ABI order: totalFilledAttoRep (filled REP), totalRefundAttoEth (ETH refund), totalProRataAllocation (underwriting commitment), totalSecondaryProRataAllocation (bad debt), and totalRepBackingUnitsAllocation (REP backing units). The forker credits backing and underwriting commitment to the bidder vault and credits bad debt only while the recorded auction debt generation is current; the auction credits refunds to the beneficiary pull-payment balance without calling recipient code. Underwriting commitment and bad debt use fixed cumulative ETH positions. Backing units use the corresponding cumulative filled-REP positions to exhaust repBackingUnitsTotal without claim-order dependence. An empty list returns five zeros without changing bids or emitting events. BidSettled per processed bid; one EthRefundCredited for the call when aggregate totalRefundAttoEth is positive withdrawPendingEthRefund() Bidder with credited ETH Caller has a positive pendingEthRefundsAttoEth balance and currently accepts ETH. Clears the caller's complete credited refund and emits its withdrawal before transferring. A rejected pull reverts the transfer, clear, and event, preserving the credit. Checks-effects-interactions makes callback reentry observe a zero balance. PendingEthRefundWithdrawn","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"accounting-examples","heading":"Accounting examples","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"tick-pricing","heading":"Tick pricing","keywords":[],"path":"reference/contracts/uniformpricedualcapbatchauction.html","sectionTitle":"Reference","summary":"Read surface and the startAuction, submitBid, refund, finalize, and withdrawal entrypoints.","text":"Bids are placed at integer ticks between MIN_TICK ( -524288 ) and MAX_TICK ( 524288 ). tickToPrice(0) is PRICE_PRECISION , one ETH per REP. Each tick above zero multiplies the price by 1.0001 through a binary-exponentiation table of _powerOf1Point0001 ; negative ticks take the reciprocal. The price at tick t is therefore approximately: price ( t ) ≈ 1.0001 t ETH per REP A tick whose price rounds to zero is rejected. Within one tick, the uniform-clearing branch fills bids first in, first out, so earlier same-tick bids are consumed before later ones.","title":"UniformPriceDualCapBatchAuction","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["invariants","safety","liveness","properties"],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"An invariant is a statement that must remain true at every successful external-call boundary, across every legal lifecycle transition, or under the economic assumptions named beside it. Reverts may interrupt a transition, but they must roll back all of its state and asset effects. The catalog separates local contract guards, automated release-tooling guards, cross-contract properties, and economic assumptions. Each entry names the strongest enforcement and evidence currently present; a documented implementation choice is not automatically a safe invariant. See the Statoblast security model for assumptions A01–A28. Funded and underfunded clearing are explained in the Truth Auction clearing guide . Four connected layers run from local authority guards through cross-contract conservation and lifecycle liveness to economic security. A failure in an earlier layer invalidates the safety claims built above it. Invariant Dependency Correct callers are necessary but insufficient. Their actions must conserve assets, every mandatory state transition must remain reachable, and the named participation and inclusion assumptions must hold where the protocol deliberately relies on economic incentives. Matches All invariants listed below Filter invariants Type Any type Enforcement status Any status Subsystem Any subsystem Expand visible Collapse all Reset filters No invariants match the selected filters.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":1},{"fragment":"standing","heading":"Classification and scope","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Each entry separates the kind of property from its current enforcement status. A status describes the strongest claim supported by the local implementation and tests; it is not a formal proof. Type Meaning Safety A forbidden caller, state, transition, or replay cannot succeed. Conservation Assets, liabilities, supplies, and claims reconcile without duplication or loss. Liveness A required permissionless action remains executable under the stated conditions. Enforcement status Meaning Contract guard A direct authorization, bound, or state check enforces the property locally. Reviewed preservation Several contracts cooperate to preserve the property in reviewed flows and tests. External assumption Solidity cannot guarantee the property without honest participation, liquidity, transaction inclusion, or external token behavior. Automated tooling guard Release, deployment, or CI tooling rejects a mismatched artifact, address, or runtime-code identity before it is accepted. Invariant identifiers are stable review labels. The prefix names the boundary rather than a Solidity file: UNI universes, QST questions, AUTH authority, BAL pool balances, SHARE shares, VAULT vaults, FORK forks, ESC escalation, ORA the oracle, AUC auctions, LIFE lifecycle, OBS observability, and EXT external tokens, callbacks, block ordering, and lineage lookups. The index and the explorer's subsystem filter group entries by the nine page sections: BAL , SHARE , and VAULT share one section, as do LIFE , OBS , and EXT .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"standing","heading":"Terms used in the catalog","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Pool question The question whose outcome determines the SecurityPool 's winning outcome shares and Escalation Game payouts. Fork question The ended question recorded by the universe fork. It may differ from the pool question. Child branch A well-formed answer encoding for the fork question, used to derive one child universe from its parent. SecurityPool's binary pool-question paths specifically use Invalid, Yes, and No. Continuation game A child Escalation Game initialized from an unresolved parent game's fork snapshot. Its child pool is in fork continuation until the game is fully resumed; the game itself remains the continuation game afterward. Carry The unresolved parent escalation deposits exported into a fork snapshot and paid out by continuation games against Merkle Mountain Range proofs . Nullifier A continuation game's record that one carried deposit identity has been consumed, so its proof cannot be replayed. Fixed payout outcome The pool-question outcome a continuation game must use after its deadline, regardless of its copied balance leader. Direct fork A caller invokes Zoltar's universe-fork entrypoint directly rather than through a pool's own non-decision path. Recursive fork A fork of a child universe created by an earlier fork. Tracked balance An amount recorded by protocol accounting; it excludes unsolicited assets unless a named transition explicitly credits them. Consumed claim A deposit, bid, or proof that has already been settled, refunded, exported, or otherwise made unusable.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Invariant index","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Each identifier links to its full statement.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Universes, REP supply, and migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status UNI-01 One fork per universe Safety Contract guard UNI-02 Valid fork questions Safety Contract guard UNI-03 Fork threshold burn and credit Conservation Contract guard UNI-04 Deterministic child universe IDs Safety Contract guard UNI-05 Well-formed child outcomes Safety Contract guard UNI-06 Per-child migration mint limit Safety Contract guard UNI-07 Branch-specific child REP Conservation Reviewed preservation UNI-08 Child theoretical supply snapshot Conservation Reviewed preservation UNI-09 Child REP supply coherence Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Questions and answer classification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status QST-01 Question registry and classifier coherence Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Authority and deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status AUTH-01 Coordinator and forker-only operations Safety Contract guard AUTH-02 Atomic pool and coordinator binding Safety Reviewed preservation AUTH-03 Immutable protocol logic Safety Reviewed preservation AUTH-04 Deterministic deployment identity Safety Reviewed preservation AUTH-05 Delegate storage compatibility Safety Reviewed preservation AUTH-06 Permissionless settlement beneficiaries Safety Contract guard AUTH-07 Published deployment verification Safety Automated tooling guard AUTH-08 Factory registry and lineage bijection Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Pool assets, shares, and vaults","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status BAL-01 ETH conservation Conservation Reviewed preservation BAL-02 Unsolicited ETH isolation Conservation Reviewed preservation BAL-03 Collateral capacity and backing Conservation Reviewed preservation BAL-04 REP coverage boundaries Safety Contract guard BAL-05 REP backing units conversion consistency Conservation Reviewed preservation BAL-06 Fee liability accounting Conservation Reviewed preservation BAL-07 Fee reserve protection Conservation Contract guard BAL-08 Aggregate pool-ledger coherence Conservation Reviewed preservation SHARE-01 Complete-set symmetry Conservation Contract guard SHARE-02 Complete-set redemption Conservation Reviewed preservation SHARE-03 Positive-output minting Safety Contract guard SHARE-04 Child supply denominators Conservation Reviewed preservation SHARE-05 Winning-share payout cap Conservation Contract guard SHARE-06 Share supply conservation Conservation Reviewed preservation VAULT-01 Dispute-staked REP isolation Conservation Reviewed preservation VAULT-02 Liquidation conservation and freshness Conservation Reviewed preservation VAULT-03 Vault registry coherence Safety Reviewed preservation VAULT-04 Escalation claims are non-transferable and migration-neutral Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Forks and child isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status FORK-01 Parent pool finality Safety Contract guard FORK-02 Immutable fork snapshot Safety Reviewed preservation FORK-03 Isolated migration proxy Safety Reviewed preservation FORK-04 Prefunded proxy isolation Liveness Reviewed preservation FORK-05 Eight-week migration boundary Safety Reviewed preservation FORK-06 Child deployment identity Safety Reviewed preservation FORK-07 Single-use non-escrowed vault migration Conservation Reviewed preservation FORK-08 One-time aggregate continuation backing Conservation Contract guard FORK-09 Cumulative child collateral Conservation Contract guard FORK-10 Share migration integrity Conservation Contract guard FORK-11 Unequal child share supplies Conservation Reviewed preservation FORK-12 Child activation after settlement Safety Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Escalation Games and carried claims","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status ESC-01 Total escrow reconciliation Conservation Reviewed preservation ESC-02 Local unresolved REP reconciliation Conservation Reviewed preservation ESC-03 Outcome carry reconciliation Conservation Reviewed preservation ESC-04 Stable deposit identifiers Safety Reviewed preservation ESC-05 Single-use claims per branch Safety Reviewed preservation ESC-06 Aggregate export accounting Conservation Reviewed preservation ESC-07 Authenticated carried winner payout Conservation Contract guard ESC-08 Game REP settlement conservation Conservation Reviewed preservation ESC-09 Terminal game outcomes Safety Contract guard ESC-10 Ancestor claim replay protection Safety Reviewed preservation ESC-11 Residual sweep preconditions Conservation Contract guard ESC-12 Pool and continuation payout agreement Safety Reviewed preservation ESC-13 Non-decision threshold and live start-bond arithmetic Safety Contract guard ESC-14 Carry commitment structural integrity Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status ORA-01 Authorized settlement callbacks Safety Contract guard ORA-02 REP-per-ETH price direction Safety Contract guard ORA-03 Oracle price validity Safety Contract guard ORA-04 Single-use staged operations Safety Contract guard ORA-05 Staged operation targets Safety Contract guard ORA-06 Consumed execution failures Liveness Contract guard ORA-07 Staged-operation queue and index bijection Safety Reviewed preservation ORA-08 Dispute and settlement boundary Safety Contract guard ORA-09 Oracle balance-domain boundary Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Truth Auctions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status AUC-01 Bid admission Safety Contract guard AUC-02 Auction caps Conservation Contract guard AUC-03 Single-use bid settlement Safety Contract guard AUC-04 Claim-order independence Conservation Reviewed preservation AUC-05 Allocation and refund reconciliation Conservation Reviewed preservation AUC-06 Bidder-vault credits Conservation Reviewed preservation AUC-07 Uniform weak-demand allocation Conservation Reviewed preservation AUC-08 Forced-ETH-resistant finalization Liveness Reviewed preservation AUC-09 Value-free finalization liveness Liveness Contract guard AUC-10 Persistent tick bid history Conservation Reviewed preservation AUC-11 Auction tree and public-model equivalence Safety Reviewed preservation AUC-12 Auction ETH liability conservation Conservation Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"invariant-index","heading":"Lifecycle, liveness, observability, and external calls","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"ID Invariant Type Enforcement status LIFE-01 Pool state transitions Safety Reviewed preservation LIFE-02 Permissionless transition liveness Liveness Reviewed preservation LIFE-03 Atomic failure behavior Safety Reviewed preservation LIFE-04 Deadline equality rules Safety Contract guard LIFE-05 Bounded transition work Liveness Reviewed preservation OBS-01 Event-state replay equivalence Safety Reviewed preservation EXT-01 Genesis token behavior boundary Conservation External assumption EXT-02 Callback-safe accounting Safety Reviewed preservation EXT-03 ERC-1155 callback safety Safety Reviewed preservation EXT-04 Same-block deadline ordering Safety Contract guard EXT-05 Depth-independent lineage lookups Liveness Reviewed preservation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"zoltar-invariants","heading":"Zoltar invariants","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"These properties govern core universe creation, REP supply, universe forks, deterministic child identities, and branch-specific REP migration.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"universes","heading":"Universes, REP supply, and migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-01","heading":"UNI-01 One fork per universe","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An initialized universe records at most one fork time and one fork question. Example: After a universe forks on question 17, a second call attempting to fork it on question 22 reverts. Type Safety Enforcement status Contract guard Primary evidence Zoltar.forkUniverse","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-02","heading":"UNI-02 Valid fork questions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property forkUniverse accepts only a question that exists in ZoltarQuestionData and whose end time has been reached ( block.timestamp >= endTime ). A pool may separately require the fork question to equal its pool question. Zoltar intentionally imposes no question-creation age, universe registration, or pool-relevance condition. Example: At exactly a known question's end time, a caller may fork a universe even when that question came from another universe or was created with an already-past end time; an unknown or still-open question is rejected. Requiring a universe-relevant or sufficiently aged question is not a Zoltar invariant. Type Safety Enforcement status Contract guard Primary evidence forkUniverse , question model , question-end fork boundary test Related assumption A15 intended question selection","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-03","heading":"UNI-03 Fork threshold burn and credit","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The fork threshold is ⌈parent theoretical supply / forkThresholdDivisor⌉ for nonzero supply, and zero only when supply is zero. Starting a fork burns that amount of the initiator's parent REP, reduces the parent theoretical supply by the same amount, and credits the threshold minus ⌊threshold / forkBurnDivisor⌋ for migration. The configured forkBurnDivisor is at least 5 , so the uncredited fork haircut cannot exceed 20%. Example: With a 1,000 REP theoretical supply, threshold divisor 20, and burn divisor 5, the initiator commits 50 parent REP, pays a 10 REP fork haircut, and receives 40 REP of migration credit. Type Conservation Enforcement status Contract guard Primary evidence getForkThresholdAttoRep and forkUniverse , fork-threshold rounding test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-04","heading":"UNI-04 Deterministic child universe IDs","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A child universe identity is exactly the truncated hash of its parent universe and fork outcome; one parent-outcome pair maps to one child. Example: Repeatedly deriving the Yes child of the same parent returns the same universe ID, while deriving its No child returns a different ID. Type Safety Enforcement status Contract guard Primary evidence getChildUniverseId , deterministic child-ID test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-05","heading":"UNI-05 Well-formed child outcomes","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only well-formed outcomes of the recorded fork question can deploy child universes or receive migrated REP. Example: For a binary categorical fork question whose valid indexes are 0, 1, and 2, passing index 3 cannot deploy a child or receive child REP. Type Safety Enforcement status Contract guard Primary evidence deployChild and _splitRep , malformed-outcome rejection tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-06","heading":"UNI-06 Per-child migration mint limit","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For one migrator and one child, cumulative child REP minted never exceeds that migrator's parent migration balance. Example: A migrator with 40 REP of migration credit cannot mint 25 REP and later mint another 20 REP into the same child. Type Safety Enforcement status Contract guard Primary evidence childMigrationRepAmountsAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-07","heading":"UNI-07 Branch-specific child REP","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property One burned parent migration balance may mint the same credited amount into several selected children. Each minted balance belongs to a different child REP token, and migration never restores the burned parent REP. Example: A 40 REP migration credit may mint 40 Yes-child REP and 40 No-child REP, but neither balance is parent REP and the burned parent balance remains zero. Type Conservation Enforcement status Reviewed preservation Primary evidence _splitRep , ReputationToken","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-08","heading":"UNI-08 Child theoretical supply snapshot","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The child theoretical-supply snapshot equals the parent's theoretical supply after the threshold burn plus the initiator's migration credit net of the fork haircut. Each child therefore excludes the uncredited fork haircut. Example: If a fork removes 50 parent REP and credits 40 migration REP, each child's theoretical snapshot is 10 REP below the pre-fork supply. Type Conservation Enforcement status Reviewed preservation Primary evidence childUniverseTheoreticalSupplySnapshotsAttoRep , common child supply snapshot test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"uni-09","heading":"UNI-09 Child REP supply coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For each child REP token, total minted supply equals the sum of holder balances, never exceeds the child's theoretical-supply snapshot, and uses the same theoretical maximum recorded by the child universe. Example: If two migrators mint 12 and 7 child REP, the child token supply is 19 REP, both balances sum to 19 REP, and minting does not change the child's theoretical maximum. Type Conservation Enforcement status Reviewed preservation Primary evidence splitMigrationRep and child universe accounting , ReputationToken supply , aggregate child-supply invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"questions","heading":"Questions and answer classification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"qst-01","heading":"QST-01 Question registry and classifier coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every successful question creation appends its deterministic ID exactly once and leaves prior question data and labels immutable. For every stored question and answer, the malformed classifier is true exactly when the public answer name is Malformed , except that a categorical question may use the literal label Malformed for a well-formed outcome. Example: Appending a scalar question after two categorical questions preserves the first two records and their order; a scalar answer with reserved bits is both classified and named malformed. Type Safety Enforcement status Reviewed preservation Primary evidence createQuestion , getQuestions , and answer classification , registry and classifier invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"statoblast-invariants","heading":"Statoblast invariants","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"These properties govern Statoblast deployment, SecurityPool accounting, fork migration, escalation, oracle operations, Truth Auctions , and the cross-contract lifecycle built on Zoltar universes.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"authority","heading":"Authority and deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A23 verified deployments and A27 cryptographic security .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-01","heading":"AUTH-01 Coordinator and forker-only operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only the price coordinator 's immutable VaultOperations executor may call the pool's REP withdrawal, liquidation, and executor-side underwriting-commitment entry points, and withdrawRepFromVault and performLiquidation also require a currently valid coordinator price. A vault sets its own commitment directly with setUnderwritingLimit ; an increase requires a currently valid coordinator price. Only the immutable forker may mutate fork accounting or transfer migration assets. Example: A wallet calling withdrawRepFromVault directly is rejected with Unauthorized because it is not the coordinator's VaultOperations executor. Type Safety Enforcement status Contract guard Primary evidence SecurityPool.onlyValidOracle and onlyForker , SecurityPoolOperationsDelegate.setVaultUnderwritingLimit , OpenOraclePriceCoordinator.vaultOperations , VaultOperations , unauthorized-caller rejection tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-02","heading":"AUTH-02 Atomic pool and coordinator binding","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The pool and its coordinator bind once during atomic factory deployment; no external caller gets a transaction boundary in which it can install a substitute pool. Example: A caller cannot front-run factory deployment and make the coordinator point to an attacker-controlled pool. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory , setSecurityPool","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-03","heading":"AUTH-03 Immutable protocol logic","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property No mutable owner, governance address, upgrade implementation, or emergency operator can replace protocol logic after deployment. Example: After deployment, no administrator can point a pool proxy at different bytecode because the pool has no upgrade slot. Type Safety Enforcement status Reviewed preservation Primary evidence Immutable release posture","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-04","heading":"AUTH-04 Deterministic deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every canonical CREATE2 address commits to the correct factory, salt, constructor arguments, parent identity, universe, question, and multiplier. Example: Changing a child's question ID changes its derived address instead of deploying different semantics at the expected address. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory , securityPoolAddressDerivation.ts","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-05","heading":"AUTH-05 Delegate storage compatibility","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Delegatecall targets are constructor-installed protocol modules, and every target interprets the forker's storage with the same layout. Example: The vault-migration delegate reads forkDataByPool from the same slot used by the forker rather than corrupting adjacent state. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPoolForker , forker delegate storage-layout test , Escalation Game storage-layout test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-06","heading":"AUTH-06 Permissionless settlement beneficiaries","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Anyone may trigger permissionless settlement, but the caller cannot choose its beneficiary. Each transfer or REP-backing-unit credit goes only to the vault, bidder, depositor, or share holder recorded for that claim. Example: Alice may settle Bob's auction bid, but the purchased REP remains pool-held while the corresponding REP backing units and underwriting commitment are credited to Bob's vault . Type Safety Enforcement status Contract guard Primary evidence SecurityPool.redeemFees and withdrawForkedEscalationDeposits , UniformPriceDualCapBatchAuction.withdrawBids , contract interaction reference","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-07","heading":"AUTH-07 Published deployment verification","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The release manifest must match the deterministic address calculation, and deployment tooling must reject installed planned contracts or bootstrap descendants whose runtime-code hash differs from the pinned release artifact. Example: Testnet deployment stops instead of treating the price-coordinator factory address as installed when its runtime bytecode differs from the expected hash. Type Safety Enforcement status Automated tooling guard Primary evidence runtime-code verification in the deployment plan , runtime-hash regression tests , deterministic manifest freshness check , mainnet manifest , and Sepolia manifest","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auth-08","heading":"AUTH-08 Factory registry and lineage bijection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every factory deployment record names one unique pool whose runtime parent, share token, universe, and question match the record. Its pool-to-origin reverse lookup and origin/universe forward lookup are mutual inverses, and its recorded share token authorizes that pool. Example: Looking up a child pool's origin and then resolving that origin with the child's universe returns the same child, not a pool from an independent origin lineage in that universe. Type Safety Enforcement status Reviewed preservation Primary evidence factory registry and canonical lookups , share-token authorization , stateful registry-bijection test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"pool-accounting","heading":"Pool assets, shares, and vaults","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the security pool guardrails . The raw ETH balance needs a surplus term. Without it, forced ETH is indistinguishable from collateral and can change an exchange rate or lifecycle precondition. rawEthBalanceAttoEth = settlementCollateralAttoEth + unallocatedAccruedFeesAttoEth + totalClaimableVaultFeesAttoEth + derivedSurplusAttoEth All terms are in attoETH. The first three are stored by the pool; derived surplus is the remainder and has no storage variable. BAL-01 states the invariant.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-01","heading":"BAL-01 ETH conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property At every successful external-call boundary, raw ETH = tracked collateral + unallocated fee reserve + total claimable vault fees + derived surplus . Derived surplus is the remainder; it has no storage variable and is never a protocol liability. Example: If the pool holds 12 ETH, owes 2 ETH in fees, and tracks 9 ETH of collateral, the remaining 1 ETH is surplus rather than additional collateral. Type Conservation Enforcement status Reviewed preservation Primary evidence Pool ETH accounting , stateful exact-accounting invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-02","heading":"BAL-02 Unsolicited ETH isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Unsolicited ETH cannot change collateral, initialize an exchange rate, or increase liabilities. Transition liveness under forced balances is owned by LIFE-02 . Example: ETH forced into an empty pool does not let the first complete-set mint use that ETH as its collateral base. Type Conservation Enforcement status Reviewed preservation Primary evidence receive , tracked collateral, and fee redemption , auction finalization , receive sender tests , mint fuzzing with forced ETH surplus","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-03","heading":"BAL-03 Collateral capacity and backing","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each vault's underwriting commitment X ( underwritingLimitAttoEth ) is separate from its REP backing. The pool maintains the total commitment T incrementally; L is tracked settlement collateral . Obligation. With positive T , a vault's obligation is L × X / T , rounded upward to the next atomic unit with full-precision arithmetic. For L ≤ T , each rounded obligation is at most X ; independently rounded obligations need not sum exactly to L . Authorization. REP deposits do not increase X . Redemptions and fees reduce L without reducing X , empty settlement epochs do not revoke it, and price or backing changes leave it unchanged. Minting. Minting requires L + deposit ≤ T and no escalation or fork-continuation game. It reads no oracle price and checks no REP backing: every vault already answers for its full commitment, so collateral within T adds no REP exposure. Minters therefore accept the current backing of the pool's commitments; minting is not blocked when that backing is insufficient. The usable collateral ceiling equals T . Withdrawal. A REP withdrawal must preserve aggregate backing for all of T and the withdrawing vault's full-commitment backing. Individual health. Each vault remains subject to full-commitment backing requirements and liquidation; aggregate health does not imply that every vault is healthy. Liquidation transfers commitment and backing to an authorized, sufficiently backed receiver without writing off collateral or changing T , so recovery depends on an eligible receiver. Example: A has a 10 ETH underwriting commitment and the pool holds 10 ETH settlement collateral. B separately deposits sufficient REP and commits 5 ETH. Their obligations become 6.666666666666666667 ETH and 3.333333333333333334 ETH. At 15 ETH settlement collateral, both obligations equal their commitments. Changing REP prices leaves the commitments and the 15 ETH collateral ceiling unchanged but can make a vault liquidatable. Type Conservation Enforcement status Reviewed preservation Primary evidence createCompleteSet , setPoolFinancials , redeemCompleteSet , and redeemShares , redeemCompleteSet and redeemShares claim-exhaustion generation transitions , createCompleteSet , finalizeTruthAuctionRepair , _creditAuctionProceeds , creditForkAuctionVault , commitment, minting, and withdrawal tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-04","heading":"BAL-04 REP coverage boundaries","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For a commitment X at REP/ETH price p , with pool multiplier m in BPS and health factor h in BPS ( 10,000 unless a delegated receiver approved more), each product rounding upward: Associated-REP branch. Pool-held vault REP plus the vault's locally dispute-staked REP is at least X × p × m / 10,000 × h / 10,000 . Pool-held-REP branch. Pool-held vault REP alone is at least X × p × max(10,500, 10,000 + (m − 10,000) / 2) / 10,000 × h / 10,000 . 10,500 BPS is the liquidation-award reserve: 10,000 plus the 500-BPS liquidation bonus. Where both apply. A REP withdrawal or vault-funded escalation deposit must leave the affected vault passing both branches, and both operations apply the same two branches to the pool aggregate against the total underwriting commitment . A liquidation receiver must pass both after accepting the transferred commitment; liquidation does not require the unhealthy target to become healthy. A wallet-funded escalation deposit moves no vault backing and runs neither check. Repricing. A later price change can make an existing position fail a branch without reducing its commitment; that enables liquidation and reverts nothing retroactively. Example: With m = 20,000 , the pool-held-REP multiplier is 15,000 BPS; with m = 10,500 it is the 10,500 -BPS floor. A receiver approved at h = 12,000 must hold 1.2× both upward-rounded requirements after accepting the transferred commitment; passing only one branch is insufficient. Type Safety Enforcement status Contract guard Primary evidence SecurityPoolUtils.isVaultHealthyAtFactor , SecurityPool._requireVaultCoverage and _requirePoolCoverage , multiplier-coverage regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-05","heading":"BAL-05 REP backing units conversion consistency","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property After deposits, withdrawals, liquidations, escalation transfers, migration, and auction claims, the same current pool-held REP balance and total REP backing units govern both REP-to-backing-unit and backing-units-to-REP conversion. Both proportional directions use full-precision multiplication and division so a representable claim cannot fail only because its intermediate product exceeds uint256 . Example: Depositing REP and immediately converting the resulting REP backing units back to REP uses the same denominator rather than a stale pre-deposit balance. Type Conservation Enforcement status Reviewed preservation Primary evidence attoRepToBackingUnits and backingUnitsToAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-06","heading":"BAL-06 Fee liability accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every attoETH of accrued fees is represented once as unallocated reserve or claimable vault fees, and redemption clears the claimable fee balance before ETH is sent. Example: Assigning 3 attoETH of reserve to a vault decreases unallocated reserve by 3 and increases that vault's claimable fees by 3, without creating a second claim. Type Conservation Enforcement status Reviewed preservation Primary evidence Fee accumulator and redeemFees","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-07","heading":"BAL-07 Fee reserve protection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Fork transfers and redemptions cannot spend ETH reserved for unpaid or unallocated fees. Example: A fork transfer may move 8 ETH of collateral from a 10 ETH balance that also contains 2 ETH of fee liabilities, but may not move all 10 ETH. Type Conservation Enforcement status Contract guard Primary evidence transferEth","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"bal-08","heading":"BAL-08 Aggregate pool-ledger coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Fee ledger. totalClaimableVaultFeesAttoEth equals summed unpaid vault fees. Operational fee eligibility. In Operational , feeEligibleUnderwritingLimitAttoEth equals summed live vault underwriting commitments plus sold Truth Auction commitment awaiting claim. uncheckpointedFeeEligibleUnderwritingLimitAttoEth covers fee-eligible commitment not yet reconciled to the current global index, including an unclaimed auction allocation after the index advances. Fork migration. During ForkMigration , configured migrated commitments remain pending outside those pool aggregates. A PoolForked parent retains its fork-time total and fee-eligible snapshots as individual vaults migrate. Auction activation. After a positive-purchase Truth Auction activation, total commitment equals fee-eligible commitment, with the outstanding unclaimed auction allocation in both aggregates. If the auction purchases zero REP, the unmigrated remainder stays an explicit unassigned commitment outside fee eligibility, as the auction settlement specification defines. Commitment ownership. At finalization and after every claim, every commitment unit the child counts belongs either to a real vault or to the nonwithdrawable unassigned position. Fee remainders. Per-vault remainder carries make ordinary fee claims independent of checkpoint frequency and claim order. Terminal residue. At a terminal fork, after all commitment behind the final index has been checkpointed, the only unreconciled whole-attoETH reserve is cumulative division residue, strictly less than N attoETH. N counts each vault entitlement ledger, any separately checkpointed unassigned auction entitlement, and each denominator epoch whose global remainder is cleared when fee-eligible commitment changes; repeated checkpoints within the same ledger and epoch carry their remainder and do not increase N . Terminal recovery. Because the configurable vault floor and auction settlement give N no small protocol-wide bound, the retained terminal recovery path releases that reserve only after uncheckpointedFeeEligibleUnderwritingLimitAttoEth reaches zero. Example: Migrating one of two vaults that each hold a 3 ETH underwriting commitment leaves the parent's frozen 6 ETH total unchanged and records 3 ETH of commitment as unassigned in the child. With purchased REP, finalization adds those 3 ETH of sold commitment to fee eligibility immediately, and later claims only transfer the position to bidder vaults. With zero purchased REP, the same 3 ETH remains unassigned and fee-ineligible until an authorized, fully backed takeover. Type Conservation Enforcement status Reviewed preservation Primary evidence getPoolAccountingSnapshot and vault checkpointing , truth-auction claim accounting , stateful ledger and claim-order invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-01","heading":"SHARE-01 Complete-set symmetry","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A complete-set mint or burn changes Invalid, Yes, and No balances by the same amount in the same universe. Example: Minting five complete sets creates five Invalid, five Yes, and five No shares for that universe. Type Conservation Enforcement status Contract guard Primary evidence mintCompleteSets and burnCompleteSets","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-02","heading":"SHARE-02 Complete-set redemption","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before outcome finalization, burning B complete sets returns ⌊B × tracked collateral / complete-set supply⌋ after the fee checkpoint, then reduces supply by B and collateral by the ETH returned. Example: With 100 sets and 10 ETH of tracked collateral, burning 10 sets returns 1 ETH before integer-rounding residue. Type Conservation Enforcement status Reviewed preservation Primary evidence redeemCompleteSet","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-03","heading":"SHARE-03 Positive-output minting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A successful positive-value complete-set mint returns a positive share amount. Example: A 1 attoETH mint that rounds to zero shares reverts instead of accepting the ETH. Type Safety Enforcement status Contract guard Primary evidence attoEthToAttoShares and the createCompleteSet wrapper , createCompleteSet settlement accounting , positive-value mint fuzzing","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-04","heading":"SHARE-04 Child supply denominators","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Child setup copies the frozen parent's remaining economic claim supply as its collateral denominator. That supply includes both materialized child ERC-1155 balances and source entitlements that can materialize later. Complete-set minting adds claims, while complete-set and winning-share redemption consume them. Example: If a parent freezes with 10 claims per outcome and a child has no materialized shares yet, setup still records 10. A new minter receives only the shares purchased at that established rate, while all 10 source claims retain their reserved collateral. Type Conservation Enforcement status Reviewed preservation Primary evidence attoEthToAttoShares and redeemShares and ShareToken.migrate","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-05","heading":"SHARE-05 Winning-share payout cap","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Total ETH paid to winning shares never exceeds the collateral available when redemption begins; rounding residue remains for later winning holders. Example: When two winners redeem sequentially, the second receives its fraction of the collateral left after the first rather than a fraction of the original balance paid twice. Type Conservation Enforcement status Contract guard Primary evidence redeemShares","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"share-06","heading":"SHARE-06 Share supply conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For every ERC-1155 share ID, total supply equals the sum of holder balances through mint, transfer, and burn operations. Per-child materialization and duplicate prevention are owned by FORK-10 . Example: Moving two Yes shares between wallets leaves Yes supply unchanged; burning one Yes share reduces both the holder-balance sum and Yes supply by one. Type Conservation Enforcement status Reviewed preservation Primary evidence ERC-1155 supply accounting , modeled holder-supply invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-01","heading":"VAULT-01 Dispute-staked REP isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property REP that a vault moved into an escalation game cannot also be withdrawn, liquidated as pool-held vault REP backing, or migrated through the ordinary non-escrowed vault path. REP deposited straight from a wallet with depositWalletRepToEscalationGame enters the game without ever becoming vault backing. Example: A vault initially attributed 20 REP that dispute-stakes 5 REP is left with 15 REP of vault backing plus a separate 5 REP claim. It cannot make an ordinary withdrawal while that escrow remains; ordinary vault migration moves only the 15 REP backing, while the dispute-staked REP claim follows its separate migration path. Type Conservation Enforcement status Reviewed preservation Primary evidence Escrow checks , EscalationGame , wallet-funded deposit regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-02","heading":"VAULT-02 Liquidation conservation and freshness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Eligibility. Liquidation eligibility and receiver authorization use full underwriting commitments , including when settlement collateral is zero. Transfer. A successful liquidation transfers underwriting commitment and REP backing units from target to receiver without changing the total commitment. Unrelated vaults retain their proportional weights. Award. The nominal REP award includes the fixed 5% liquidation bonus and is capped by available target backing; a sufficiently backed receiver can take the full commitment even when that award is not fully funded. Receiver backing. Both backing constraints apply to the receiver's entire resulting commitment. Residual commitment. Residual target commitment remains visible and can be taken over later; liquidation does not write it off. Fees and stake. Earned fees and dispute stake stay with their owners, with fees checkpointed before the transfer. Underbacked commitments continue earning fees; backing health affects liquidation eligibility, not fee entitlement. Delegated route. A delegated route bounds the transferred commitment by the receiver's signed reservation and consumes or releases that reservation exactly once. Example: If the target or receiver changes after staging, execution may fail safely and release the full reservation. The operator receives no ownership merely for submitting the transaction. Type Conservation Enforcement status Reviewed preservation Primary evidence Liquidation design , performLiquidation , executeStagedOperation , liquidation commitment-transfer tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-03","heading":"VAULT-03 Vault registry coherence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The vault registry is append-only and contains each nonzero address at most once. Registration does not require economic state: any vault path that registers through _registerVault or the operations delegate's equivalent inline registration, including a public fee checkpoint for an empty address, can append it. Pagination is newest-registered first; later activity and full exit do not reorder or remove an entry. Consumers read current vault and escalation state to decide which registered vaults to display. Example: After a vault has fully exited and its REP backing, underwriting commitment, claimable fees, escalation stake, bad debt , and open interest are all zero, its address remains in registry pagination. A UI can filter the empty position without losing historical discovery. Type Safety Enforcement status Reviewed preservation Primary evidence _registerVault , registry pagination and direct-claim boundary tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"vault-04","heading":"VAULT-04 Escalation claims are non-transferable and migration-neutral","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An escalation claim is permanently bound to the depositor committed in its carry leaf and has no transfer path and no power over parent open-interest migration. Liquidation cannot read, move, or acquire it. Payout to the committed depositor is owned by ESC-07 . Example: Moving half a vault's underwriting commitment leaves every escalation claim unchanged, and locking that claim cannot increase the open interest routed to any child. Type Safety Enforcement status Reviewed preservation Primary evidence withdrawDeposit , liquidation design , child-liquidation claim-retention test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"forks","heading":"Forks and child isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the share migration and fork migration guardrails.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-01","heading":"FORK-01 Parent pool finality","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once a pool's universe forks, the pool's operational flows are frozen by the fork-time check in isOperational , whatever its stored state. A pool that enters PoolForked never returns to Operational . A pool with an inherited fixed outcome never enters PoolForked ; ESC-12 owns that case. Example: After fork activation, the parent cannot accept another REP deposit or later return from PoolForked to Operational . Type Safety Enforcement status Contract guard Primary evidence isOperational , activateForkMode","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-02","heading":"FORK-02 Immutable fork snapshot","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property When the parent first enters fork mode, it captures fork time, collateral, REP buckets, total REP backing units, escalation state, and underwriting commitments exactly once. Those immutable values are the common basis for every child of that fork. Example: REP sent unsolicited to the parent after fork mode begins cannot change the REP snapshot used to initialize a later-created No child. Type Safety Enforcement status Reviewed preservation Primary evidence Fork snapshot preparation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-03","heading":"FORK-03 Isolated migration proxy","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each parent pool maps to exactly one deterministic migration-proxy address, and that address is the pool's isolated identity in the Zoltar migration ledger. Example: Two parent pools using the same forker derive different proxy addresses and therefore cannot spend each other's migration credit. Type Safety Enforcement status Reviewed preservation Primary evidence getMigrationProxyAddress","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-04","heading":"FORK-04 Prefunded proxy isolation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Preexisting or unsolicited REP at the deterministic proxy cannot block initiation or become unclassified migration principal. Example: An attacker sending 1 REP to the future proxy address cannot make fork initiation revert or count that REP as pool migration principal. Type Liveness Enforcement status Reviewed preservation Primary evidence initiateSecurityPoolFork","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-05","heading":"FORK-05 Eight-week migration boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Statoblast child-pool creation, pool-local vault migration, public pool-proxy REP splitting through migrateRepToZoltar , and own-fork claims are allowed through forkActivationTime + 8 weeks , inclusive, and are closed after that timestamp. Starting a child's Truth Auction after the deadline still completes that child's remaining pool-proxy REP split. forkActivationTime is recorded when the parent pool enters PoolForked ; post-migration activation begins only after its window ends. Share materialization has no expiry, but after the deadline it can target only an already-created child. This pool-local boundary does not limit Zoltar.deployChild , addRepToMigrationBalance , or splitMigrationRep ; those Zoltar operations follow their own fork identity and balance guards without this timestamp check. Example: Vault migration succeeds exactly at the eight-week deadline and reverts one second later. Type Safety Enforcement status Reviewed preservation Primary evidence forkActivationTime recording and child guards , MIGRATION_TIME , deployChild , addRepToMigrationBalance , and splitMigrationRep , migration and auction-start deadline tests , nested-fork migration-window regression test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-06","heading":"FORK-06 Child deployment identity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A deployed child must name the requesting pool as its parent and must use the child universe derived from that parent's selected branch. Its factory, forker, auction, share token, pool question, and security multiplier must equal the values supplied or inherited by the parent factory path. External-universe fork initiation requires the source pool to be authorized by its declared share token; own-game initiation does not. That relationship is not proof of configured-factory registration. The auction must have deployed code and must not already be trusted for another child. Example: On the external-universe path, the forker first requires the source to be authorized by its declared share token without treating that check as factory registration. The configured canonical factory installs the parent's share token, pool question, and multiplier in the child; the post-deployment guard then checks deployed and unique auction assignment plus parent, universe, factory, forker, and auction relationships before linking it. Type Safety Enforcement status Reviewed preservation Primary evidence _prepareForkState external-fork authorization guard , _validateChildPoolDeployment and deployChildSecurityPool","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-07","heading":"FORK-07 Single-use non-escrowed vault migration","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Vault migration converts the parent's backing-unit claim to REP, credits that REP amount as child-local backing units, and clears the corresponding parent REP backing units and underwriting commitment before reuse. A positive parent claim that maps to zero child REP receives zero child backing units, so rounding cannot preserve a stale claim that later regains value. Claimable fees remain in the parent vault while proportional settlement collateral routes separately at pool level. Example: After Alice migrates her non-escrowed vault accounting to the Yes child, a second migration call cannot credit the same parent REP backing units to the No child. Type Conservation Enforcement status Reviewed preservation Primary evidence _migrateNonEscrowedVaultAccounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-08","heading":"FORK-08 One-time aggregate continuation backing","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once per child. Each selected child initializes the canonical carry snapshot and receives the complete aggregate continuation backing at most once. Optional cleanup. Vault cleanup, callable only by the vault owner within the migration window, first migrates that vault's non-escrowed position and then clears its unresolved parent escalation-deposit accounting. It creates no child escrow and cannot change carried-proof eligibility. Unrelated fork. The continuation cannot resume until its game balance covers all effective unresolved principal. Own fork. Let R be the snapshot's raw unresolved principal: the sum of inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep across all three outcomes, before direct-claim deductions. Initial backing must be at least R - ⌊R / 5⌋ , where 5 is the fixed Constants.MINIMUM_FORK_BURN_DIVISOR , not the universe's configured fork burn divisor. The live balance must cover the initial backing not yet exported by valid direct pre-resume claims, scaled down by any REP a Truth Auction removed from the game. Example: Creating the Yes child installs its snapshot and aggregate backing before Alice acts. Alice may later clear her unresolved parent escalation-deposit accounting, but that cleanup neither funds the child nor enables or disables her winning proof. Type Conservation Enforcement status Contract guard Primary evidence _ensureChildEscalationBacking , resumeFromFork , isForkCarryFundingComplete , _exportForkedEscrowByOutcome , and fork-backing regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-09","heading":"FORK-09 Cumulative child collateral","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Cumulative parent ETH transferred to children never exceeds the fork collateral snapshot and is derived from cumulative migrated REP, not per-call rounding. Example: If several calls collectively migrate R child REP, their collateral target is ⌈fork collateral × R / denominator⌉ , independent of how that same R is partitioned. The denominator is vaultRepAtForkAttoRep for an own fork and auctionableAttoRepAtFork otherwise. Type Conservation Enforcement status Contract guard Primary evidence _transferForkMigratedCollateralToChild","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-10","heading":"FORK-10 Share migration integrity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Share migration preserves the holder's parent token-ID balance as a persistent entitlement, rejects duplicate or malformed target outcomes, and mints only the unmaterialized balance into each selected child. A used source balance cannot transfer. Example: Materializing seven parent Yes shares in one child leaves all seven parent entitlements visible and locked. A later call can mint seven into another existing child, but cannot mint the first child twice. Type Conservation Enforcement status Contract guard Primary evidence ShareToken.migrate","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-11","heading":"FORK-11 Unequal child share supplies","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Child pricing uses the fork-time economic claim supply rather than currently materialized outcome supplies. Unequal ERC-1155 supplies therefore do not block complete-set minting or proportional complete-set redemption. The denominator lifecycle and payout mechanics are owned by SHARE-04 . Example: If the economic supply is 12 while materialized supplies are 10, 8, and 6, a new complete set is priced against 12 and adds the same newly purchased balance to all three materialized supplies. Type Conservation Enforcement status Reviewed preservation Primary evidence setShareTokenSupplyAttoShares during auction preparation , attoSharesToAttoEth , redeemCompleteSet , and redeemShares , mintCompleteSets and persistent migration accounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"fork-12","heading":"FORK-12 Child activation after settlement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Value-free truth-auction settlement activates a child with its tracked migrated collateral plus retained auction ETH, which cannot exceed the parent fork snapshot. Fork-time economic claim accounting keeps later minting and proportional burns independent from materialization order. Example: A child with 9 ETH against a 10 ETH fork snapshot activates after value-free finalization with 9 ETH of tracked collateral; its later operations remain subject to the ordinary share-supply and minting guards. Type Safety Enforcement status Reviewed preservation Primary evidence Truth-auction start and finalization","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"escalation","heading":"Escalation Games and carried claims","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the escalation guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-01","heading":"ESC-01 Total escrow reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property totalDisputeStakedAttoRep equals effective live vault-denominated escrow plus effective aggregate continuation backing in forkCarryDisputeStakedAttoRep . Continuation backing is not assigned to child-vault health or migration power, but it must enter the aggregate before the Truth Auction so physically held REP cannot escape the Truth Auction's REP removal. Auction retention, the fraction of game REP left after that removal, floors the aggregate total and the continuation bucket independently; do not reconstruct either aggregate by summing independently rounded vault views. Example: If vault-denominated escrow contributes 4 and 6 REP and an external-fork continuation carries 12 REP of aggregate proof backing, the total is 22 REP, represented as 22 × 10^18 attoREP in totalDisputeStakedAttoRep , before the auction. A 75% retention records ⌊22 × 10^18 × 75%⌋ attoREP, or 16.5 total effective REP, and ⌊12 × 10^18 × 75%⌋ attoREP, or 9 aggregate continuation REP. This makes the carried claims absorb the same repair loss without pretending that their backing belongs to a particular child vault. Type Conservation Enforcement status Reviewed preservation Primary evidence Continuation initialization , truth-auction retention accounting","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-02","heading":"ESC-02 Local unresolved REP reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property totalLocalUnresolvedAttoRep equals the sum of unresolved local deposits, and each vault-local counter is its exact component. Example: If Alice has 3 unresolved REP and Bob has 5, their counters are 3 and 5 and the global local-unresolved total is 8. Type Conservation Enforcement status Reviewed preservation Primary evidence Unresolved counters","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-03","heading":"ESC-03 Outcome carry reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For each outcome, currentCarryTotalAttoRep equals effective inherited unresolved principal plus unresolved local deposits. Effective inherited principal subtracts immediate-parent direct claims and becomes zero for an inherited losing outcome after finalization. Example: A child snapshots 7 Yes REP, the parent directly claims 2 REP, and the child receives a new unresolved 2 REP Yes deposit. Its current Yes carry is (7 - 2) + 2 = 7 REP . Type Conservation Enforcement status Reviewed preservation Primary evidence Escalation accounting invariants , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-04","heading":"ESC-04 Stable deposit identifiers","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An ordinary game's stable deposit identifier is its local deposit index. A continuation game derives the identifier from its own address, outcome, and local index, so two different continuation deposits cannot share a carry or nullifier key merely because their local indexes match. Example: Deposit zero on Yes in a child game and deposit zero on Yes in its grandchild produce different stable identifiers. Type Safety Enforcement status Reviewed preservation Primary evidence Stable deposit identity , EscalationGameSettlement._getStableLocalParentDepositIndex , SecurityPoolForker.getEscalationDepositId","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-05","heading":"ESC-05 Single-use claims per branch","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Along any single root-to-descendant fork path, each local or inherited deposit may be claimed, settled, refunded, or exported at most once. Child nullifiers are branch-local, so selected sibling branches keep separate claim authorization. A direct claim from an ancestor is the exception and is owned by ESC-10 . Example: Consuming a carried proof in a Yes grandchild prevents replay farther down that branch while a sibling branch remains independent. Type Safety Enforcement status Reviewed preservation Primary evidence Carry nullifiers , MMR proofs , carried-proof replay test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-06","heading":"ESC-06 Aggregate export accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Aggregate unresolved export clears the exporting vault's three outcome totals, unresolved counter, and parent escrow exactly once. It retains the deposit rows and carry commitment solely as immutable proof material for selected children. Example: After Alice exports her aggregate claim, her parent escrow is zero even though her historical deposit row remains available to prove a child claim. Type Conservation Enforcement status Reviewed preservation Primary evidence exportVaultUnresolvedTotalsWithoutTransfer","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-07","heading":"ESC-07 Authenticated carried winner payout","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A carried claim must authenticate an unconsumed proof for the final winning outcome. The proof fixes the original claim identity and its committed depositor, who receives the normal winning payout even when another account relays the transaction. Liquidation cannot change that recipient. Example: Bob may relay Alice's valid winning proof, but the payout still goes entirely to Alice as the committed depositor. A losing proof cannot consume backing, and reward math may make a winning payout greater than its principal. Type Conservation Enforcement status Contract guard Primary evidence withdrawDeposit","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-08","heading":"ESC-08 Game REP settlement conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every REP unit held for a game is accounted for exactly once as winning principal, burned escalation haircut, reward funding, losing principal, unsettled residual, ordinary-game REP swept back to the pool, fork-continuation REP burned, or REP moved out by fork activation or a Truth Auction. Settlement cannot create an additional REP claim. Example: Paying winners and sweeping the final residual reduces the game balance to zero without total payouts exceeding the REP previously held. Type Conservation Enforcement status Reviewed preservation Primary evidence Settlement","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-09","heading":"ESC-09 Terminal game outcomes","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once resolution or non-decision closes a game path, later deposits cannot reopen or change that terminal result. Example: After Yes becomes final, a later attempt to deposit on No reverts rather than changing the winner. Type Safety Enforcement status Contract guard Primary evidence EscalationGame","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-10","heading":"ESC-10 Ancestor claim replay protection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property If a deposit is claimed directly from an ancestor during an own fork, every existing or later descendant treats the corresponding proof as spent, even if that descendant has not written its own nullifier, and subtracts the claimed principal from its effective inherited principal. Example: Claiming deposit 4 from the parent blocks proof 4 in an already-created child and in a grandchild created later. Type Safety Enforcement status Reviewed preservation Primary evidence Forked claims , direct-claim replay test across current and late children","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-11","heading":"ESC-11 Residual sweep preconditions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Residual REP cannot be settled until effective unresolved principal is zero for every outcome. For a continuation, the sweep first retires its inherited aggregate forkCarryDisputeStakedAttoRep ; after that retirement, no local dispute stake or vault escrow may remain in totalDisputeStakedAttoRep . Inherited losing principal retires at finalization without a proof; winning inherited proofs and every local unresolved deposit still require their applicable terminal transition. Ordinary-game residual returns to the pool, while fork-continuation residual is burned and cannot accrue to child-local backing units. Example: After Yes finalizes, an unclaimed inherited No leaf does not block sweeping. An unclaimed inherited Yes proof, an unsettled local deposit, or a live vault escrow record still does. Type Conservation Enforcement status Contract guard Primary evidence sweepResidualRepToSecurityPool , external-fork residual burn regression test , own-fork residual burn regression test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-12","heading":"ESC-12 Pool and continuation payout agreement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property When a universe forks on a pool's question, each child pool and its continuation game use that child's Invalid, Yes, or No branch as the final pool-question outcome. Once a pool inherits that fixed outcome, new local escalation deposits and every later fork transition revert, whether the new universe fork uses the same question or another one. Deposit withdrawal reverts unless the pool and game report the same outcome. Example: A Yes child created by a fork on the pool question pays carried Yes deposits even if copied game balances favored No. It rejects new local dispute-staked REP before escrow, so a later local non-decision cannot lock vault redemption. A later matching or unrelated universe fork leaves the stored SystemState.Operational and fixed Yes outcome unchanged, and eligible share, vault REP, and carried-proof redemption paths remain available, while universe-fork guards still freeze normal operating calls. Type Safety Enforcement status Reviewed preservation Primary evidence activateForkMode , getQuestionResolution , fixed-outcome propagation , and pool/game payout check","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-13","heading":"ESC-13 Non-decision threshold and live start-bond arithmetic","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For a positive fork threshold of F attoREP, non-decision requires ⌈F / 2⌉ attoREP on at least two outcomes. Therefore the two threshold balances total at least F , while one attoREP less on both outcomes totals strictly less than F . At pool construction, the configured start bond is max(1 REP, live universe theoretical REP supply / 10,000,000) , and a new origin requires the live non-decision threshold to exceed it. If an existing pool's live threshold later falls to or below that configured bond, ordinary game deployment clamps the live start bond to nonDecisionThresholdAttoRep - 1 , provided the threshold exceeds one attoREP. Example: If F = 5 attoREP, non-decision requires 3 attoREP on two outcomes, which total 6 attoREP; one attoREP less on both, 2 and 2 , totals 4 attoREP, below the fork threshold. Type Safety Enforcement status Contract guard Primary evidence getNonDecisionThresholdAttoRep , origin threshold admission , deployEscalationGame , and start-liveness regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"esc-14","heading":"ESC-14 Carry commitment structural integrity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property For every outcome, exported carry peaks, leaf count, unresolved total, and nullifier root equal the corresponding outcome state. Only leaf-count-selected peak heights are occupied, independently bagging those peaks yields the exported root, and consumed proof indexes are unique. The accounting definition of unresolved total is owned by ESC-03 . Example: Three Yes leaves occupy the height-zero and height-one peaks; bagging those two peaks reproduces the exported Yes root before and after one inherited proof is consumed. Type Conservation Enforcement status Reviewed preservation Primary evidence getForkCarrySnapshot and getForkCarryRoots , bagCarryPeaks , independent carry-structure invariant tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"oracle","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A18 independent correction incentive , A19 observable correctable price , and A06 lifecycle executors . No oracle invariant bounds operation value by report liquidity or bounds pending-report duration; these are the excluded guarantees EG03 and EG04 . Per-function accept and reject conditions are in the oracle guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-01","heading":"ORA-01 Authorized settlement callbacks","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Only the configured OpenOracle may supply a settlement callback, and its report identifier must equal the coordinator's pending report. Example: A callback from another contract or for an older report ID cannot update the cached REP/ETH price. Type Safety Enforcement status Contract guard Primary evidence openOracleCallback , callback caller and report-identity guard test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-02","heading":"ORA-02 REP-per-ETH price direction","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An accepted price is positive REP per ETH: amount2 REP × 1e18 / amount1 WETH . Higher values require more REP for the same ETH obligation. Example: A report of 200 REP for 2 WETH stores 100 REP per ETH, not 0.01 ETH per REP. Type Safety Enforcement status Contract guard Primary evidence openOracleCallback , ratio direction","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-03","heading":"ORA-03 Oracle price validity","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A cached price is usable only while nonzero and strictly younger than its chain-specific validity window . Example: On mainnet, a price whose final report reached settlement eligibility exactly five minutes ago is stale; one that reached it four minutes and 59 seconds ago remains usable. Type Safety Enforcement status Contract guard Primary evidence isPriceValid , five-minute validity boundary test , late-settlement freshness regression tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-04","heading":"ORA-04 Single-use staged operations","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every staged operation has one immutable identifier. Once execution is attempted with a usable price, success or a caught failure consumes that identifier, emits the result, and prevents a retry. An uncaught transaction revert instead rolls back the entire attempt. Example: A pool-level withdrawal rejection is caught and emitted as failed, after which the same operation ID cannot be executed again. Type Safety Enforcement status Contract guard Primary evidence executeStagedOperation , staged-operation overwrite and double-execution test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-05","heading":"ORA-05 Staged operation targets","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Withdrawals target the initiating vault. Liquidations name separate operator, receiver, and target roles; the receiver must differ from the target, while the operator may equal either. A liquidation fails when the protected target REP-backing-unit or underwriting-commitment snapshot becomes stale. Example: Alice can stage her own REP withdrawal. A liquidation operator can target Bob, but its receiver cannot be Bob; execution fails if Bob changes his REP backing units or underwriting commitment after staging. Type Safety Enforcement status Contract guard Primary evidence Staging and snapshot checks","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-06","heading":"ORA-06 Consumed execution failures","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An expired operation, a liquidation with a stale target snapshot, a withdrawal that would move zero REP, or a liquidation inside the configured minimum price distance is a consumed failure under ORA-04 : it emits an observable failure result instead of remaining executable. Example: If an earlier withdrawal empties a vault, its second queued withdrawal is consumed as a zero-effect failure rather than retried after every price update. Type Liveness Enforcement status Contract guard Primary evidence executeStagedOperation","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-07","heading":"ORA-07 Staged-operation queue and index bijection","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Operation IDs are append-only. Active enumeration contains each and only each operation with a live initiator; the bounded pending settlement queue contains unique active IDs; and pendingOperationSlotId is zero for an empty queue or equals its head. Example: Settling four queued operations removes those four IDs from both indexes, leaves an overflow operation active for manual execution, and does not reuse any consumed ID. Type Safety Enforcement status Reviewed preservation Primary evidence active and pending staged-operation indexes , queue/index invariant test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-08","heading":"ORA-08 Dispute and settlement boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property The settlement deadline is exclusive: disputes require the current clock to be strictly before the deadline, while settlement is available at and after it. Example: At timestamp deadline , a new dispute is rejected and settlement is allowed. Type Safety Enforcement status Contract guard Primary evidence settle and dispute validation , exact settlement-deadline test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ora-09","heading":"ORA-09 Oracle balance-domain boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Direct REP or WETH held by the coordinator is outside OpenOracle and remains untouched by settlement or recovery. OpenOracle credits balances by beneficiary rather than by report: the callback sends the coordinator's entire withdrawable internal REP and WETH credit to the recorded pending sponsor, including any third-party deposit that names the coordinator as beneficiary. Example: REP transferred directly to the coordinator remains there, while REP deposited into OpenOracle for the coordinator is swept with the report proceeds to the current sponsor and leaves only OpenOracle's balance sentinel. Type Conservation Enforcement status Reviewed preservation Primary evidence pendingReportSponsor and _withdrawOpenOracleReporterBalances , deposit and withdrawTo , coordinator/OpenOracle balance-domain test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auctions","heading":"Truth Auctions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Per-function accept and reject conditions are in the Truth Auction guardrails .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-01","heading":"AUC-01 Bid admission","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Bids are accepted only during the one-week window, at a supported tick whose computed ETH-per-REP price is positive, and at or above the auction's minimum bid size. Example: A bid submitted one second after the one-week window or below the minimum bid size reverts without being recorded. Type Safety Enforcement status Contract guard Primary evidence submitBid , bid-size and tick admission tests , bid and finalize deadline test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-02","heading":"AUC-02 Auction caps","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Final retained ETH never exceeds the ETH raise cap, and total purchased REP never exceeds the REP sale cap. Example: If bids offer 12 ETH against a 10 ETH cap, finalization retains at most 10 ETH, and the rest stays refundable through bid settlement. Type Conservation Enforcement status Contract guard Primary evidence computeClearing and finalize , dual-cap clearing tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-03","heading":"AUC-03 Single-use bid settlement","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Each bid is settled at most once; claimed state is set before refundable ETH is credited to bidder-specific pull escrow. Settlement never calls recipient code. withdrawPendingEthRefund clears the caller's credit before its only external call, and a rejected transfer reverts the clear. Example: A reverting bidder cannot block settlement or withdraw another bidder's credit. Its own failed pull preserves the complete balance for a later authorized retry. Type Safety Enforcement status Contract guard Primary evidence withdrawBids and refund functions","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-04","heading":"AUC-04 Claim-order independence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Per-bid REP, refund, underwriting-commitment, and bad-debt results do not depend on post-finalization claim order. The fixed cumulative-position rule that produces this is owned by AUC-06 . Example: Alice claiming before Bob gives each vault the same REP, ETH refund, and underwriting commitment as Bob claiming before Alice. Type Conservation Enforcement status Reviewed preservation Primary evidence allocateFromCumulativePosition , order-independent settlement test , cross-tick dust withdrawal-order test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-05","heading":"AUC-05 Allocation and refund reconciliation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property A zero-demand auction records zero purchased REP. Otherwise, the sum of all winning-bid REP allocations equals the stored aggregate purchase, and each bid's unretained ETH remains refundable. Example: If finalization stores 30 purchased REP, all winning claims together receive exactly 30 REP and every unretained attoETH is refunded. Type Conservation Enforcement status Reviewed preservation Primary evidence Auction settlement , UniformPriceDualCapBatchAuction.finalize and withdrawBids","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-06","heading":"AUC-06 Bidder-vault credits","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Credit. A bid claim keeps purchased REP pool-held and transfers the bid's proportional REP backing units, underwriting commitment , and finalization-to-claim fees from the unassigned position to the bid's recorded vault. These credits add to, rather than replace, that vault's migrated position. Bad debt. The claim also transfers the proportional auction bad debt while the auction-finalization generation is current; after that generation expires, the raw claimed-debt counter advances without crediting stale debt to the vault. Conservation. Each decrease in unassigned backing and commitment equals the corresponding vault credit, and current-generation unassigned debt decreases by its corresponding vault credit. The auction rate is derived only from bounded child-local units, and cumulative credit cannot exceed the finalized denominator. Order independence. Commitment and current-generation bad-debt division dust follows each bid's fixed cumulative ETH position, so each winner's allocation is independent of claim order. A winning dust bid whose REP allocation rounds to zero can still receive a positive fixed-position commitment share. Aggregates. Claiming does not change total or fee-eligible underwriting commitment, active open interest, current-generation total bad debt, retention rate, or aggregate accrued fees. Example: A vault with migrated REP backing units keeps them when settling a winning auction bid. A current-generation claim moves the bid's backing units, deterministic commitment share, proportional bad debt, and accrued fees into that vault while leaving every pool aggregate unchanged. If the generation has expired, the same claim moves the backing units, commitment share, and fees but assigns no old debt. If a dust bid's REP share is zero but its commitment share is positive, claiming that bid alone still credits the commitment. Type Conservation Enforcement status Reviewed preservation Primary evidence Auction-claim settlement , _creditAuctionProceeds , creditForkAuctionVault , claim-ordering reconciliation test , claim-order bad-debt test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-07","heading":"AUC-07 Uniform weak-demand allocation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property In underfunded clearing, qualifying ETH is retained bid ETH offered at or above the cap-implied qualification threshold. The threshold is not an execution-price floor. Qualifying bidders collectively receive maxAttoRepBeingSold in proportion to that ETH at the aggregate effective price underfundedWinningAttoEth / maxAttoRepBeingSold . Each qualifying bid uses its full ETH, and per-bid cumulative floors assign indivisible attoREP, so a dust winner can round to zero REP without changing the aggregate price. With no qualifying ETH, every bid refunds. Example: If Alice supplies 60% and Bob 40% of qualifying ETH, they receive 60% and 40% of the complete REP sale cap subject to deterministic attoREP rounding. Type Conservation Enforcement status Reviewed preservation Primary evidence Truth Auction clearing design , underfundedWinningAttoEth allocation in UniformPriceDualCapBatchAuction , underfunded settlement tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-08","heading":"AUC-08 Forced-ETH-resistant finalization","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Auction finalization succeeds regardless of unsolicited ETH already present in the child pool or forker. This is the auction case of BAL-02 (the forced ETH stays surplus) and LIFE-02 (it cannot block the transition). Example: One attoETH forced into the child before finalization remains surplus and does not change protocol-accounted collateral. Type Liveness Enforcement status Reviewed preservation Primary evidence finalizeTruthAuctionRepair , forced-ETH bidding and finalization tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-09","heading":"AUC-09 Value-free finalization liveness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property At and after the auction deadline, finalization succeeds without added ETH, and a finalization call carrying ETH reverts. Qualifying bids then settle for REP and non-qualifying bids refund. The collateral the child activates with is owned by FORK-12 . Example: Exactly at the deadline, finalizeTruthAuction with no value succeeds, and the same call with 1 attoETH attached reverts with No repair ETH . Type Liveness Enforcement status Contract guard Primary evidence SecurityPoolForker.finalizeTruthAuction , finalizeTruthAuctionRepair , finalization deadline and no-donation tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-10","heading":"AUC-10 Persistent tick bid history","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Bid cumulative ETH remains append-only for a tick even when the active AVL node is deleted and later recreated. Refunded history is subtracted exactly once, so every later accepted bid retains a valid allocation or refund path. Example: Deleting an empty price tick and later bidding at that price continues cumulative ETH after the old history instead of making the new bid unclaimable. Type Conservation Enforcement status Reviewed preservation Primary evidence _appendBid and refund-prefix accounting and repeated tick deletion/recreation tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-11","heading":"AUC-11 Auction tree and public-model equivalence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before finalization, active tick pages contain exactly the nonzero ticks not removed by pre-finalization refunds, in descending order, and clearing computed from the AVL tree equals an independent calculation over those bids. Finalization freezes that tree and clearing result: later claims change bid flags and ETH liabilities but not active tick pages. Post-finalization liabilities are owned by AUC-12 . Historical insertion and refund-prefix obligations are owned by AUC-10 . Example: Before finalization, an independent descending-tick scan returns the same clearing result as the contract. After a winner settles, its bid is marked claimed and any refund moves to pull credit, while the final clearing page and result remain unchanged. Type Safety Enforcement status Reviewed preservation Primary evidence AVL tree and clearing , enumeration and auction integration , seeded independent-model and frozen-snapshot tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"auc-12","heading":"AUC-12 Auction ETH liability conservation","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Before finalization, auction ETH equals active unrefunded bids plus aggregate pendingEthRefundsAttoEth and derived surplus. After finalization, the remaining balance equals refunds still attached to unclaimed bids plus credited pendingEthRefundsAttoEth and derived surplus. Settling a refund moves value between those two liabilities without transferring ETH; only an authorized pull reduces the balance. Per-bid settlement partitions and aggregate REP allocation are owned by AUC-05 . Example: Before finalization, settling a 2 ETH losing bid removes it from active clearing and adds a 2 ETH bidder credit, leaving raw auction ETH unchanged until that bidder pulls it. Type Conservation Enforcement status Reviewed preservation Primary evidence finalize , withdrawBids , and credited refunds , seeded and pull-refund ETH-liability tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"lifecycle","heading":"Lifecycle, liveness, observability, and external calls","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Security assumptions: A02 viable operating costs , A16 timely inclusion , A06 lifecycle executors , and A26 Ethereum execution .","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-01","heading":"LIFE-01 Pool state transitions","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Pool state topology permits only Operational → PoolForked for a parent and ForkMigration → ForkTruthAuction → Operational for a child. Example: A child cannot move directly from ForkMigration to Operational ; even when no repair auction is needed, startTruthAuction enters ForkTruthAuction and finalizes in the same transaction. Type Safety Enforcement status Reviewed preservation Primary evidence SystemState , fork transitions ; see FORK-12 for child accounting consistency.","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-02","heading":"LIFE-02 Permissionless transition liveness","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Once a resolution, migration, auction-completion, or withdrawal function's documented semantic preconditions hold, dust, unsolicited balances, empty collections, or earlier permissionless calls cannot permanently prevent some caller from completing it. Example: Forced ETH and an empty losing-bid list do not prevent a caller from finalizing an otherwise complete Truth Auction. Type Liveness Enforcement status Reviewed preservation Primary evidence FORK-04 , BAL-02 , and AUC-08 ; named LIFE-02 fixed-point and stateful lifecycle regressions , forced-balance and zero-demand auction regressions , and oracle recovery and empty-vault regressions","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-03","heading":"LIFE-03 Atomic failure behavior","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property An uncaught revert rolls back every state mutation and transfer in the transition. Deliberately consumed failures, which commit an explicit failed result instead, are owned by ORA-04 . Example: If a child migration reverts after an attempted token transfer, neither the transfer nor its accounting update remains committed. Type Safety Enforcement status Reviewed preservation Primary evidence EVM revert semantics, OpenOraclePriceCoordinator.executeStagedOperation consumed-failure paths","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-04","heading":"LIFE-04 Deadline equality rules","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Every deadline assigns equality to one side of the boundary. These entries own their boundaries: FORK-05 (pool migration stays open at equality; auction start opens afterward), AUC-01 (bidding closes at equality, when finalization opens), ORA-03 (cached prices are stale at equality), and ORA-08 (OpenOracle disputes close and settlement opens at equality). The remaining boundaries are: A universe fork and the first escalation deposit are both allowed at question-end equality. Staged operations remain executable through equality and expire afterward. An escalation result becomes final only after its end timestamp. ERC-2612 permits include equality, while ERC-3009 authorizations use a strict validity window. Example: Exactly at a question's end time, both forkUniverse and the first depositToEscalationGame succeed; one second earlier, both revert. Type Safety Enforcement status Contract guard Primary evidence question-end fork boundary , initial-reporting boundary , migration and auction boundaries , escalation finality boundary , cached-price and staged-operation boundaries , and OpenOracle dispute and settlement boundary","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"life-05","heading":"LIFE-05 Bounded transition work","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property No mandatory transition iterates over the whole deposit, bid, or vault history in one transaction; callers use bounded pages, fixed outcome sets, proofs, or balanced-tree traversal. Work is not constant in fork depth. Computing a carried claim's payout calls getUnresolvedClaimInterval on each source game between the claiming game and the game where the deposit was made, so its gas grows linearly with the number of forks the deposit has been carried across. The contracts enforce no maximum fork depth. The lookups that stay depth-independent are listed in EXT-05 . Example: Settling one carried deposit verifies one proof and makes one interval call per ancestor game; it does not iterate over the other deposits in those games. Type Liveness Enforcement status Reviewed preservation Primary evidence SecurityPool.getVaults , auction bid pages and AVL traversal , MerkleMountainRange proofs , EscalationGameClaimDelegate.getUnresolvedClaimInterval","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"obs-01","heading":"OBS-01 Event-state replay equivalence","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Ordered canonical events reconstruct the same universe, pool, vault, coordinator, and escalation carry state exposed by storage. Replay isolates contract-local counters and recognized emitters, and every replay-supported state transition emits the checkpoint or delta needed to reach its resulting storage value. Example: Replaying seeded pool and vault operations matches their accounting storage, while replaying a deployed parent deposit, fork snapshot, and child carry checkpoint matches the child's roots, peaks, leaf counts, unresolved totals, and nullifier roots. Type Safety Enforcement status Reviewed preservation Primary evidence contract interaction reference , event replay model , actual-log storage-equivalence tests","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-01","heading":"EXT-01 Genesis token behavior boundary","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Genesis REP and configured WETH obey the token accounting model defined, per network, by security assumption A21 . Type Conservation Enforcement status External assumption Primary evidence Security assumption A21","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-02","heading":"EXT-02 Callback-safe accounting","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property External ETH or token callbacks observe effects already committed for that action. A required delivery that fails reverts without leaving partial accounting; an explicitly deferrable delivery instead commits the action together with an exactly accounted recipient liability. Example: A fee recipient's fallback observes its claimable fees already cleared, so reentry cannot redeem the same claimable fees twice. Type Safety Enforcement status Reviewed preservation Primary evidence SecurityPool.redeemFees , UniformPriceDualCapBatchAuction.withdrawPendingEthRefund , OpenOraclePriceCoordinator refund paths , rejecting-sponsor refund rollback test Related assumption A22 asset-recipient compatibility","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-03","heading":"EXT-03 ERC-1155 callback safety","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property ERC-1155 receiver callbacks cannot mint beyond pool capacity, alter the amount minted, or reenter the same accounting effect twice. Example: A receiver callback during complete-set minting cannot call back into the pool and reuse the same ETH capacity for a second mint. Type Safety Enforcement status Reviewed preservation Primary evidence createCompleteSet wrapper , createCompleteSet accounting , ERC-1155 receiver acceptance and rejection tests Related assumption A22 asset-recipient compatibility","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-04","heading":"EXT-04 Same-block deadline ordering","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Transaction ordering within a block cannot move an action across a deadline. The equality assignments owned by LIFE-04 depend only on the block timestamp, so mutually exclusive before-deadline and after-deadline actions cannot both succeed at one timestamp. Example: At the OpenOracle settlement deadline, ordering a dispute before settlement in the block still cannot make the dispute valid. Type Safety Enforcement status Contract guard Primary evidence ORA-08 , same-block dispute and settlement ordering , same-block staged execution and expiry ordering , and same-block migration, bidding, and finalization ordering","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"ext-05","heading":"EXT-05 Depth-independent lineage lookups","keywords":[],"path":"reference/invariants.html","sectionTitle":"Reference","summary":"Contract, lifecycle, cross-contract, liveness, and economic properties.","text":"Required property Origin registration, inherited-fork detection during child construction, and direct-claim replay checks do not traverse universe or pool ancestry. Carried-claim payout reads are not covered: their cost grows with fork depth, as LIFE-05 states. Example: At lineage depths 1 and 32, a replay query for the same global deposit id performs the same lineage-registry and claimed-id lookups rather than 1 or 32 parent calls. Type Liveness Enforcement status Reviewed preservation Primary evidence SecurityPoolFactory.getOriginId , getPoolId , and getSecurityPoolHasInheritedForkOutcome , SecurityPoolForker.getEscalationDepositId and isEscalationDepositClaimedDirectly , depth-independent replay gas test","title":"Statoblast and Zoltar invariants","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["assumptions","security","threats","guarantees"],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Statoblast and Zoltar enforce accounting, authorization, and lifecycle rules onchain. Their economic safety and practical liveness still depend on the participant, market, asset, deployment, client, data, Ethereum, and cryptographic assumptions below. An assumption is not a guarantee enforced by the contracts. Each entry says what must remain true, what can fail if it does not, and where the related mechanics are explained. The Statoblast and Zoltar invariants catalog lists contract-enforced properties and their implementation evidence. Participation and coordination Forks, truth, value, and liquidity Oracle correction, inclusion, and operational data Assets, clients, deployment, Ethereum, and cryptography Guarantees deliberately not made","title":"Statoblast security model","topic":"Safety","weight":1},{"fragment":"orientation","heading":"Security-model orientation","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The assets and state at stake are REP , ETH settlement collateral , outcome shares , vault backing, Escalation Game deposits, child-universe accounting, and the integrity of event-derived state. Boundary Examples Trusted protocol components Zoltar, SecurityPools , share tokens, price coordinators , forkers , and their configured delegates. External dependencies OpenOracle , WETH/REP token behavior, Ethereum execution and finality, RPCs, wallets, and proof data. Untrusted actors Traders, vault owners, liquidators, disputers, bidders, settlers, keepers, and indexers. Failure outcomes Reverted calls, delayed transitions, underfunded child repair, stale prices, incorrect external data, or unreconstructable history. The assumptions below explain what must remain true for these assets and transitions to retain their intended safety or liveness properties; they are not additional contract guarantees.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"security-review-orientation","heading":"Reviewing an operational concern","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"To classify an economic or liveness concern, find its external dependency in the grouped assumptions below and follow that entry's mechanics links. Contract-enforced properties are in the invariant catalog; fork-depth gas behavior, for example, is LIFE-05 and EXT-05 . Operator work relies particularly on these assumptions: A06 lifecycle executors A15 intended question selection A20 chain-data and proof availability A22 asset-recipient compatibility A23 verified deployments A24 client, RPC, and wallet integrity A25 safe immutable parameters A26 Ethereum execution and finality A27 cryptographic security A28 account authority","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-participation","heading":"Participation and coordination","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions explain why someone performs the economically useful action instead of merely being permitted to perform it.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a01","heading":"A01 Participants act on risk-adjusted economic incentives","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Enough participants prefer actions with greater expected value after gas, fees, delay, capital lockup, and risk. The model does not rely on altruistic defense. Failure boundary: A nominally profitable liquidation, dispute, bid, migration, or fork defense may not happen when its risk-adjusted return is unattractive. Mechanics: economic roles , liquidation incentives , auction clearing , and oracle incentives .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a02","heading":"A02 Required actions remain worth their operating costs","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For each time-sensitive action, transaction fees, opportunity cost, coordination cost, and capital lockup remain small enough relative to the value protected or earned. Failure boundary: An action can be technically executable but economically abandoned before its deadline. Mechanics: Truth Auction lifecycle , oracle gas parameters , and Escalation Game lifecycle .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a03","heading":"A03 Each economic role has enough independent participants","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Trading, liquidation, escalation, migration, auction bidding, price correction, and settlement have enough non-colluding participants for the relevant action. Secondary-market trading is external to Statoblast. Failure boundary: Thin or controlled participation can remove price discovery, competitive bidding, or an opposing outcome deposit. Mechanics: economic roles , fork coordination , and auction participation .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a04","heading":"A04 Participants can mobilize REP to raise an alarm","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Market participants can mobilize enough REP, from a wallet or from vault backing through its vault owner, to fund an early competing Invalid , Yes , or No deposit and keep the local contest active while additional capital reacts. Wallet REP cannot fund a deposit in a fork-continuation game. Failure boundary: A wrong local outcome can become final before better-capitalized participants enter. Mechanics: escalation resolution , escalation accounting , and escalation guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a05","heading":"A05 Participants value continued access to the supported Statoblast lineage","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The participants whose coordination determines durable use value continued access to the supported Statoblast lineage at least as highly as its configured statoblastSecurityMultiplierBps basis points of the value secured by that lineage. BPS_DENOMINATOR = 10_000 converts that stored value to its human multiplier. Value Statoblast access × BPS_DENOMINATOR ≥ statoblastSecurityMultiplierBps × Value secured Compare one lineage’s continued-use value and secured value at the same pre-attack time. Failure boundary: Participants may rationally abandon, grief, or coordinate away from a lineage whose continued-use value is too small. Mechanics: fork security , fork migration , and Statoblast security boundary .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a06","heading":"A06 At least one executor advances every required public transition","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"An adequately funded participant or service monitors and calls each needed permissionless transition, including liquidation initiation, local escalation deposits and settlement, fork activation, child creation, vault and share migration, auction start and finalization, bid settlement, OpenOracle report settlement, settled-report callback recovery, overflow operation execution, and proof-based claims. Failure boundary: Permissionless state can remain stalled even though no contract authorization prevents progress. Mechanics: lifecycle liveness , fork migration guardrails , and oracle guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-forks","heading":"Forks, truth, value, and liquidity","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions connect onchain branching and accounting to offchain truth judgments, asset value, liquidity, and migration.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a07","heading":"A07 A supported lineage preserves enough aggregate child value","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For each protected Statoblast origin lineage, evaluate the parent and its child-pool continuations in one numeraire at the fork-security decision horizon, before long-run value has fully concentrated on one branch. The sum of traded child-lineage values remains large enough compared with that parent lineage’s pre-fork value under the origin’s immutable statoblastSecurityMultiplierBps . Each child asset is valued in its own branch; unrelated external collateral is not counted again. Value parent lineage ≤ ∑ child ∈ Lineage continuations Value child × BPS_DENOMINATOR statoblastSecurityMultiplierBps lineage Parent and child values use the same origin lineage, valuation source, numeraire, and decision horizon. For multiplier 20_000 BPS , aggregate child-lineage value must be at least twice parent-lineage value; multiplier 30_000 BPS requires three times that value. Failure boundary: Value destruction or fragmentation can make a malicious or unnecessary fork cheaper than the harm it causes. Mechanics: fork economics , fork coordination , and pool migration .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a08","heading":"A08 REP market capitalization approximates economic value","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At the stated valuation time and system scope, REP market capitalization is a sufficiently accurate observable proxy for the discounted cash flow participants expect from REP. Failure boundary: Thin, manipulated, or speculative pricing can overstate the economic value securing open interest. Mechanics: REP economics and economic backing claims .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a09","heading":"A09 Users value the universes they judge truthful","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users prefer the universe or universes they judge truthful, so economic activity and durable asset value concentrate there. Unlike A07’s fork-security decision horizon, this assumption describes the later, durable allocation of value after users coordinate. Value before fork ≈ Value truthful universe When several branches remain plausibly truthful, document the value split instead of assuming one winner. Failure boundary: Coordination on a false branch, or durable fragmentation across branches, defeats the value-concentration security argument. Mechanics: branch non-guarantees and pool fork migration .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a10","heading":"A10 Participants can access timely outcome evidence","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users can obtain enough reliable real-world evidence before the relevant protocol deadline to judge which universe is truthful. Failure boundary: Missing, delayed, or conflicting evidence can split honest capital or let a false local outcome become final. Mechanics: question encoding , invalid outcomes , and local resolution .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a11","heading":"A11 Migration is operationally practical","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Users, exchanges, interfaces, custodians, and other integrations are willing and able to migrate assets and state into the child universe or universes they support during the applicable windows. Failure boundary: Supported branches can remain illiquid or undercollateralized because economic claims and backing do not move there. Mechanics: REP splitting , pool migration , and share migration guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a12","heading":"A12 Truth Auctions can convert supported child REP efficiently","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"When repair is needed, enough Truth Auction demand can buy some supported child REP for ETH at an acceptably small discount and operating cost. This does not assume that the full repair target is raised. Failure boundary: Weak or strategically withheld demand leaves the child operational with impaired collateral. Mechanics: auction lifecycle , clearing , and repair accounting .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a13","heading":"A13 REP is sufficiently liquid","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants can acquire or sell the required REP quantities without price impact or delay large enough to invalidate reporting, disputing, liquidation, auction, or migration economics. Failure boundary: Capital may exist in principle but cannot be assembled at a usable price before the deadline. Mechanics: economic roles , escalation , and oracle positions .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a14","heading":"A14 REP economic value exceeds the open interest it secures","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"For a stated pool, lineage, or system scope at one timestamp, open interest and REP discounted cash flow are valued in the same numeraire, and REP discounted cash flow remains strictly greater. For a pool-level evaluation, open interest means the pool’s protocol-accounted ETH collateral unless the analysis explicitly names a broader exposure measure. The REP supply and price basis must also be stated; market capitalization is the observable proxy in A08 . This external relationship is separate from each pool’s onchain multiplier-adjusted REP backing check. Open Interest < Discounted Cash Flow REP Record scope, timestamp, common numeraire, price source, REP supply basis, and open-interest definition when evaluating this strict inequality. Failure boundary: REP holders may rationally accept or cause losses larger than the durable REP value placed at risk. Mechanics: security pools , liquidation backing , and oracle exposure analysis .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a15","heading":"A15 Question selection remains aligned with user intent","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Interfaces and users verify the immutable question ID and metadata when selecting a market or pool, and the question has evidence and wording from which participants can reach an outcome or intentionally choose Invalid . Failure boundary: Unverified selection can route users and capital to an unintended market or pool, while ambiguous wording or unavailable evidence can split local outcome coordination. Mechanics: UNI-02 and question identity .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-oracle","heading":"Oracle correction, inclusion, and operational data","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions cover truthful REP/ETH price discovery, deadline access, capital, independent correction, and the offchain information required to act. OpenOracle's optional flexible-escalation and halt-only-fee flags can change a corrector's required capital and net incentive, so a deployment that enables them must evaluate the same assumptions against its configured flag set.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a16","heading":"A16 Deadline transactions can obtain Ethereum inclusion","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Honest users can submit competitively priced Ethereum transactions and obtain canonical inclusion within every relevant dispute, escalation, migration, auction, staging, and settlement window. Each onchain comparison assigns the exact deadline timestamp to one phase. Same-block ordering cannot move an action across that boundary: users must target the phase valid at the block timestamp rather than rely on transaction ordering to extend an expired window. Failure boundary: Censorship or congestion lasting through a deadline can finalize a wrong report or prevent a supported action. Mechanics: deadline invariants , auction windows , and oracle censorship model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a17","heading":"A17 OpenOracle has an available, adequately capitalized corrector","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At least one OpenOracle participant continuously monitors pending REP/ETH reports, can identify candidate errors using the reference market in A19 , can fund the scenario-dependent WETH and REP replacement position plus transaction costs, and can obtain inclusion before settlement. The participant's net incentive to perform the correction is the separate boundary in A18 . Failure boundary: An incorrect report can settle and authorize price-sensitive pool actions when no capable participant detects, funds, and includes a correction. Mechanics: REP/ETH oracle , correction incentives , and attack model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a18","heading":"A18 At least one available corrector has an independent net incentive","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"At least one participant satisfying A17 is not under common control with the sponsor-funded coordinator reporting path, does not share the manipulation payoff, and is not bribed or compensated. The participant's net payoff from correcting is strictly greater than its net payoff from leaving the harmful report uncorrected. Two external submissions are not required for every request. Failure boundary: A sponsor-controlled, bribed, or economically indifferent corrector can make the contestable report path behave like a single trusted reporter. Mechanics: settlement validation scope , economic tradeoffs , and oracle invariants .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a19","heading":"A19 A robust reference market makes harmful REP/ETH errors correctable","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Independent participants can observe a manipulation-resistant reference REP/ETH price. Every price error large enough to unlock a security-relevant pool action also leaves a correction opportunity that remains profitable after actual gas, prevailing priority fees, OpenOracle fees, price impact, and required capital lockup. Failure boundary: A harmful deviation below the profitable correction threshold, or a manipulated/illiquid reference market, can settle without an economically rational challenge. Mechanics: report sizing , external-payoff model , and settlement limits .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a20","heading":"A20 Canonical chain data and proof construction remain available","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants can access reorg-aware Ethereum history, recognized contract addresses, OpenOracle report state, and the event data needed to construct carry and nullifier proofs before use. Failure boundary: A valid dispute, settlement, migration, or inherited claim can become practically unavailable even while its contract entrypoint remains live. Mechanics: event replay , carry proofs , and operator orientation .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumptions-technical","heading":"Assets, clients, deployment, Ethereum, and cryptography","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These assumptions define the technical foundation below the protocol’s onchain guards.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a21","heading":"A21 Genesis REP and configured WETH obey the required accounting model","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Genesis REP and configured WETH move exactly the requested base units, use 18 decimals, return supported ERC-20 values, and do not rebase, charge transfer fees, invoke unexpected callbacks, blacklist protocol contracts, pause required transfers, or permit unauthorized minting. WETH remains redeemable 1:1 for ETH, the genesis theoretical supply is accurate, and the hard-coded Constants.BURN_ADDRESS burn sink remains inaccessible. These are external assumptions on both networks, with one exception: on Sepolia the reviewed GenesisReputationToken enforces genesis REP issuance and transfer behavior, provided A23 verifies its deployed bytecode and wiring and A26 preserves Ethereum execution. Sepolia WETH is Uniswap's published contract, which the deployer verifies only by runtime-code hash. Canonical child REP is the reviewed ReputationToken contract and adds no external-token assumption. Failure boundary: Origin-pool, genesis-fork, or oracle accounting can overstate balances, backing, burned supply, or WETH value. Mechanics: EXT-01 and oracle token pair .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a22","heading":"A22 Participant-controlled recipients can accept required asset deliveries","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Vaults, oracle sponsors, traders, share holders, and other caller-controlled recipients use addresses that accept native ETH when claiming fees, collateral, or proceeds. Truth-auction settlement instead credits bidder-specific pull escrow without calling the bidder; the bidder must accept ETH only when withdrawing that credit. Contract recipients also return the required ERC-1155 receiver selector when complete-set creation, share migration, or an outcome-share transfer delivers tokens to them. A rejected ETH pull or push reverts that transfer, and a rejected ERC-1155 callback reverts the mint or transfer and its surrounding protocol action. No protocol path can force a rejecting address to accept a later delivery or redirect every payout or mint. Failure boundary: A contract account that rejects ETH or the required ERC-1155 callback can strand its own payout or make its complete-set, migration, transfer, or claim action unavailable even while protocol-wide accounting remains safe. Mechanics: ETH callback safety , ERC-1155 callback safety , share-token receipt , auction refunds , oracle request refunds , and security pool guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a23","heading":"A23 Users select verified canonical deployments","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The reviewed release is built reproducibly with its pinned compiler and toolchain configuration. The deterministic manifest freshness check rejects address drift, while the deployment plan verifies pinned runtime-code hashes for planned contracts and bootstrap descendants. Users and integrations must still verify post-deployment wiring, factory and forker provenance, pool lineage, question ID, and the manifest against the intended network. Constructor admission alone is not a safety proof. Failure boundary: Toolchain drift, unavailable or mismatched reviewed hashes, permissionless lookalike instances, wrong dependencies, or unintended lineage and question wiring can bypass the reviewed protocol even when the selected bytecode functions as configured. Mechanics: release posture , deployment status , compiler configuration , OpenOracle build provenance , and authority invariants .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a24","heading":"A24 Clients, RPCs, and wallets preserve user intent and canonical state","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Interfaces, indexers, RPC providers, and wallet software return canonical, reorg-aware state; construct and display the intended chain, target, calldata, parameters, and ETH value; and submit only transactions the user authorizes. Users verify transaction previews rather than treating an application label as an onchain guarantee. Failure boundary: Compromised or stale offchain software can misroute signatures or capital, hide deadlines or events, or cause users to authorize valid but unintended calls without violating contract guards. Mechanics: deployment discovery , contract interactions , and operator verification .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a25","heading":"A25 Immutable parameters preserve economic and executable security margins","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"The selected parameter relationships keep the fork threshold and fork haircut economically meaningful, the start bond affordable, the pool multiplier and the pool-held-REP branch multiplier derived from it ( BAL-04 ) large enough for their distinct coverage roles, the oracle target error profitable to correct after fees and gas, dispute and settlement windows usable, and callback and transition gas executable. The Statoblast pool statoblastSecurityMultiplierBps is distinct from openOracleSecurityMultiplierBps . Failure boundary: Weak or internally inconsistent immutable parameters can defeat the economic or liveness argument even when the canonical contracts function exactly as configured. Mechanics: Statoblast pool parameters , fork economics , liquidation economics , oracle parameters , and oracle attack model .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a26","heading":"A26 Ethereum preserves the execution environment the protocol relies on","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Ethereum continues to provide correct EVM execution and atomic rollback, sufficient canonical finality, usable timestamp and block.basefee semantics, and block gas limits and gas schedules under which every mandatory immutable transition remains executable. Failure boundary: Deep reorganizations, invalid state execution, adversarial time behavior, or gas repricing can reverse accepted state or strand required transitions. Mechanics: contract interactions , atomicity and deadlines , and Escalation Game lifecycle .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a27","heading":"A27 Ethereum cryptographic primitives remain secure","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Keccak-256 remains collision- and preimage-resistant at the truncated widths used by the protocol, and CREATE2 identity remains sound. secp256k1 ECDSA signatures remain unforgeable with correct EOA signer recovery for Ethereum transactions and EIP-712 authorizations. OpenOracle's fixed Permit2 singleton and LiquidationApprovalRegistry.permitLiquidationApproval , through SignatureValidation , additionally validate either an EOA signature or an ERC-1271 contract-account signature correctly. OpenOracle fixes the Permit2 address, requires the exact permitted amount, sends the requested tokens to itself, and constructs the witness from the beneficiary, relayer, token owner, and intent. Permit2 defines the EIP-712 domain, deadline, permitted-amount ceiling, unordered-nonce replay protection, and EOA/ERC-1271 signature validation. Verification under A23 must cover the pinned Permit2 implementation at that fixed address. Failure boundary: Forged identities, colliding questions or universes, false carry proofs, forged EOA transactions, incorrect EOA recovery or ERC-1271 acceptance, or broken domain and nonce enforcement can violate otherwise-correct guards or authorize an unintended token transfer. Mechanics: universe identity , proof hashing , Permit2 deposit authorization , Permit2 signature interface , liquidation-approval signature validation , pinned Permit2 implementation provenance , and deterministic address guardrails .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"assumption-a28","heading":"A28 Participants retain control of account authority","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"Participants protect the private keys, signing devices, session permissions, and delegated ERC-20 or ERC-1155 approvals that authorize their accounts. Account recovery and custody arrangements do not give an unintended party effective control during a security-sensitive window. Failure boundary: A stolen key, compromised signer, or overbroad approval can authorize valid but unwanted transfers, deposits, bids, migrations, or configuration changes without violating a contract guard. Mechanics: transaction authority , security pool guardrails , and account-authority monitoring .","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"excluded-guarantees","heading":"Guarantees deliberately not made","keywords":[],"path":"reference/security-model.html","sectionTitle":"Reference","summary":"Normative participant, market, deployment, client, and cryptographic assumptions.","text":"These outcomes remain possible without contradicting the security model. They should be included in user, operator, and integration risk disclosures. EG01. Zoltar creates valid branches but does not enforce that the fork question is relevant to a user, establish the objectively truthful branch, obtain user consent to a fork, or force users to coordinate on one branch. EG02. A Truth Auction may raise less than its repair target; the child then activates with migrated collateral plus accepted auction ETH. EG03. OpenOracle report liquidity does not cap the notional value of operations using an accepted price, and settlement does not prove external price correctness. EG04. A participant with unbounded capital can keep funding valid disputes and delay the sponsor lane indefinitely; no bounded coordinator-availability claim is made. EG05. The immutable protocol has no administrator who can pause, upgrade, roll back, or rescue an unsafe deployment after launch. EG06. Escalation principal and expected rewards are not senior to open-interest repair. A child Truth Auction may proportionally reduce them, and a losing escalation claim pays its committed depositor nothing.","title":"Statoblast security model","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["testnet","Sepolia","deploy","private key","spending limit"],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"How-to guide The testnet deployer installs the complete deterministic Zoltar and Statoblast infrastructure in one run. It is safe to rerun: a contract already at its target address is skipped only when its runtime bytecode matches, and an unexpected contract at a target address stops the deployment.","title":"Deploy testnet contracts","topic":"Operations","weight":1},{"fragment":"before-you-deploy","heading":"Before you deploy","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Complete the repository setup in the README . Use a dedicated testnet account. To size its balance without deploying, run the deployer once with --max-total-cost-eth=0.000001 : its preflight aborts and the abort message reports the upper-bound cost of the missing steps. A normal run prints the same figure in its Estimated maximum cost log line. Use an HTTPS RPC endpoint. Loopback HTTP endpoints are accepted for local test networks. Make sure the deployer account has no pending transactions. If the testnet rejects the fixed raw legacy transactions that install the canonical CREATE2 deployer and the proxy deployer, make sure both are already present as predeploys. Sepolia is the default target (chain ID 11155111 ). A different testnet must support EIP-1559, the Cancun opcodes used by Zoltar and Uniswap V4, and the Osaka CLZ opcode used by the compiled contracts. The deployer rejects Ethereum mainnet (chain ID 1 ).","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"deploy-with-github-actions","heading":"Deploy with GitHub Actions","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Use the Deploy Testnet Contracts workflow for a deployment from main . Create a protected GitHub environment named testnet-deployment . Add the deployer's private key as the environment secret TESTNET_DEPLOYER_PRIVATE_KEY . Optionally add ETHERSCAN_API_KEY as well; without it post-deploy verification skips Etherscan. Open Actions → Deploy Testnet Contracts → Run workflow . Select main , complete the inputs, and enter DEPLOY as the confirmation. Review the job summary for each planned deployment's result and address. It includes transaction hashes for contracts deployed during the run. The job runs only when the workflow is started from main and the confirmation is exactly DEPLOY . Otherwise GitHub skips it without an error and no summary is produced; if the run shows a skipped job, check the branch and confirmation and start it again. Use a public RPC URL without credentials. Workflow inputs are stored in GitHub metadata and are not secret.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"deploy-locally","heading":"Deploy locally","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Load PRIVATE_KEY from a secret manager or a hidden prompt. Never paste the key into a command, because the command may be saved in shell history. In Bash: read -rsp 'Testnet deployer private key: ' PRIVATE_KEY \\ && echo && export PRIVATE_KEY Run the deployer with an explicit RPC endpoint and spending limits: bun run deploy:testnet -- \\ --rpc-url=https://rpc.example \\ --chain-id=11155111 \\ --max-fee-per-gas-nanoeth=100 \\ --max-total-cost-eth=20 Remove the key from the shell when the command finishes: unset PRIVATE_KEY The deployer reads the exported PRIVATE_KEY automatically. You can instead pass --private-key=0x... directly, but then the complete command, and therefore the key, may be saved in shell history. Run bun run deploy:testnet -- --help for all options. Options other than --private-key also accept uppercase arguments after -- or environment variables. Input Default Purpose RPC_URL / --rpc-url Required RPC endpoint for the target network CHAIN_ID / --chain-id 11155111 Expected decimal chain ID MAX_FEE_PER_GAS_NANO_ETH / --max-fee-per-gas-nanoeth 100 Rejects higher RPC fee suggestions. If a canonical deployer is missing, the run aborts when this is below 100 , the fixed gas price of the deployers' raw transactions. MAX_TOTAL_COST_ETH / --max-total-cost-eth 20 Caps the conservative preflight estimate and transaction budget PRIVATE_KEY / --private-key Required 0x -prefixed 32-byte deployer key The defaults are authorization limits, not a spend forecast or a required balance. Before sending a transaction, the command checks the RPC chain ID, EVM features, EIP-1559 support, canonical deployer compatibility, expected bytecode, and fee limits. It then estimates only the missing deployment steps. If the conservative estimate exceeds MAX_TOTAL_COST_ETH , it exits; on a live network nothing has been funded or deployed at that point, while an Anvil development node may already have received the replayed Uniswap contracts. Per-transaction checks enforce the same budget while the deployment runs. The run logs each planned contract with Status: deployed , Status: already deployed , or Status: ready (installed without a submitted transaction), then verifies the bootstrap support contracts. A step that fails logs Status: failed and stops the run. When deployment succeeds, the command runs source verification for the target chain. Only Sepolia ( 11155111 ) is verified; any other chain logs that it has no known explorer support and succeeds. Verification submits the addresses in the tracked docs/sepolia-deployment-addresses.json manifest, not addresses discovered during the run. Blockscout and Sourcify run without a key; Etherscan runs only when ETHERSCAN_API_KEY is set and is otherwise skipped with a message. A verification failure makes the command exit nonzero even though the contracts are deployed , and prints the command to retry on its own: bun run verify:contracts -- --chain-id=11155111 . Treat a nonzero exit as \"check which stage failed\" rather than \"nothing was deployed\".","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"recover-an-interrupted-run","heading":"Recover an interrupted run","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"Wait for all pending transactions to settle, then rerun the same command. The deployer revalidates completed contracts and resumes with the first missing step.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"what-gets-deployed","heading":"What gets deployed","keywords":[],"path":"how-to/deploy-testnet-contracts.html","sectionTitle":"How-to guides","summary":"Install the deterministic infrastructure on Sepolia from GitHub Actions or a local shell.","text":"deterministic genesis REP the canonical CREATE2 deployer, the proxy deployer, and Permit2 a deterministic Uniswap V3 SwapRouter on chains other than Sepolia, deterministic WETH and a complete Uniswap deployment (V3 factory, QuoterV2, V4 PoolManager, and V4 Quoter) the Zoltar and Statoblast protocol factories and their bootstrap support contracts the Trading factory and router, at the canonical 0.30% fee The command does not create Uniswap pools or add liquidity; protocol factories create market-specific contracts later, when those features are used. Uniswap sourcing per chain is listed in the contract inventory , and the deployment status reference explains how clients read which steps are installed. The bots read core addresses from the tracked mainnet and Sepolia manifests, so on testnets they work only against Sepolia and Sepolia replays such as a local Anvil node with chain ID 11155111 . A deployment to another testnet is not usable by the bots until that chain has a generated manifest.","title":"Deploy testnet contracts","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["release","launch","checklist","genesis REP","manifest"],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"How-to guide Follow this guide before tagging a Zoltar and Statoblast release. It lists the checks that must pass before the tag and, for Sepolia and deterministic testnets, the genesis REP review that determines every deterministic address there. Mainnet uses the existing REPv2 token and deploys no genesis REP.","title":"Prepare a protocol release","topic":"Operations","weight":1},{"fragment":"immutable-protocol-release-posture","heading":"Know what a release cannot do","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"The contracts are immutable: no operator can pause, upgrade, roll back, or rescue them after deployment, so a release publishes verifiable provenance instead (commit and tag, deterministic addresses, CI and QA results, production UI artifact hash, known limitations) and never describes a UI deployment as an emergency control. See EG05 .","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"launch-release-checklist","heading":"Run the release checklist","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"From a fresh dependency install ( bun install --frozen-lockfile ), run bun run check:mainnet-deployment:generated . It fails when either generated deployment manifest is stale. If so, regenerate both manifests with bun ./tooling/contracts/check-mainnet-deployment.mts --write , which only rewrites mainnet-deployment-addresses.json and sepolia-deployment-addresses.json ; review the diff, then rerun the check. Run bun run ui:build:prod . It repeats the manifest check, so it fails if a manifest is still stale. Confirm the build used the pinned compiler configuration in solidity/ts/compile.ts , the exact tool versions in solidity/package.json , and the imported OpenOracle profile in UPSTREAM.md . Review the pinned runtime-code hashes: the EXPECTED_*_RUNTIME_CODE_HASHES maps in ui/zoltarShared/ts/protocol/deployment.ts and ui/statoblastShared/ts/protocol/deployment.ts . Check them in three ways, then publish the reviewed hashes with the release: Run bun ./tooling/testing/bun-test.mts --preload ./bun-test-setup-ui.ts ui/zoltar/ts/tests/protocol/deployment.test.ts ui/statoblast/ts/tests/protocol/deployment.test.ts . It confirms that a clean local build still matches the pinned hashes of the directly compiled steps (the deployment status oracle, Multicall3, ZoltarQuestionData, and five Statoblast artifacts); it does not cover the other pinned contracts. On Sepolia, rerun bun run deploy:testnet . It checks the runtime code of every installed contract against its pinned hash. It is not read-only: it needs PRIVATE_KEY , deploys any missing step, and then runs explorer verification. For any other deployed address, compare the keccak-256 hash of its eth_getCode result with the pinned hash by hand before marking the release canonical. Push the final tag only after the CI gate succeeds on the same commit. The tag must match v (for example v12 ); the Version deploy workflow rejects any other form. That workflow reruns CI, builds the InterPlanetary File System (IPFS) publisher image, reads the content identifier (CID) from that image, checks only that it has the bafy… form, and creates or updates the GitHub release with that CID in its notes. Confirm the release exists and records the CID before announcing. In the production UI release notes, state that ?simulate=1 is a browser-local sandbox. Treat a stale, unavailable, or unsupported live quote as a blocker for the affected client action; never substitute a simulation price for it.","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"genesis-rep-deployment","heading":"Review genesis REP allocations (Sepolia and deterministic testnets)","keywords":[],"path":"how-to/launch-a-release.html","sectionTitle":"How-to guides","summary":"The pre-tag checklist, runtime-hash review, and the testnet genesis REP review.","text":"Sepolia genesis REP allocations are canonical source data in sepoliaRepAllocations.ts . The configured 11 million REP mint cap is divided equally among the listed holders; adding a holder automatically reduces every holder's allocation. Integer division may leave the total minted supply below the cap by less than one attoREP per holder. Review both the holder list and the computed total before deployment. The constructor of GenesisReputationToken rejects an empty list, a zero address, a repeated holder, a zero balance, and a total above the cap. There is no administrator, post-deployment mint, allocation correction, or recovery entrypoint, so fix an incorrect allocation in the source list before deployment and then regenerate the deterministic manifests. Because constructor arguments are part of CREATE2 init code, any allocation change produces a new genesis REP address and new addresses for every deployment step whose constructor wiring depends on it. Never continue a deployment from a manifest generated for a different allocation list.","title":"Prepare a protocol release","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["monitoring","assumptions","operators","signals"],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"How-to guide Check that the economic and liveness assumptions behind a deadline-bearing or price-sensitive action still hold before you take it, and keep checking until its last deadline. The contracts cannot tell you when such an assumption has stopped holding.","title":"Monitor security assumptions","topic":"Operations","weight":1},{"fragment":"how-to-use","heading":"Check an action's assumptions","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"List the assumptions the action depends on. The security model lists which assumptions protect which mechanism. Find the rows for those assumptions in the table below . Take each row's reads for the same lineage , pool, and block as the action. Express the values in one numeraire and cover the action horizon . If a read is weak or unavailable, apply the row's response before proceeding. Repeat the reads on the row's cadence until the action's last deadline has passed. Most on-chain reads are also indexed by augurScan under /operations/… (see the augurScan README ). The liquidator and OpenOracle arbitrager bots in bots/ show live pool, vault, and report state in their dashboards.","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"terms","heading":"Terms used in the table","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"Numeraire The one unit of account, such as ETH, in which you express every value you compare. Action horizon The period until the action's last deadline. Corrector An account that disputes an incorrect OpenOracle report; see A17 . Callback-recovery candidate A price coordinator whose pending report OpenOracle has already settled; see settlement recovery . Overflow operation A staged operation outside the next settlement callback's batch of four; see execution batches .","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"assumption-monitoring","heading":"Reads, cadence, and response for each assumption","keywords":[],"path":"how-to/monitor-security-assumptions.html","sectionTitle":"How-to guides","summary":"Check the assumptions behind an action: what to read, how often, and how to respond when one is weak.","text":"Assumptions What to read Review cadence Response when the boundary is weak or unknown Executor incentives and participation — A01, A02, A03, A06 Liquidation candidates and net reward: liquidator bot dashboard Dispute opportunities and net reward: OpenOracle arbitrager dashboard Active reporters, correctors, escalation depositors, and Truth Auction bidders: augurScan /operations/reports , /operations/escalations , /operations/auctions Callback-recovery candidates: coordinator pendingReportId , then the settlement timestamp in OpenOracle storedGame(reportId) ; anyone can clear one with recoverSettledPendingReport() Overflow operations: coordinator getActiveStagedOperationCount() minus getPendingSettlementOperationCount() Continuously for deadline-bearing flows; before launch and after parameter or gas-regime changes Fund or arrange independent executors, reduce exposed value, or disclose that the affected transition may stall Fork lineage value and migration readiness — A05, A07, A09, A11 Fork start: Zoltar getForkTime(universeId) Migration progress: augurScan /operations/forks Parent and child REP prices: market quotes in one numeraire Custodian, exchange, interface, and proof-tool readiness: each party's published support statement (no on-chain read) Before a fork-security claim and throughout migration and coordination windows Do not claim fork deterrence, practical migration, or value concentration; narrow supported lineage and exposure REP value and liquidity versus secured exposure — A08, A13, A14 Theoretical REP supply : Zoltar getUniverseTheoreticalSupplyAttoRep(universeId) Pool open interest : settlementCollateralAttoEth in getPoolAccountingSnapshot() Pool-held REP: getTotalPoolHeldAttoRep() Cached REP/ETH price: coordinator lastPrice REP depth and price impact: arbitrager Uniswap venue quotes Pool and vault risk: augurScan /operations/risk REP discounted cash flow: off-chain valuation (no on-chain read) At launch, continuously while open interest exists, and after material price, supply, liquidity, or exposure changes Cap or stop new exposure in clients and disclosures; do not describe REP backing as economically sufficient Outcome evidence and escalation funding — A04, A10 Escalation Game deadline: getEscalationGameEndDate() Outcome funding: getOutcomeBalancesAttoRep() and getBindingCapitalAttoRep() , or augurScan /operations/escalations REP available to fund a correction: wallet REP balanceOf (wallet deposits, except in a game carried across a fork) and vault REP backingUnitsToAttoRep(securityVaults(vault).repBackingUnits) of each ready account Outcome evidence: where each source publishes (off-chain) From question creation through local resolution and any fork window Mark the market or action impaired, surface the deadline, and avoid asserting that honest local correction remains fundable Truth Auction demand — A12 Truth Auction bids: auction getActiveTickPage(offset, limit) and previewFinalization() , or augurScan /operations/auctions REP/ETH depth and expected discount: arbitrager Uniswap venue quotes Bidder gas cost: RPC eth_feeHistory Before and during every repair auction Disclose likely incomplete repair and plan operation of the child at only migrated collateral plus accepted auction ETH Transaction inclusion and Ethereum execution — A16, A26 Base and priority fees: RPC eth_feeHistory Block gas limit: latest block Reorg history: augurScan /operations/integrity Escalation deadline: getEscalationGameEndDate() Truth Auction close: auction auctionStarted plus one week Migration close: forker forkData(pool) forkActivationTime plus eight weeks Margin: each deadline minus expected inclusion delay Continuously while a deadline or mandatory transition is live Raise transaction fees where rational, use independent submission paths, and disclose missed-deadline or stranded-transition risk REP/ETH price correction — A17, A18, A19 Pending report: coordinator pendingReportId , then OpenOracle storedGame(reportId) Report outcomes: coordinator PriceRequested , PriceReported , and PriceReportRejected events, or augurScan /operations/reports Independent correctors: whether any, such as an operator running the OpenOracle arbitrager , reports disputes profitable after fees, gas, and price impact Corrector inventory: wrapped Ether (WETH) and REP balances Continuously while a report is pending or a cached price can authorize operations Block or discourage new price-sensitive operations and disclose that an incorrect report may settle Token behavior and recipient compatibility — A21, A22 Sepolia genesis REP code: keccak-256 of eth_getCode against reputationToken in EXPECTED_SEPOLIA_DEPLOYMENT_RUNTIME_CODE_HASHES ( ui/zoltarShared/ts/protocol/deployment.ts ) Sepolia WETH code: the same against sepoliaPublished.weth.runtimeCodeHash in scripts/artifacts/uniswap-deployment.json Mainnet REPv2 and WETH code: an externally sourced reference hash (no repository pin) Sepolia genesis REP supply: shared/zoltar/ts/deployment/sepoliaRepAllocations.ts against getTotalTheoreticalSupply() WETH redeemability and recipient ETH and ERC-1155 acceptance: a test transfer from a disposable account At deployment verification and before first use of a new recipient or integration Reject the deployment or incompatible recipient; do not rely on redirected recovery Deployments, clients, data, and keys — A20, A23, A24, A27, A28 Manifest freshness: bun run check:mainnet-deployment:current Explorer source verification: bun run verify:contracts -- --chain-id= Code presence: getDeploymentMask() Runtime hashes: release checklist Event replay: a second RPC or augurScan /operations/integrity Signers, typed-data domains, nonces, and approvals: each operator's key store At release, on every environment or account change, and continuously for indexers Stop signing or operating, reject an unverifiable deployment, revoke compromised authority where possible, and re-establish canonical state from independent sources Question selection — A15 Question creation, end date, and labels: ZoltarQuestionData questionCreatedTimestamp , getQuestionEndDate , and getOutcomeLabels Evidence plan and pool relevance: off-chain review Before pool selection Reject or warn on the selection; do not represent an admitted question as relevant or resolvable Immutable parameters — A25 Deployed configuration: manifest protocolConfig Fork and non-decision thresholds: Zoltar getForkThresholdAttoRep(universeId) and getNonDecisionThresholdAttoRep(universeId) Oracle costs: coordinator getRequestPriceCostAttoEth() and getSettlementCallbackGasLimit() Required relationships: A25 Before deployment and after any change in external gas or market conditions used by the model Treat the immutable deployment as unsupported; there is no administrative parameter repair","title":"Monitor security assumptions","topic":"Operations","weight":0},{"fragment":"","heading":"","keywords":["operators","guardrails","recovery","edge cases"],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Reference What a Statoblast security pool , share migration, Escalation Game , fork migration, Truth Auction , or REP/ETH price coordinator will and will not accept, one subsystem at a time. Statoblast is the prediction-market layer built on the Zoltar fork oracle; see the system overview . Every rule names the contract source that enforces it, so operators, indexers, and interface maintainers can check it against the exact Solidity. The invariant catalog connects these local guardrails to cross-contract conservation, liveness, and the stated economic assumptions; the security model is normative for external assumptions. Release procedure lives in Prepare a protocol release , assumption monitoring in Monitor security assumptions , and the remaining support contracts in the contract inventory .","title":"Subsystem guardrails","topic":"Safety","weight":1},{"fragment":"security-pool-guardrails","heading":"Security pool guardrails","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"The following pool-creation, minting, withdrawal, and direct-ETH rules are enforced by contracts. Participant-controlled payout and share-receiving addresses must satisfy A22 asset-recipient compatibility . Deterministic identity depends on A27 cryptographic security , while vault and token authority depends on A28 account authority . Area Implementation behavior Source Origin multiplier deployOriginSecurityPool requires statoblastSecurityMultiplierBps above 10,001 BPS ( Multiplier must exceed 10001 BPS ). SecurityPoolFactory.sol Origin question The question must exist ( Question does not exist ), must not have ended ( Question has already ended ), and must have exactly two categorical labels, Yes then No ( Question must have two outcomes , First outcome must be Yes , Second outcome must be No ). Statoblast adds Invalid as the third trading and resolution outcome. SecurityPoolFactory.sol , ShareToken.sol , BinaryOutcomes.sol Origin universe The universe must be unforked ( Universe already forked ) and have a REP token ( Universe REP token missing ). SecurityPoolFactory.sol Origin uniqueness SecurityPoolFactory allows one pool per origin and universe ( Security pool origin and universe already claimed ). The origin is the question, origin universe, security multiplier, and oracle priority fee. SecurityPoolFactory.sol Start-bond admission A new origin's non-decision threshold must exceed its start bond ( Escalation threshold too low ). ESC-13 owns the start-bond formula and its later clamp. SecurityPoolFactory.sol , SecurityPoolUtils.sol Vault REP floor A zero configured vault REP floor selects the live universe theoretical REP supply divided by 100,000; a nonzero constructor value is the exact override. SecurityPoolUtils.sol Commitment floor minimumSecurityBondDebtAttoEth , the smallest nonzero commitment a liquidation may leave with its target or give its receiver, is a nonzero factory constructor argument ( Minimum security bond debt zero ). The default deployment configuration sets it to 1 ETH. SecurityPoolFactory.sol , SecurityPoolOperationsDelegate.sol Deployment history The factory records security-pool deployments and exposes paged deployment-history reads for indexers and UIs. SecurityPoolFactory.sol Pool salt SecurityPoolFactory derives securityPoolSalt = keccak256(abi.encode(parent, universeId, questionId, statoblastSecurityMultiplierBps, initialReportPriorityFeeAttoEthPerGas)) , using a zero parent for an origin. SecurityPoolFactory.sol Coordinator and auction addresses The coordinator and child Truth Auction factories each hash securityPoolSalt with their caller ( SecurityPoolFactory ) for their CREATE2 salt. OpenOraclePriceCoordinatorFactory.sol , UniformPriceDualCapBatchAuctionFactory.sol Pool address The pool deployment worker uses literal CREATE2 salt zero; its address varies through the full constructor init-code hash, which contains the pool wiring. SecurityPoolDeployer.sol Share-token address An origin share token uses originId , the keccak256 hash of the ABI-encoded questionId , statoblastSecurityMultiplierBps , initialReportPriorityFeeAttoEthPerGas , and originUniverseId in that order, directly as its CREATE2 salt, while factory ownership, Zoltar, and question ID remain in its init code. Children reuse that lineage token and inherit its priority fee. SecurityPoolFactory.sol , ShareTokenFactory.sol Share-token salt squatting Direct ShareTokenFactory callers cannot reserve the canonical origin-pool share-token address. CREATE2 includes constructor arguments in the init-code hash, and the share token owner is msg.sender , so a direct caller using the canonical salt deploys a caller-owned token at a different address than the SecurityPoolFactory deployment. ShareTokenFactory.sol , ShareToken.sol Complete-set capacity Like other operational flows, complete-set minting first requires an unforked universe ( Forked ) and an Operational pool ( Pool inactive ). It then reverts with Fork await while a fork continuation is pending, Escalation mint closed once an Escalation Game exists, Settlement unavailable for zero ETH or an inherited fork outcome, Exchange rate undefined when the deposit converts to no shares or outstanding shares have no collateral, and Over capacity when settlement collateral plus the deposit would exceed the pool's total underwriting commitments . Minting reads no oracle price or REP backing; BAL-03 states the rule. SecurityPool.createCompleteSet , SecurityPoolSettlementDelegate.createCompleteSet Fee eligibility Fee-eligible underwriting commitment includes vault-assigned commitments and sold Truth Auction commitments awaiting claim. BAL-08 owns the ledger invariant. SecurityPool.sol Fee reserve and rounding Settlement-collateral decay first enters an unallocated reserve; vault checkpoints and auction claims move only whole attoETH into totalClaimableVaultFeesAttoEth and carry sub-attoETH remainders forward. totalAccruedFeesAttoEth() returns reserve plus assigned claimable fees. Index carry is cleared when pool financials are installed or a vault's underwriting commitment changes or moves by liquidation; assigning finalized-auction commitment to its winning vault preserves it. SecurityPool.updateSettlementCollateral , SecurityPool.updateVaultFees , SecurityPool._clearFeeIndexRemainder Terminal fee reserve After a fork ends accrual and every eligible allocation is reconciled, the next vault fee checkpoint returns unclaimable whole reserve attoETH to settlement collateral. Fee cutoffs per pool and epoch are specified in the updateSettlementCollateral reference . SecurityPool.sol Retention-rate updates Retention-rate updates no-op when the pool is not Operational ; otherwise utilization divides tracked collateral by total underwriting commitments, independent of price and backing. No commitments or any Escalation Game, open or resolved, select the maximum retention rate. Unclaimed sold auction commitment therefore already affects utilization and fee accrual. A later claim changes only its vault assignment, not fee eligibility, total commitment, minting capacity, or retention solely because of that claim. SecurityPool.sol Multiplier-preserving REP outflows withdrawRepFromVault rejects withdrawal while the vault still has REP escrowed in an escalation game. Withdrawals and new escalation deposits independently preserve multiplier-adjusted REP backing for the affected vault and aggregate pool at the latest valid REP/ETH price. SecurityPool.sol External fork withdrawal lock If the universe forked before the local escalation game ended and non-decision was not reached, parent-pool escalation withdrawal reverts. The child continuation already has the canonical snapshot and aggregate backing: winning inherited deposits settle there by proof, inherited losers require no transaction, and clearing the vault's unresolved parent escalation-deposit accounting is optional. SecurityPool.sol , EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep REP-to-backing-unit round-up The pool’s internal REP-to- backing-unit conversion uses ceiling division when it removes vault REP backing units for an escalation deposit. That intentionally removes enough REP backing units to cover the requested REP even when the conversion is fractional. SecurityPool._attoRepToBackingUnitsRoundUp , SecurityPool.depositToEscalationGame Vault-funded escalation deposit Beyond the unforked-universe and Operational -pool requirement of other operational flows, depositToEscalationGame rejects a pool with an inherited fixed outcome ( Forked ), a pending fork continuation ( Fork await ), a question that has not ended when no game exists ( Question active ), and a carried game that has not resumed ( Fork paused ). It deploys the game on the first valid deposit, previews the accepted amount ( No deposit when zero), and removes vault REP backing units rounding up ( REP too low , Escrow low ). With any pool commitment it requires a valid price ( Stale price ). It then applies the BAL-04 checks to the vault and the pool ( Vault backing insufficient , Pool backing insufficient ) and requires the remaining vault REP to be zero or at least the vault REP floor ( Vault REP below minimum ). ESC-13 owns the start-bond clamp applied when the game is deployed. SecurityPool.depositToEscalationGame , EscalationGameFactory.deployEscalationGame , EscalationGame.recordDepositFromSecurityPool Wallet-funded escalation deposit depositWalletRepToEscalationGame transfers REP from the caller's wallet straight into the game; that REP never becomes vault backing or commitment capacity. It needs no vault and no oracle price and runs no backing check. It rejects an inherited fixed outcome or a forked universe ( Forked ), a non-operational pool ( Pool inactive ), a pending fork continuation ( Fork await ), a question that has not ended when no game exists ( Question active ), and a carried game ( Fork game ). SecurityPool.depositWalletRepToEscalationGame , SecurityPoolOperationsDelegate.depositWalletRepToEscalationGame Direct ETH receiver Ordinary calls to receive() accept ETH only from the forker, its Truth Auction, or its parent pool. Forced ETH can bypass receive() ; it remains raw, unaccounted surplus and is not collateral or accrued fees. SecurityPool.sol Vault enumeration getVaults(startIndex, count) pages the vault registry newest-registered first and returns an empty array when count == 0 or the start index is out of range; getVaultCount() reports the registry length. VAULT-03 owns registry membership and what consumers must read before displaying an entry. SecurityPool.getVaults","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"share-migration","heading":"Share migration","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Share migration after a fork is user-facing asset migration, not vault REP migration. Canonical rules live in FORK-10 for persistent per-child materialization, SHARE-04 for the economic-claim denominator, and FORK-11 for unequal materialized supplies. Area Implementation behavior Source Persistent entitlement ShareToken.migrate preserves the caller's parent token balance as a branch-independent entitlement. After its first use that source balance is transfer-locked, preventing a seller and buyer from materializing the same claim. ShareToken.sol Target list The target outcome list must be non-empty ( ShareToken migration requires at least one target outcome ), contain only well-formed outcomes of the fork question under Zoltar question-data validation ( ShareToken target outcome is malformed for the fork question ), and be strictly increasing ( ShareToken target outcomes must be provided in strictly increasing order ). ShareToken.sol , ZoltarQuestionData.sol Canonical source and fork transition Migration requires a canonical source pool for the token's universe. If that pool is still Operational , migrate first asks its forker to initiate the pool fork; the call proceeds only after the source is PoolForked . That conditional transition can freeze the source pool and emit the ordinary pool-fork and snapshot events. ShareToken.migrate , SecurityPoolForker.initiateSecurityPoolFork Canonical destinations Every destination must be a canonical direct child of the source pool. A single-target migration may lazily create a missing child while the child-pool deployment window is open; a multi-target migration requires every canonical child pool to exist before the call ( ShareToken bulk migration requires canonical child pools ). Lazy creation can also emit child-link, REP-migration, and continuation events. ShareToken.migrate , SecurityPoolForker.createChildUniverse Independent materialization Each selected child token id is minted up to the current source balance. A later call can select another existing child, and source shares added through an ancestor migration materialize only their previously unminted delta. ShareToken.sol Economic denominator startTruthAuction copies the frozen parent's remaining economic claim supply into the child rather than its currently materialized ERC-1155 supply. Complete-set minting and redemption update that denominator; share migration does not because its claims were reserved at fork time. SecurityPoolForker.sol , SecurityPool.sol Timing Shares can materialize indefinitely in an already-created child; creating that child is bounded by the child-pool deployment window . Raw Zoltar child-universe deployment and migration-REP splitting follow Zoltar's fork and balance guards, not this pool timestamp. ShareToken.sol , SecurityPoolForkerVaultMigrationBase.sol , Zoltar.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"escalation-resolution-and-deposits","heading":"Escalation resolution and deposits","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section specifies accepted deposits, edge-case resolution results, and the consumption of carry proofs or residual REP. Area Implementation behavior Source Deposit preview The preview path expects a proposed amount of at least the current startBondAttoRep . EscalationGame.previewDepositOnOutcome Recorded deposit amount The recorded deposit must be positive, and the accepted amount must be at least startBondAttoRep unless it exactly fills the selected outcome to nonDecisionThresholdAttoRep . EscalationGame.recordDepositFromSecurityPool , EscalationGameCalculations._getAcceptedDepositAmount Outcome room Accepted deposit amount is capped to the selected outcome's remaining room under nonDecisionThresholdAttoRep . EscalationGameCalculations._getAcceptedDepositAmount Tie adjustment If the accepted amount would create a tie with the current maximum balance while still below non-decision, the contract reduces the accepted amount by 1 attoREP ; if that breaks the accepted-amount rule, the deposit is rejected. EscalationGameCalculations._getAcceptedDepositAmount Unresolved resolution state If two or more outcomes meet the current running cost, getQuestionResolution() returns None . EscalationGameCalculations.getQuestionResolution Matching-fork continuation resolution After the continuation deadline, a game with a fixed child outcome settles deposits against that outcome. Payout settlement rejects any pool/game outcome mismatch. See Matching-question child outcome for the pool-level finality rule. EscalationGameCalculations.getQuestionResolution , EscalationGameSettlement._getPayoutQuestionResolution , SecurityPoolForker.getQuestionOutcome Empty-game fallback If all outcome balances are zero after the running cost is non-zero, getQuestionResolution() returns Invalid ; if the running cost is still zero, the unresolved check returns None first. EscalationGameCalculations.getQuestionResolution Strict leading resolution After the unresolved-cost check and the all-zero Invalid fallback, a strict Invalid , Yes , or No lead returns that outcome. Local deposits cannot create a tie below non-decision (see Tie adjustment ). Continuation snapshots preserve the parent balances exactly, including ties, so every selected branch starts from the same unresolved game state. EscalationGameCalculations.getQuestionResolution , EscalationGameProofVerifier._getStrictLeaderOrNone , EscalationGameCalculations._getAcceptedDepositAmount , EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances Structural non-decision predicate hasReachedNonDecision() becomes true when two or more outcomes reach nonDecisionThresholdAttoRep ; nonDecisionState separately records how that balance condition entered the lifecycle. ESC-13 owns the threshold arithmetic. Zoltar.getNonDecisionThresholdAttoRep , EscalationGameCalculations.hasReachedNonDecision nonDecisionState = None No explicit non-decision state is active. Deposits may remain available subject to the ordinary activation, continuation, timing, and amount guards. EscalationGame.previewDepositOnOutcome , EscalationGameDepositDelegate.recordDeposit nonDecisionState = Local A local deposit brought a second outcome to the threshold. The game stores the real nonDecisionTimestamp , closes further deposits, and canTriggerOwnFork() returns true. That predicate is game-local: a pool with an inherited fixed outcome still rejects the fork transition in activateForkMode() . EscalationGameDepositDelegate.recordDeposit , EscalationGameCalculations.canTriggerOwnFork , SecurityPool.activateForkMode nonDecisionState = InheritedThresholdTie Set when a continuation snapshot carries two or more threshold-full balances; no local nonDecisionTimestamp is recorded and deposits are closed. With a fixed child outcome, the game follows the continuation clock and canTriggerOwnFork() is false. Otherwise fork eligibility remains until applyTruthAuctionHaircut removes REP sold in the Truth Auction and breaks the tie; that clears the state, emits InheritedThresholdTieReopened , and on resume rebases the clock to the reduced binding capital with a fresh response period and reopens pool-mediated deposits. EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances , EscalationGameCalculations.getEscalationGameEndDate , EscalationGameCalculations.canTriggerOwnFork , EscalationGameDepositDelegate.applyTruthAuctionHaircut Carry proofs Inherited carry uses Merkle Mountain Range peaks and nullifier roots so child games can consume proofs without replaying already-spent parent deposits. EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._verifyAndConsumeCarriedDepositProof Continuation withdrawal After a child pool's carried game resolves, anyone may relay a batch of winning carried proofs for one depositor ( One vault ). ESC-07 owns the payout recipient and ESC-05 the single use of each proof. SecurityPool.withdrawForkedEscalationDeposits , EscalationGameSettlement.withdrawDeposit , EscalationGameDepositDelegate.consumeCarriedDeposit Carried payout amount Retained principal maps the deposit's cumulative endpoints through each ancestor's auction ratio; the reward uses the separate reward interval , binding capital , winning balance, and fork-threshold scaling. Allocations within a game are fixed, so claim order cannot change payouts. EscalationGameClaimDelegate.getUnresolvedClaimInterval Inherited losers Inherited losing outcomes retire without a proof once the result is final; locally created losing deposits settle ordinarily. EscalationGameSettlement.withdrawDeposit Carried-claim gas Allocation reads call each source game in the deposit's lineage , so gas grows with fork depth. No maximum depth is enforced; see LIFE-05 . EscalationGameClaimDelegate.getUnresolvedClaimInterval Optional unresolved parent escalation-deposit accounting cleanup Optional. SecurityPoolForker.migrateVaultWithUnresolvedEscalation first runs ordinary vault migration for that vault, then exports one Invalid / Yes / No principal tuple to one selected child without a token transfer. It never processes another vault, preserves proof leaves, and neither funds dispute-staked REP backing nor authorizes inherited claims. SecurityPoolForker.migrateVaultWithUnresolvedEscalation , EscalationGameEscrow.exportVaultUnresolvedTotalsWithoutTransfer , EscalationGameForker.migrateVaultWithUnresolvedEscalation Residual sweep sweepResidualRepToSecurityPool returns an ordinary game's residual to the security pool and burns a carried game's entire residual. ESC-11 owns the preconditions. EscalationGameSettlement.sweepResidualRepToSecurityPool","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"fork-migration","heading":"Fork migration","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section specifies pool-level migration after a universe fork: proxies, child-pool creation, pool-proxy REP splitting, and child outcome selection. Area Implementation behavior Source Pool-specific migration identity The forker lazily deploys one deterministic SecurityPoolMigrationProxy per parent pool. The proxy is the stable msg.sender for Zoltar migration accounting. REP sent to its predictable address before deployment remains isolated surplus: fork accounting uses newly routed REP and the Zoltar migration ledger, not the proxy’s preexisting ERC-20 balance. SecurityPoolForker.sol , SecurityPoolMigrationProxy.sol Proxy authority The migration proxy is owner-controlled by the forker and wraps lockRep , forkUniverse , splitToChild , and child REP sweeping. SecurityPoolMigrationProxy.sol Child REP backing During vault migration, the forker ensures the child pool is backed by enough child-universe REP for cumulative migrated REP credited to that child. SecurityPoolForkerVaultMigrationBase.sol Vault fees during migration Migration uses one fixed, fee-exclusive snapshot and a cumulative REP ceiling. The parent vault is checkpointed before its underwriting commitment is cleared, so earned fees remain redeemable, and parent-to-child ETH transfers cannot consume the balance reserved by totalAccruedFeesAttoEth() . The invariant catalog specifies BAL-07 fee-reserve protection , FORK-09 cumulative child collateral , and FORK-08 continuation backing . SecurityPoolForker.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPool.sol Split shortfall tracking The forker tracks how much REP has already been split for each parent-pool/outcome pair and only splits the shortfall before sweeping child REP into the child pool. SecurityPoolForkerVaultMigrationBase.sol Canonical continuation snapshot Fork initialization stores the complete parent Invalid / Yes / No balances, carry totals, peaks, leaf counts, and nullifier roots once. Every lazily created child reads that same stored snapshot, even if an allowed parent claim occurs before a later child is created. SecurityPoolForker._snapshotEscalationAtFork , SecurityPoolForkerBase._initializeChildForkedEscalationGameIfNeeded , EscalationGameCarry.initializeForkCarrySnapshotWithResolutionBalances Aggregate escalation backing An external unrelated fork reproduces the drained game's dispute-staked REP one-for-one in each selected child. The escalation's own fork transfers aggregate backing net of the fork haircut instead; ordinary pool-held REP remains one-to-one. Each selected child receives its applicable aggregate backing once, and resumeFromFork remains paused until that backing is present after accounting for child REP already exported by valid direct pre-resume claims. See FORK-08 for the raw and effective principal definitions and exact funding bound. Neither path scales or releases per-vault child escrow. SecurityPoolForker.initiateSecurityPoolFork , SecurityPoolForker.forkZoltarWithOwnEscalationGame , SecurityPoolForkerVaultMigrationBase._ensureChildEscalationBacking , EscalationGame.resumeFromFork Direct-claim replay protection A successful direct own-fork claim records both the stable parent deposit identity and cumulative claimed principal by outcome. Every current, late, or recursively inherited child rejects a second payout; effective inherited principal subtracts immediate-parent direct claims so those leaves cannot strand the residual sweep. EscalationGameForker.claimForkedEscalationDeposits , SecurityPoolForker.isEscalationDepositClaimedDirectly , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep Continuation setup Child creation installs the canonical carry commitment, source-game link, and aggregate backing without waiting for vault transactions or copying claims and owners. The fixed 64-peak MMR frontier is logarithmic commitment storage for up to 2^64 - 1 leaves, not a participant cap; see Merkle Mountain Range carry-proof peaks . SecurityPoolForkerBase._finalizeAwaitingForkContinuationIfReady , EscalationGameSettlement.withdrawDeposit , EscalationGameCarry._getEffectiveInheritedUnresolvedTotalAttoRep Continuation resume Once the child is operational and fully funded, resumeForkedEscalationGame resumes it in one bounded permissionless call. Winning proofs can then be relayed, and optional parent cleanup may happen independently. SecurityPool.resumeForkedEscalationGame Own-fork REP buckets When escalation triggers its own fork, escalationChildRepAtForkAttoRep equals disputeStakedRepToForkAttoRep - ⌊forkThresholdAttoRep / forkBurnDivisor⌋ . vaultRepAtForkAttoRep preserves ordinary pool-held REP one-for-one. Creating one selected child does not reduce the post-fork-haircut escalation backing available to another selected child. SecurityPoolForker.forkZoltarWithOwnEscalationGame , SecurityPoolForker.getOwnForkRepBuckets , SecurityPoolForkerBase._initializeOwnForkRepBuckets Child-pool deployment window Child pools are created lazily for selected fork outcomes, only while the parent pool is PoolForked ( Parent not forked ) and the migration window is open ( Migration closed ). The same window bounds pool-local vault and REP migration. FORK-05 owns the eight-week boundary. SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolUtils.sol Matching-question child outcome When the parent universe forks on the pool's question, the child stores its selected branch as a fixed result. depositToEscalationGame and depositWalletRepToEscalationGame reject new local deposits, and activateForkMode rejects every later pool fork transition ( Forked in each case). ESC-12 owns the property; Forks and migration gives the collateral and REP-liveness rationale. SecurityPool.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolForker.sol Unrelated-fork child outcome A child created by an unrelated fork without an inherited fixed result uses a local escalation result only if that escalation ended before the universe forked; otherwise continuation or later state must produce the outcome. SecurityPoolForker.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"truth-auction-operations","heading":"Truth Auction operations","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"Collateral-repair auctions have three operator-critical boundaries: forker ownership, a one-week bidding window, and paged settlement into vault accounting. Bids close at auctionStarted + AUCTION_TIME ; both direct auction finalization and the public forker wrapper allow finalization at >= that boundary. The canonical clearing rules and examples are in Truth Auction . Area Implementation behavior Source Owner Child-pool Truth Auctions are owned by SecurityPoolForker . The direct auction startAuction and finalize calls are owner-only, while anyone can reach them through startTruthAuction and finalizeTruthAuction . UniformPriceDualCapBatchAuction.sol , SecurityPoolForker.sol Finalized settlement After finalization, only the auction owner withdraws bid outcomes from the auction; SecurityPoolForker wraps that call so anyone can settle a vault's bid pages. UniformPriceDualCapBatchAuction.sol , SecurityPoolForker.sol Child fee activation Completed migration or truth-auction settlement starts a new child fee epoch. Migrated ownership and sold truth-auction ownership enter the fee denominator at finalization. Each later auction claim assigns the bidder vault its ownership and fees accrued from the saved finalization index through the current index without changing the pool’s live eligible total; intervening capacity changes and liquidations remain preserved. SecurityPool.sol , SecurityPoolForker.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"repeth-oracle-operations","heading":"REP/ETH oracle operations","keywords":[],"path":"reference/operator-guardrails.html","sectionTitle":"Reference","summary":"What each subsystem will and will not accept, mapped to contract sources.","text":"This section covers coordinator staging, callback recovery, stale-operation handling, and liquidation boundaries. Report sizing, request cost, and current OpenOracle parameters are canonical in the OpenOracle integration parameters . Area Implementation behavior Source Atomic initial report The sponsor commits an explicit ETH bounty of at least the dynamic request cost and funds the WETH/REP position; the coordinator retains the whole bounty and submits that position atomically as the initial reporter. A caller-selected WETH amount above the dynamic minimum is allowed. See OpenOracle sizing and funding for derivation, reporter withdrawals, application buffering, and escalation effects. OpenOraclePriceCoordinator.sol , openOracle.ts Immediate execution If a price is still valid, the operation executes immediately and positive unused ETH is refunded. A contract caller must accept the refund callback or the execution rolls back; the canonical refund warning also covers newly opened reports. OpenOraclePriceCoordinator.sol Fresh-price request guard requestPrice reverts while the cached coordinator price is still valid ( Oracle price already fresh ), so callers cannot open a redundant pending report on top of a fresh cache. OpenOraclePriceCoordinator.sol Staging guardrails Withdrawal and liquidation amounts must be non-zero ( Staged operation amount must be non-zero ); a zero underwriting commitment is a valid exit. Validity must be positive and no more than five minutes ( Staged operation timeout must be positive , Staged operation timeout exceeds the maximum allowed ). Withdrawals and underwriting-commitment changes target the operator's own vault ( Self operation target mismatch ). A liquidation receiver must differ from its target ( Receiver is target ); ORA-05 owns the role rules. A delegated receiver requires a valid bounded approval and queue-time reservation, while the self-receiving operator path requires no signature. OpenOraclePriceCoordinator.sol , OpenOraclePriceCoordinatorTypes.sol Delegated receiver approvals LiquidationApprovalRegistry supports direct receiver approvals and Ethereum Improvement Proposal 712 (EIP-712) permits from externally owned accounts (EOAs) or ERC-1271 contract wallets. An approval binds pool, receiver, exact operator, exact or wildcard target, cumulative and per-operation ETH debt limits, minimum post-health factor, validity window, and nonce. Revocation blocks new reservations without disturbing pending ones; nonce invalidation blocks stale approvals. LiquidationApprovalRegistry.sol , openOracle.ts Approval reservation lifecycle Staging reserves at most requested debt, snapshotted target underwriting commitment, per-operation allowance, and available cumulative allowance. Success consumes exactly the transferred underwriting commitment and releases the remainder; an untransferred residual consumes no approval quota. Every terminal failure and permissionless expiration releases once. Approval validity must cover the latest legal execution time. OpenOraclePriceCoordinator.sol , LiquidationApprovalRegistry.sol Pending report bound At most four price actions are attached to one settlement callback, counting each commitment change, liquidation, or withdrawal within a vault bundle separately. Deposits use no slot. Bundles must fit the remaining callback capacity; single operations can still be tracked as active outside the callback batch. OpenOraclePriceCoordinator.sol Sponsor exclusivity Once the cached price is stale and a caller funds a fresh coordinator report, only that pendingReportSponsor can append more staged operations until settlement. Valid disputes reset the settlement clock, so this paid exclusive lane can be extended indefinitely; the coordinator makes no bounded-availability guarantee. The economic tradeoffs , attack model , and parameter table own dispute funding, escalation, and rounding details. OpenOraclePriceCoordinator.sol , OpenOracle.sol Rejected settlement When the callback fails any condition in coordinator settlement validation , it emits PriceReportRejected , leaves lastPrice unchanged, clears the pending report so a new price can be requested, and terminally fails every operation attached to that report, releasing each delegated-liquidation reservation. OpenOraclePriceCoordinator.sol , OpenOracle.sol Recovery path Coordinator reports opt into OpenOracle's STORE_ALL and TRACK_DISPUTES flags. Recovery requires a pending report whose stored OpenOracle settlement timestamp is nonzero. It returns withdrawable reporter balances to the sponsor, clears the report, consumes all associated pending operations, and releases their liquidation reservations. An expired operation can also be cleaned permissionlessly before any valid-price requirement. OpenOraclePriceCoordinator.sol Consumed failures Expired operations ( Staged operation expired ), stale liquidations ( Stale liquidation ), zero-effect withdrawals ( Withdraw amount has no effect ), and liquidations too close to threshold are consumed and emitted as failed executions. ORA-06 owns the property. OpenOraclePriceCoordinator.sol Vault operation bundle submitVaultOperations applies a deposit, commitment change, liquidations of other vaults, and withdrawal to one pool. At most four price actions fit a bundle. A fresh-price failure reverts the submission; with a stale price the deposit remains while the remaining actions execute atomically after settlement. Any change to a queued liquidation target's REP backing units or underwriting commitment fails the whole bundle, including the owner's commitment change and withdrawal. See coordinator execution and funding . VaultOperations.sol Liquidation snapshot A staged liquidation becomes stale if target REP backing units or its underwriting commitment ( underwritingLimitAttoEth ) changes. The underwriting-commitment snapshot bounds the reservation; the proportional-obligation snapshot is historical context. Execution rechecks full-commitment target health and the receiver's entire resulting underwriting commitment against live price and backing. REP awards cap at available target units without reducing the accepted underwriting commitment. Successful transfer conserves total underwriting commitments. Residual exposure remains visible and earns fees. See queued execution . OpenOraclePriceCoordinator.sol , SecurityPool.sol Liquidation distance A staged liquidation must remain at least minLiquidationPriceDistanceBps beyond the liquidation threshold when it executes. OpenOraclePriceCoordinator.sol , SecurityPoolOperationsDelegate.sol","title":"Subsystem guardrails","topic":"Safety","weight":0},{"fragment":"","heading":"","keywords":["inventory","factories","delegates","SecurityPoolUtils","trust boundary"],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Reference This page lists every production Solidity source by area. The contract interaction reference documents the entrypoints of the contracts users and keepers call; this page adds the caller and trust boundaries of the deployment helpers, delegate modules, and libraries that reference does not cover, the SecurityPoolUtils previews, and the Uniswap contracts a testnet deployment uses.","title":"Contract inventory","topic":"Contracts","weight":1},{"fragment":"caller-and-trust-boundaries","heading":"Caller and trust boundaries","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Deployment helpers are not interchangeable with canonical protocol discovery. Several are intentionally permissionless and bind the caller into each deployed address, through a caller-namespaced salt or the caller in the init code; an application must discover canonical instances through SecurityPoolFactory , recognized security pools , and recognized forker events rather than treating every factory-created address as canonical. Module Direct caller boundary Canonical-use boundary EscalationGameFactory deployEscalationGame and deployEscalationGameFromFork have no permission check, but a successful caller must implement the ISecurityPool reads used during construction; an EOA or incompatible contract reverts. The CREATE2 salt is zero; the caller is bound into the init code as the new game's securityPool , so each caller has one game address; the factory itself becomes the game's immutable owner and immediately calls start or startFromFork . Ordinary deployment requires a threshold above one attoREP and lowers a start bond at or above that threshold to threshold - 1 . The factory has no owner role and no later resumeFromFork relay. Accept a game only after EscalationGameSet from a recognized pool. In the supported continuation path, the owning pool calls resumeFromFork , which also verifies aggregate funding. ShareTokenFactory Anyone can call deployShareToken to deploy or retrieve a token keyed by keccak256(abi.encode(msg.sender, salt, questionId)) . The CREATE2 salt is the raw salt ; the caller and question id enter through constructor arguments, and that caller is the token's initial authorized address. Origin lineage tokens are the instances created by SecurityPoolFactory and named in DeploySecurityPool ; children reuse the parent's token. UniformPriceDualCapBatchAuctionFactory Anyone can call deployUniformPriceDualCapBatchAuction . Its salt is namespaced by caller and supplied salt, and its operational owner is the caller-supplied owner address. During external-universe initiation, the source must be authorized by its declared share token; own-game initiation does not perform that check, and neither relationship proves configured-factory registration. Child linking requires a deployed auction that this forker has never trusted before and preserves the source's factory and forker. Canonical pools remain the instances registered by the configured SecurityPoolFactory . OpenOraclePriceCoordinatorFactory Anyone can call deployOpenOraclePriceCoordinator under a caller-namespaced salt with caller-supplied OpenOracle, REP token, and positive initialReportPriorityFeeAttoEthPerGas ; coordinator construction rejects zero and values that would consume the reserved OpenOracle uint128 report and escalation-halt capacity. The caller therefore chooses this immutable gas-price assumption within that bound. The same call deploys and initializes the coordinator's LiquidationApprovalRegistry clone and binds it to the coordinator. A pool coordinator is the instance named by canonical DeploySecurityPool ; SecurityPoolFactory atomically binds it to that pool before returning, and canonical child deployment inherits the value from the parent coordinator. PriceCoordinatorDeploymentWorker , LiquidationApprovalRegistryDeployer , and CreationCodeChunk The coordinator factory constructor deploys one worker and one registry deployer; only that factory may call the worker's deploy and configureLiquidationApprovalRegistry or the registry deployer's deploy . The worker stores coordinator creation code in two CreationCodeChunk data contracts, deploys coordinators with CREATE2 , and is the only address that may call setLiquidationApprovalRegistry . The registry deployer creates the registry implementation and deploys minimal-proxy clones under the coordinator's salt. Code-size and deployment plumbing with no protocol authority; users do not call them. LiquidationApprovalRegistry implementation The implementation the registry deployer creates is never initialized, so anyone can call its initialize and bind it to an arbitrary coordinator. Clones are initialized in their deployment transaction. Trust registry state only at the address returned by a recognized coordinator's liquidationApprovalRegistry() . SecurityPoolDeployer and SecurityPoolDeploymentWorker Only the configured SecurityPoolFactory may call the deployer; only that deployer may call its worker. They are code-size deployment plumbing. The proxy deployer deploys one deterministic SecurityPoolOperationsDelegate , and its address is passed into the SecurityPoolFactory constructor. The proxy deployer is the deterministic CREATE2 deployment proxy that every canonical deployment goes through; it is not a Solidity source in this repository and appears in the deployment manifests as step proxyDeployer . The factory passes that address through its deployer and worker to every pool. Its deterministic address is published as securityPoolOperationsDelegate . Pools become canonical only when the factory emits SecurityPoolRegistered and DeploySecurityPool . SecurityPoolMigrationProxy Only its immutable owner , the SecurityPoolForker that created it, may call lockRep , forkUniverse , splitToChild , or sweepChildRep . Its deterministic per-parent address is exposed by getMigrationProxyAddress and recorded in fork snapshot events; users do not call it. EscalationGameDepositDelegate , EscalationGameClaimDelegate , EscalationGameForker , SecurityPoolForkerVaultMigrationDelegate , SecurityPoolSettlementDelegate , and SecurityPoolOperationsDelegate Their public methods are delegatecall implementations. The deposit delegate implements depositRepOnOutcome , depositRepOnOutcomeWithPermit , depositRepOnOutcomeWithAuthorization , recordDeposit , recordForkedEscrowForOutcome , applyTruthAuctionHaircut , funding-gated resumeFromFork , consumeEscrowedRepForOwner , consumeCarriedDeposit , consumeUnresolvedRepForClaimOwners , creditClaimOwners , and creditExternalClaimOwners . The shared claim delegate handles retention checkpoint reads and initialization; it has no ownership or import surface. The forker delegates implement escalation and vault migration. SecurityPoolSettlementDelegate is abstract and contributes complete-set minting validation and funded inherited-collateral installation to the single deployed SecurityPoolOperationsDelegate . That operations delegate implements underwriting commitment changes, aggregate mint backing checks, and authorized liquidation transfers that conserve total underwriting commitments without writing off residual exposure. REP backing and fees are accounted separately. See the SecurityPool and EscalationGame interaction references for the public entrypoints, including the selectors each contract's fallback() routes to its delegate. A direct call may revert against uninitialized state or may mutate only the helper's isolated storage; it is not a protocol action. Accept resulting state and logs only when the recognized game, pool, or forker executes the matching wrapper through delegatecall . State changes and events then occur in that recognized contract's context. Canonical liquidation enters through SecurityPool.performLiquidation , which only the pool's VaultOperations executor may call; continuation progress enters through SecurityPool.resumeForkedEscalationGame . SecurityPoolEventEmitter and SecurityPoolForkEventEmitter SecurityPoolEventEmitter inherits the pool's typed SecurityPoolStorage base and exposes emitPoolAccountingCheckpoint and emitVaultAccountingCheckpoint . SecurityPoolForkEventEmitter inherits the forker's typed SecurityPoolForkerStorage base and exposes emitForkSnapshotEvents . The entrypoints are externally callable and payable , but direct calls execute against the helper's own storage and emit from the helper address. Payability permits delegatecalls from value-bearing protocol flows; callers must not send ETH directly because it is not protocol collateral and the helpers have no recovery surface. Pools delegate accounting checkpoints to their pool-layout emitter, while the forker delegates fork snapshots to its forker-layout emitter, so logs are emitted from the recognized pool or forker address. Indexers must reject matching signatures from either helper or any unrecognized emitter. Storage-layout tests protect both typed delegate layouts. EscalationGameProofVerifier , MerkleMountainRange , and SecurityPoolUtils Math and proof routines have no lifecycle authority. Public verifier calls and SecurityPoolUtils pure previews can be used for previews, but do not mutate a game or pool. SecurityPoolUtils also has state-changing external library functions, configureForkMigratedVault , consumeUnassignedCommitment , and creditForkAuctionVault , which execute through delegatecall in the forker's context; library call protection rejects direct calls to them. A result becomes protocol state only through a recognized game, pool, or forker transaction and its events. DeploymentStatusOracle Anyone can call getDeploymentMask ; the constructor alone fixes the ordered address list and emits DeploymentAddressesSet . It reports code presence only, not canonical wiring or readiness. Decode it using its constructor event or the matching deployment manifest order.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"securitypoolutils-read-surface","heading":"SecurityPoolUtils read surface","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"The table lists every external or public read of the library; its three state-changing library functions are in the trust-boundary table above. The previews distinguish a vault's underwriting commitment from its current proportional share of open interest . REP-per-ETH prices use PRICE_PRECISION , and health factors and security multipliers use basis points. The previews have no lifecycle, caller, freshness, or canonical-pool authority; only a recognized pool or coordinator transaction can apply their result. Function Exact boundary behavior Conceptual owner calculateFeeAccrual(settlementCollateralAttoEth, retentionRate, timeDelta, indexRemainder, feeEligibleUnderwritingLimitAttoEth, feesOwedRemainder) Applies fixed-point retention over elapsed time to settlement collateral net of the already-counted but uncredited decay (indexRemainder + feesOwedRemainder) / 1e18 , carries the global index remainder, and returns whole credited fees plus the next fee remainder. Credited fees therefore never exceed settlement collateral. Canonical callers avoid a zero fee-eligible underwriting commitment total before this division. Fee accrual calculateVaultFee(underwritingLimitAttoEth, feeIndexDelta, remainder) Floors the vault's whole fee credit and returns the remaining fixed-point numerator for its next checkpoint. Fee accrual calculateVaultOpenInterestAttoEth(activeOpenInterestAttoEth, vaultUnderwritingLimitAttoEth, totalUnderwritingLimitAttoEth) Attributes live pool open interest pro rata to underwriting commitment, rounding a positive vault share upward. A zero vault or total underwriting commitment returns zero. Dynamic capacity calculateBundledLiquidationTransfer(targetBackingUnits, targetUnderwritingLimitAttoEth, targetOpenInterestAttoEth, requestedDebtAttoEth, repEthPrice, currentPoolHeldAttoRepBalance, currentTotalRepBackingUnits, minimumRemainingAttoRep) Both target exposure arguments are the target's full underwriting commitment. Transfers the lesser of request and that commitment. The REP award, the debt's REP value plus a 5% bonus (105%), rounds up in REP and backing units, then caps at available target units. Partial transfers reserve the configured minimum REP when available. A full transfer can use all target units. The receiver must independently satisfy health for its full underwriting commitment; no residual underwriting commitment is written off. Vault liquidation isVaultHealthy(poolHeldVaultRepBackingAttoRep, disputeStakedAttoRep, underwritingLimitAttoEth, repEthPrice, poolSecurityMultiplierBps) Checks the associated-REP and free pool-held REP requirements against the full underwriting commitment at a factor of 10,000 BPS. Both requirements round upward; a zero commitment is healthy. Capacity and health calculateRetentionRate(settlementCollateralAttoEth, mintingCapacityAttoEth) Zero minting capacity returns the maximum retention rate. Otherwise retention decreases linearly through the 80% utilization dip and remains at the minimum rate above it. Retention rate isVaultHealthyAtFactor(poolHeldVaultRepBackingAttoRep, disputeStakedAttoRep, underwritingLimitAttoEth, repEthPrice, poolSecurityMultiplierBps, healthFactorBps) Public pure. The isVaultHealthy check with both REP requirements multiplied by healthFactorBps / 10,000 , rounded upward. A factor below 10,000 BPS returns false, before the zero-commitment case returns true. Receiver approvals calculateLiquidationBackingUnitsAward(debtToMoveAttoEth, repEthPrice, currentPoolHeldAttoRepBalance, currentTotalRepBackingUnits) Public pure. Returns the backing units for the REP value of the moved commitment plus the 5% bonus, rounding upward in REP and again in units. With zero total units or zero pool-held REP it returns the REP award multiplied by PRICE_PRECISION . Vault liquidation calculateInitialEscalationDepositAttoRep(theoreticalSupplyAttoRep) Public pure. Returns theoreticalSupplyAttoRep / 10,000,000 , with a floor of 1 REP. SecurityPoolFactory calculateMinimumVaultRepDepositAttoRep(theoreticalSupplyAttoRep, configuredMinimumAttoRep) Public pure. Returns configuredMinimumAttoRep when it is nonzero, otherwise theoreticalSupplyAttoRep / 100,000 . SecurityPoolFactory getUnassignedPositionFeeAccounting(securityPoolAddress) External view. Returns the forker's auction-finalization fee index for the pool's unassigned position and the fees that position has accrued since, underwritingLimitAttoEth × (feeIndex − feeIndexAtFinalization) / PRICE_PRECISION . The fee amount is zero when the pool has no Truth Auction or the auction purchased no REP. SecurityPoolForker getBadDebtGeneration(securityPool) External view. Returns badDebtGeneration from the pool's getPoolAccountingSnapshot() . SecurityPool","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"production-contract-inventory","heading":"Production contract inventory","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"Every production Solidity source appears in one row. The first row lists the sources with a page in the contract interaction reference; the sources of the other documented contracts appear in the row for their area. Area Named contracts and modules Role Core contracts Zoltar.sol , ZoltarQuestionData.sol , SecurityPool.sol , OpenOraclePriceCoordinator.sol , VaultOperations.sol , UniformPriceDualCapBatchAuction.sol Universe forks and REP migration, question storage, the security pool, its price coordinator and vault bundle executor, and the Truth Auction. Entrypoints: Zoltar , ZoltarQuestionData , SecurityPool , OpenOraclePriceCoordinator , VaultOperations , and UniformPriceDualCapBatchAuction . Deployment tracking DeploymentStatusOracle.sol Reports one code-presence bit per configured deployment-step address. See Deployment Status Oracle . Carry proof hashing MerkleMountainRange.sol , EscalationGameProofVerifier.sol , EscalationGameTypes.sol Defines the carried-deposit leaf shape, the 64-peak limit, proof-length rules, and nullifier-root replay protection. See Merkle Mountain Range carry proofs . Escalation game composition EscalationGame.sol , EscalationGameCalculations.sol , EscalationGameCarry.sol , EscalationGameClaimDelegate.sol , EscalationGameDepositDelegate.sol , EscalationGameEscrow.sol , EscalationGameSettlement.sol , EscalationGameState.sol , EscalationGameStorage.sol Splits the game across immutable ownership and storage, claim and deposit delegation, calculations, continuation proofs, escrow, and settlement without exposing those internal modules as separate canonical games. ERC-20 support ERC20.sol , IERC20.sol , IExternalGenesisReputationToken.sol , IERC20Metadata.sol , Context.sol , SafeERC20Ops.sol , GenesisReputationToken.sol , ReputationToken.sol Base REP token implementation, ERC-20 and external genesis REPv2 interfaces, metadata, execution context, safe transfer wrappers, the constructor-allocated testnet stand-in for mainnet REPv2 ( GenesisReputationToken ) with fixed theoretical supply, and the inherited transfer , approve , and transferFrom entrypoints. ERC-1155 and token ids ERC1155.sol , ShareToken.sol , TokenId.sol , IERC1155.sol , IERC1155Receiver.sol , IERC165.sol , IShareToken.sol Outcome-share token plumbing, interface support, token-id encoding, inherited setApprovalForAll , and both single and batch safeTransferFrom forms. Factories and deployers EscalationGameFactory.sol , SecurityPoolFactory.sol , SecurityPoolDeployer.sol , ShareTokenFactory.sol , UniformPriceDualCapBatchAuctionFactory.sol , OpenOraclePriceCoordinatorFactory.sol , Create2Deployment.sol Deterministic deployment entrypoints for pool, share-token, oracle-coordinator, liquidation-approval-registry clone, escalation-game, and auction instances, plus the shared CREATE2 helper library they use. Migration, settlement, liquidation, and storage modules SecurityPoolStorage.sol , DelegateCallForwarder.sol , DelegateCall.sol , SecurityPoolSettlementDelegate.sol , SecurityPoolOperationsDelegate.sol , SecurityPoolMigrationProxy.sol , SecurityPoolForker.sol , SecurityPoolForkerAuctionSettlementBase.sol , SecurityPoolForkerBase.sol , SecurityPoolForkerStorage.sol , SecurityPoolForkerTypes.sol , SecurityPoolForkerVaultMigrationBase.sol , SecurityPoolForkerVaultMigrationDelegate.sol , UniformPriceDualCapBatchAuctionStorage.sol , OpenOraclePriceCoordinatorTypes.sol , EscalationGameForker.sol , SecurityPoolEventEmitter.sol , LiquidationApprovalRegistry.sol , SignatureValidation.sol Defines shared pool storage, delegated liquidation accounting and bounded approval reservations, Elliptic Curve Digital Signature Algorithm (ECDSA) and ERC-1271 signature validation, funded continuation delegatecalls, fork-time state, truth-auction settlement, vault and unresolved-escalation migration, event encoding, and stable proxy identity used while routing parent state into child pools. Protocol interfaces IEscalationGame.sol , IEscalationGameDelegateContexts.sol , ISecurityPoolDeploymentWorkerConfiguration.sol , IZoltarForkState.sol , ISecurityPool.sol , ISecurityPoolForker.sol , ISecurityPoolForkerChildEscalationGameInitializer.sol , IUniformPriceDualCapBatchAuction.sol , IWeth9.sol Typed boundaries used by games, pools, migration delegates, auctions, and WETH integration. Protocol utilities Constants.sol , ScalarOutcomes.sol , BinaryOutcomes.sol , SecurityPoolUtils.sol , Multicall3.sol , WETH9.sol Shared constants and math, outcome representations, Multicall3 aggregate , tryAggregate , tryBlockAndAggregate , blockAndAggregate , aggregate3 , aggregate3Value , and block-context reads, plus standard WETH9 deposit , withdraw , approval, and transfer support. Operator deployment helper GenesisUniswapV3Seeder.sol Lets the Chaos bot mint a bounded full-range genesis REP/WETH Uniswap V3 position, pays the pool callback from exact operator approvals, and refunds unused tokens. Trading protocol PredeploymentShareSink.sol , TradingLiquidityToken.sol , TwoWayConstantProductFactory.sol , TwoWayConstantProductMath.sol , TwoWayConstantProductPair.sol , TwoWayConstantProductRouter.sol , ITradingShareToken.sol , ITwoWayConstantProductFactory.sol , ITwoWayConstantProductPair.sol . Deterministic two-outcome pool deployment, constant-product pricing and reserves, routed liquidity and swap operations, receive-based share authorization, permit-enabled liquidity tokens, canonical Statoblast share-token integration, and quarantine of shares sent to counterfactual pair addresses before deployment. REP authorization support AuthorizationSignatures.sol , ERC20Authorization.sol , IERC20Authorization.sol . Pinned signature recovery, EIP-712 domain handling, ERC-2612 permits, and ERC-3009 transferWithAuthorization , recipient-bound receiveWithAuthorization , and cancelAuthorization used by newly deployed child REP. Imported oracle integration UPSTREAM.md , OpenOracle.sol , Errors.sol , ISignatureTransfer.sol , interfaces/IERC20.sol , interfaces/IERC165.sol , token/ERC20/IERC20.sol , IERC1363.sol , SafeERC20.sol , Panic.sol , ReentrancyGuard.sol , StorageSlot.sol , utils/introspection/IERC165.sol , Math.sol , SafeCast.sol OpenOracle's imported source, exact openPunt revision, compiler profile, and dependency provenance are owned by UPSTREAM.md . The coordinator submits attoETH/attoREP reports with dispute history and full game storage enabled; it does not enable the new optional flags. OpenOracle's packed event stream remains separate from Zoltar replay.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"testnet-uniswap-dependencies","heading":"Testnet Uniswap dependencies","keywords":[],"path":"reference/contract-inventory.html","sectionTitle":"Reference","summary":"Every production Solidity source by area, the caller and trust boundaries of deployment helpers and delegate modules, SecurityPoolUtils previews, and testnet Uniswap dependencies.","text":"The UI, the bots, and the testnet deployer read Uniswap addresses from one registry, shared/core/ts/deployment/uniswapDeployments.ts . Chain WETH, V3 factory, QuoterV2, V4 PoolManager, V4 Quoter SwapRouter Sepolia ( 11155111 ) Uniswap's published contracts ( V3 , V4 ); the deployer requires each to carry Uniswap's exact runtime code. An Anvil node with the Sepolia chain ID receives them by replaying Uniswap's original creation transactions, vendored byte for byte in scripts/artifacts/uniswap-deployment.json . Deterministic SwapRouter (v1) bound to the published factory; Uniswap publishes none on Sepolia. Any other testnet Deterministic WETH plus a complete Uniswap V3 and V4 deployment from the pinned bytecode. Deterministic SwapRouter from the pinned bytecode.","title":"Contract inventory","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["deployment","bitmask","runtime bytecode","status"],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"DeploymentStatusOracle is a deployment-progress helper. It does not measure protocol readiness or initialization success. It only reports which configured deployment-step addresses currently contain runtime bytecode.","title":"Deployment status oracle","topic":"Contracts","weight":1},{"fragment":"mask","heading":"What getDeploymentMask() returns","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"The constructor stores one ordered address[] deploymentAddresses . getDeploymentMask() loops over that array and checks deploymentAddresses[index].code.length . When code exists, the oracle sets bit index in the returned uint256 . This is a code-presence bitmap. A set bit means code exists at the configured address. A clear bit means the address currently has no code. The oracle does not verify constructor arguments, ownership wiring, or post-deployment setup. A row of deployment steps maps by index into bit positions in a uint256 mask. Each step sets its bit only when code exists at that configured address. Deployment status mask Each configured deployment step uses one bit position in the returned word. The oracle sets that bit only if the step's address currently contains code. deployedMask = ∑ i = 0 codePresent ( i ) ⋅ 2 i Each configured deployment step contributes one bit position to the returned word.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"ordering","heading":"How bits map to deployment steps","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Bit positions are array positions. Bit 0 maps to the first constructor address, bit 1 to the second, and so on. Off-chain decoding must use the same ordered list that seeded the oracle. The constructor emits DeploymentAddressesSet(address[] deploymentAddresses) with that exact ordered list. It is the on-chain source for recovering a particular oracle instance's bit mapping. The manifest below describes the current planned deployment and must match the constructor event for that instance. The current user interface (UI) and deployment helpers derive the constructor list from deploymentSteps with one exception: the oracle does not include its own address in its constructor array. The manifest still lists deploymentStatusOracle as a deployment step, but the UI tracks that step out of band and starts consuming mask bits from the remaining addresses. The tables below render the complete bit mappings directly from the canonical mainnet deployment manifest and Sepolia deployment manifest , excluding deploymentStatusOracle . Each manifest's ordered deploymentSteps array is the canonical mapping for that network. The orders differ: Sepolia inserts the genesis REP token at bit 1 , so the same mask names different steps on each network. Select the network before decoding. A second, Zoltar-only oracle is deployed by the Zoltar app's deployment flow and by the testnet deployer. Neither manifest lists it or publishes its address: the testnet deployer's plan names it zoltarDeploymentStatusOracle , a step id that exists only in that plan, alongside the tradingFactory and tradingRouter steps the manifests also omit. Its constructor list is a prefix of the manifest mapping: the proxy deployer, genesis REP on Sepolia, Multicall3, ZoltarQuestionData , and Zoltar . Decode its mask with the same table; only those leading bits exist. Bit Mainnet step id Label Status in entered mask Loading the canonical manifest… Bit Sepolia step id Label Status in entered mask Loading the canonical manifest… If the manifest's constructor order changes, the rendered bit meanings change with it; this page does not maintain a second list. The manifest's derivedContracts list adds no mask bits. Five of its six entries ( securityPoolForker , escalationGameClaimDelegate , escalationGameFactory , securityPoolFactory , and securityPoolOperationsDelegate ) repeat a deploymentSteps address under a different label, so each already has a bit. Only escalationGameProofVerifier , which EscalationGameFactory deploys in its constructor, has no bit. The tables use the deploymentSteps labels. In the Sepolia manifest the genesis REP step has the id reputationToken and the label GenesisReputationToken . It is the token at network.genesisRepTokenAddress , not a child ReputationToken .","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"deployment-mask-decoder","heading":"Decode a deployment mask","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Decoded status Loading the canonical mapping… Network Ethereum mainnet Sepolia Mask value The decoder maps each set bit to the selected network's constructor address at the same index. Retry loading the canonical mapping","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"limit","heading":"Why the cap is 256 steps","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"The constructor requires deploymentAddresses.length <= uint256(type(uint8).max) + 1 , which is 256 . The limit exists because the result is a single uint256 , and each tracked step consumes one bit. Indices 0 through 255 are supported. A deployment process with more than 256 tracked addresses must split status across multiple masks or use a different representation.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"interpretation","heading":"Interpretation and verification boundaries","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Evidence What it proves What it does not prove Bit set Runtime bytecode exists at the configured address. Correct bytecode, constructor values, wiring, permissions, or operational readiness. Bit clear No runtime bytecode was observed at that address by this call. Whether the address is intentionally empty or the manifest is wrong. Manifest match The decoder used the intended ordered address list for the network. That deployed code matches the release or that remote procedure call (RPC) responses are honest. Full deployment verification Code hashes, required wiring, permissions, and manifest provenance can be checked together. Economic safety or future operational liveness.","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"interpretation","heading":"Static decoder test vectors","keywords":[],"path":"reference/deployment-status.html","sectionTitle":"Reference","summary":"Deployment progress bitmask semantics, per-network bit mappings, and the 256-step limit.","text":"Mask Meaning 0x0 No tracked constructor address contains runtime code. 0x1 Only constructor address index 0 is present. 0x5 Constructor address indices 0 and 2 are present. 2^255 Only the highest supported bit, index 255, is present. The interactive tables require JavaScript. The ordered source lists are available in the mainnet deployment manifest and Sepolia deployment manifest ; bit i always corresponds to the i th constructor address after excluding deploymentStatusOracle .","title":"Deployment status oracle","topic":"Contracts","weight":0},{"fragment":"","heading":"","keywords":["MMR","carry proof","hashing","nullifier"],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Statoblast uses a Merkle Mountain Range (MMR) only for inherited escalation carry: the unresolved deposits a parent Escalation Game exports when its universe forks. Each child universe 's continuation game, the child Escalation Game that resumes the dispute during fork continuation , verifies withdrawals against those compact snapshots without replaying the full parent history on-chain. The hashing primitives live in MerkleMountainRange.sol . Snapshot storage, proof structs, peak bounds, and replay protection live in EscalationGameTypes.sol , EscalationGameCarry.sol , and EscalationGameProofVerifier.sol . Local carry appends live in EscalationGameDepositDelegate.sol .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":1},{"fragment":"leaf-shape","heading":"Leaf fields","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each leaf commits to one unresolved deposit. The encoding fixes the field order and hashing. Field Why it is committed depositor Binds the payout to the original depositor; see VAULT-04 . outcome Separates Invalid, Yes, and No carry domains. amountAttoRep Commits to the source principal. parentDepositIndex Provides the stable identity that selects the deposit's leaf in the nullifier tree , the per-continuation record of claimed carried deposits that prevents a proof from being replayed. cumulativeAmountAttoRep Preserves payout-order prefix data. sourceNodeId Distinguishes otherwise identical leaves copied from different local nodes.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"encoding","heading":"Normative encoding","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"The leaf ABI types are (address,uint8,uint256,uint256,uint256,uint256) , in the order depositor, outcome, amountAttoRep, parentDepositIndex, cumulativeAmountAttoRep, sourceNodeId . outcome is the Solidity enumeration ordinal ( 0 Invalid, 1 Yes, 2 No). Leaf hashing uses standard ABI word padding through abi.encode ; parent hashing uses the 64 raw bytes from abi.encodePacked(left, right) , so the order of left and right is significant. There is no additional domain separator. leafHash = keccak256(abi.encode(depositor, outcome, amountAttoRep, parentDepositIndex, cumulativeAmountAttoRep, sourceNodeId)) parentHash(left, right) = keccak256(abi.encodePacked(left, right)) // peaks[0..peakCount-1] are the occupied peaks in ascending height order bagPeaks(peaks, peakCount): if peakCount == 0: return bytes32(0) root = peaks[peakCount - 1] for i = peakCount - 1 down to 1: root = parentHash(peaks[i - 1], root) return root The fold starts at the highest occupied peak and places each lower peak as the left operand. With occupied heights 0 , 2 , and 3 , the root is parentHash(peak0, parentHash(peak2, peak3)) . A single peak is the root itself, and an empty range has root bytes32(0) . Proof verification rejects each of the following with the quoted revert string: an outcome whose snapshot has no leaves: Carry peak absent ; a zero amountAttoRep : Proof amount zero ; leafIndex >= leafCount : Bad carry leaf ; a merkleMountainRangePeakIndex that is not the height of the peak containing leafIndex : Bad carry peak ; a sibling array whose length is not peakHeight + peakCount - 1 : Bad MMR proof length ; a reconstructed root that differs from the bagged snapshot peaks: Bad carry proof ; a nullifier path whose length is not 64 : Bad nullifier length ; a nullifier path that does not reproduce the current nullifier root from an empty leaf, which includes an already-consumed nullifier: Bad nullifier proof .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"encoding","heading":"Conformance vectors","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Input or intermediate Value Leaf 0 ABI values 0x0000000000000000000000000000000000000001, 0, 1, 0, 1, 0 Leaf 0 hash 0xb01042d963a0c261d64893dfb7e1f221c93ef608653cb92f9ca2c8899ca4572b Leaf 1 ABI values 0x0000000000000000000000000000000000000002, 1, 2, 1, 2, 1 Leaf 1 hash 0xe0ca39e8852dc96783e8b8f0859cfbf155338f9144ba4b9fdd6af847299fc867 Two-leaf root 0x1c9c7f3c2c8bebf92ce393deb5dccdd253f2b10084af72defb5dcd4486832b27 Leaf 2 ABI values 0x0000000000000000000000000000000000000003, 2, 3, 2, 3, 2 Leaf 2 hash 0x92b2040f7e9b4f1e1b587eda2fb255419704a6ea1693789658adfddbf98389ae Three-leaf root 0x3488c83edd77c5259c9432e90f972d45d0ced819fd3691eddfe41fe05d676564 Empty nullifier root 0xe2c3ed4052eeb1d60514b4c38ece8d73a27f37fa5b36dcbf338e70de95798caa","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"peaks","heading":"Peaks and the 64-peak bound","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"The carry snapshot stores one peak per set bit in the leaf count. The system fixes MERKLE_MOUNTAIN_RANGE_MAX_PEAKS = 64 , and carry initialization requires each snapshot leaf count to be less than 2^64 . The constant caps the number of peak positions, not the number of leaves: any leaf count from 0 up to but not including 2^64 fits inside 64 peak slots. A leaf count of thirteen is shown as binary one one zero one, corresponding to occupied peaks at heights zero, two, and three which are later bagged into one root. MMR peaks. The occupied peak heights are exactly the set bits in the snapshot leaf count. To form one root, the verifier collects the occupied peaks in ascending height order and folds them with bagPeaks . snapshotLeafCount < 2 64 Carry initialization rejects a larger leaf count with Leaf count high . Local carry appends behave like binary addition with carries: a new leaf merges upward through occupied lower peaks until it finds the first empty peak slot. If that upward carry would reach height 64 , the append reverts with MMR too tall .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"proofs","heading":"Proof structure","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"A carried-deposit proof has two parts. First it proves membership in the inherited MMR snapshot for one outcome. Then it proves that the same parentDepositIndex has not already been consumed in this continuation's nullifier tree. Component Purpose leafIndex , merkleMountainRangePeakIndex , merkleMountainRangeSiblings Proves the carried deposit belongs to the inherited snapshot root for that outcome. nullifierSiblings Proves the nullifier leaf is still empty so the carried deposit cannot be replayed. The membership lane combines the carried deposit leaf with bottom-up siblings inside its selected peak, then with other occupied peak roots in ascending height order to reconstruct the snapshot root. The nullifier lane hashes the stable parent deposit index and combines it with a fixed-depth sibling path to prove the claim has not already been consumed. Carry proof anatomy. The MMR sibling array first reconstructs one selected peak and then supplies every other occupied peak. The independent 64-level nullifier path prevents the same stable deposit identity from being consumed twice. merkleMountainRangePeakIndex is the occupied peak height, not the ordinal position of that peak among occupied peaks. leafIndex is the leaf's global position across the whole snapshot. The verifier derives the peak that contains that position, requires merkleMountainRangePeakIndex to equal its height, and orders the in-peak siblings by the in-peak offset leafIndex - peakStart , where peakStart is the peakStartIndex returned by getCurrentCarryPeakForLeaf . Claim accounting also keys inherited-versus-local provenance and settled principal by the global position. For example, if the full snapshot has 13 leaves, the height- 3 peak holds global leaves 0 through 7 , the height- 2 peak holds 8 through 11 , and the height- 0 peak holds 12 . A proof for the third leaf of the height- 2 peak uses merkleMountainRangePeakIndex = 2 and leafIndex = 10 ; its in-peak offset is 2 . merkleMountainRangeSiblings is also ordered in two phases. The first merkleMountainRangePeakIndex entries are the bottom-up Merkle siblings inside the selected peak. The remaining entries are the other occupied peak roots in ascending peak-height order, skipping the selected peak height. That exact ordering is why the verifier checks merkleMountainRangeSiblings.length == peakHeight + peakCount - 1 .","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"nullifier-tree","heading":"Nullifier tree","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each continuation outcome keeps a binary Merkle tree of fixed depth NULLIFIER_DEPTH = 64 , hashed with the same parentHash . The path is uint256(keccak256(abi.encode(parentDepositIndex))) . Only its low 64 bits are used: bit d , counted from the least significant bit, selects the side at depth d , starting at the leaf. A 0 bit hashes parentHash(node, sibling) ; a 1 bit hashes parentHash(sibling, node) . An unconsumed leaf is bytes32(0) ; a consumed leaf is bytes32(uint256(1)) . The empty root is bytes32(0) hashed with itself 64 times: root = parentHash(root, root) . Its value is in the conformance vectors . nullifierSiblings lists the 64 siblings from the leaf upward. The verifier recomputes the current root with the empty leaf, then stores the root recomputed with the consumed leaf.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"mmr-proof-planner","heading":"Plan a carry proof","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Choose a snapshot leaf count and one occupied peak. The planner reports the global leafIndex range of that peak, checks an in-peak offset, and reports the exact sibling-array lengths the verifier enforces. It does not construct hashes or replace an off-chain proof builder. Selection Valid in-peak offset Selected peak capacity 4 leaves; leafIndex 8…11 Snapshot Snapshot leaf count Occupied peak height Height 2 Proof position In-peak offset MMR sibling hashes required 4 Nullifier sibling hashes required 64 Binary leaf count 1101₂ Occupied peak heights 0, 2, 3","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"snapshots","heading":"Snapshots in child continuations","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"Each continuation outcome stores both an inherited snapshot baseline and a mutable current state. Field Meaning snapshotLeafCount and snapshotPeaks The immutable inherited carry commitment. currentLeafCount and currentPeaks The descendant carry snapshot after inherited snapshot initialization plus local carry appends and local carry-leaf removal. Inherited proof consumption is tracked by currentNullifierRoot and unresolved totals rather than by mutating these peak fields directly. inheritedUnresolvedTotalAttoRep and localUnresolvedTotalAttoRep The principal totals the current carry state must still represent. currentNullifierRoot The replay-protection root after any carried proof has been consumed. getForkCarrySnapshot() reports the current carry peaks, leaf counts, totals, and nullifier roots after local appends and proof consumption. getCarryLeafPageByOutcome() pages only local unresolved leaves.","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"sources","heading":"Sources","keywords":[],"path":"reference/merkle-mountain-range.html","sectionTitle":"Reference","summary":"Carry-proof encoding, peak bagging, proof shape, nullifier tree, and bounds.","text":"MerkleMountainRange.sol EscalationGameProofVerifier.sol EscalationGameCarry.sol EscalationGameTypes.sol EscalationGameDepositDelegate.sol","title":"Merkle Mountain Range carry proofs","topic":"Mechanisms","weight":0},{"fragment":"","heading":"","keywords":["Statoblast","markets","security pools","overview"],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"Prediction markets Follow one question: “Will the fictional Aurora spacecraft launch before 31 December 2030?” Statoblast creates a collateralized market with Yes, No, and Invalid shares, resolves ordinary disagreement locally, and uses Zoltar branches only when local resolution cannot produce a decision or another fork interrupts the pool.","title":"How Statoblast works","topic":"Protocol","weight":1},{"fragment":"mental-model","heading":"1. Mental model","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Statoblast is the market layer. For each question, universe, and pool configuration (security multiplier and oracle priority fee) it deploys one SecurityPool that holds ETH settlement collateral , tracks vault owners' underwriting commitments , and mints, migrates, and settles shares. Zoltar owns the questions, universes, REP, and forks underneath it; Trading and OpenOracle sit beside it. The system overview introduces all four. The example question enters a SecurityPool. Local reporting may resolve the market or produce a non-decision; an independent fork of the pool's universe can also interrupt the pool while it remains unresolved and operational. Either fork trigger leads through child migration, collateral repair where needed, and branch-specific redemption. Market lifecycle. Local resolution is the ordinary route. An own-question non-decision or an independent universe fork while the pool remains unresolved and operational enters the migration and collateral-repair route.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"normal-lifecycle","heading":"2. Normal market lifecycle","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Register the example question in Zoltar and deploy its SecurityPool in one universe. Vault owners deposit REP; traders deposit ETH to mint complete sets. Traders may exchange shares through an exchange such as Trading . After the question ends, the first REP deposit on an outcome opens the Escalation Game . An unchallenged report wins three days later; a contested game runs until one outcome is the strict leader at its deadline. Holders then redeem winning shares from the pool's settlement collateral. ETH mints Invalid, Yes, and No shares. Operational pools redeem full sets, and finalized winning shares redeem through outcome settlement. Share lifecycle. One unit of ETH mints matching Invalid, Yes, and No claims; the complete set can be burned while the pool is operational or the winning share redeemed after finalization.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"participants-assets","heading":"3. Participants and assets","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# Traders and liquidity providers Mint complete sets, hold or trade outcome shares, redeem claims, and optionally provide Yes/No liquidity. Vault owners Deposit REP, set a separate underwriting commitment in ETH, keep it backed, earn fees, and may report or migrate. Reporters Place REP-backed positions on Invalid, Yes, or No in the Escalation Game. Liquidation receivers and operators A receiver vault accepts a transferred underwriting commitment and receives REP backing. An operator submits the operation but receives no automatic protocol payment. Truth Auction bidders Supply ETH in exchange for child-pool REP-backed accounting positions when a child needs collateral repair. Asset or claim What it represents Where it is held or recorded ETH settlement collateral Backing for outstanding complete sets The SecurityPool; it is allocated, not copied, during migration REP Universe-specific reporting and security capital; never settlement collateral Wallets, SecurityPool vault accounting, Escalation Games, or migration contracts Outcome shares Yes, No, or Invalid claims for one pool and universe An ERC-1155 ShareToken deployed once per origin pool and reused by all of its fork descendants Underwriting commitment ETH a vault owner agrees to underwrite; its share of the pool total sets the vault's collateral obligations and fee rights SecurityPool vault accounting Escalation claims REP-backed positions on reported outcomes The Escalation Game until claimed or migrated Trading LP tokens A claim on one trading pool 's Yes and No reserves The trading pool's ERC-20 ledger","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"local-resolution","heading":"4. Local resolution","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# The game opens with the first REP deposit after the question ends. REP-backed balances then accumulate behind Invalid, Yes, and No. Their median is binding capital and determines the moving deadline. After that deadline, exactly one strict balance leader produces the local winner. Winning shares redeem from that pool. If two outcomes reach the non-decision threshold , the game does not choose between them. Anyone can then fork the universe on the market question through Statoblast, which pays the fork threshold from the REP held by the pool and the game. See the Escalation Game explanation for the required-support curve, deadlines, payouts, and how games continue across forks.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"forks-migration","heading":"5. Forks and migration","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# An unresolved operational pool can enter the fork path in two ways. Its own Escalation Game can reach non-decision and fork Zoltar on the market question; in this example, that creates Invalid, Yes, and No children. A fork of the pool's universe on another question can also interrupt it, in which case the children represent that categorical or scalar question's valid answers. A finalized pool remains settled and rejects later fork migration. A pool moves from active operation through fork, child deployment, REP and collateral migration, and any auction repair to an operational child. Fork timeline. The parent halts permanently; each child becomes operational only after migration and any required repair. Migration is open for a migration window of eight weeks, counted from the call that puts the parent pool into fork mode. A vault's parent backing claim, underwriting commitment, and proportional pool collateral are routed into one selected child pool. The same parent vault migration cannot be reused across siblings. Eligible outcome-share balances work differently: users can materialize branch-specific ledger claims in multiple selected child pools. That reproduces claims, not ETH; see what Zoltar does not guarantee . The full eligible source balance can materialize in each selected child as a separate branch claim, while the source remains locked. ETH is not copied. Share migration. Branch-specific token claims may appear in more than one child; settlement collateral follows vault migration and remains finite. If a child receives too little ETH, it can sell child REP through a one-week Truth Auction, which anyone can start once the migration window has closed. Full demand can repair the shortfall; weak demand can leave redemption below face value. A child begins with a collateral shortfall. Auction ETH may fully repair it, partially repair it, or leave it unchanged when there is no demand. Collateral repair. The auction raises what demand supports and never selects truth.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"fees-capacity-liquidations","heading":"6. Fees, underwriting, and liquidations","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# REP deposits do not create underwriting commitments; each vault owner sets one separately. A vault's share of total commitments sets its share of the pool's settlement collateral obligations and of the open-interest fees that outstanding collateral pays. New complete sets can be minted only while total commitments cover the resulting collateral and no Escalation Game has opened. Minting needs no oracle price or backing check, because vault owners already answer for their full commitments ( invariant BAL-03 ). A vault whose REP no longer backs its commitment can be liquidated: some or all of its commitment and backing move to an authorized receiver vault. See vault liquidation .","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"security","heading":"7. Security assumptions and non-guarantees","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"# REP-backed incentives do not prove objective truth; users and applications decide which branches retain activity. OpenOracle depends on timely, profitable correction of inaccurate REP/ETH reports. A fork gives each child only the ETH that migrates to it ( Zoltar's non-guarantees ). ETH pushed into a pool outside its accounting is not counted as collateral. Steps that anyone may trigger, such as forking or starting an auction, still need someone to send the transaction. Spot prices from trading pools are manipulable and are never protocol oracles. Normative assumptions and guarantees are listed in the security model and invariant catalog .","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"security","heading":"Design rationale","keywords":[],"path":"explanation/statoblast.html","sectionTitle":"Explanations","summary":"A market lifecycle from creation through local resolution or fork migration to redemption.","text":"Statoblast's ancestry includes the Arctic Tern Oracle , Sisyphean Exchange , Partial Colored Coins , and Isonzo . Those research ideas influenced the design; the deployed contracts govern current behavior.","title":"How Statoblast works","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["Zoltar","universes","questions","REP"],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"Branching universes Zoltar records global questions and lets an eligible parent universe branch into outcome-specific child universes . Each child universe has its own REP ledger, and REP holders move into children under fixed migration rules.","title":"Zoltar and branching universes","topic":"Protocol","weight":1},{"fragment":"branching","heading":"A parent becomes separate child ledgers","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# For a binary market question, one forking parent universe creates separate Invalid, Yes, and No child ledgers. An unrelated fork instead follows its own fork question's valid answers. Forking parent Invalid branch Valid outcome branches Branch set. A binary launch question produces Invalid, Yes, and No children. Alice converts 100 parent REP into a migration balance , a parent-universe credit that can mint the same amount in each valid child, and uses it to mint 100 child REP in the Yes universe and 100 child REP in the No universe. These are separate branch-specific ledgers. They are not 200 globally interchangeable REP, they do not copy ETH, and Zoltar does not guarantee equal economic value across branches. Applications and users later determine where economic activity continues.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"questions","heading":"Global questions and fork eligibility","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Questions are global Zoltar objects and are not bound to a universe. Any account can fork a universe by naming a question when three conditions hold: the universe has not forked before, so each universe forks at most once; the question exists and its end time has passed; and the caller supplies the full fork threshold in that universe's REP. Zoltar does not check that the question concerns the universe, so applications such as Statoblast enforce any stricter relationship they need. The fork question decides which child universes can exist: one for each of its valid answers. A categorical question allows Invalid and each of its labels. A scalar question allows Invalid or a well-formed packed scalar answer. Zoltar sets no migration deadline; REP holders can add to their migration balance at any time after the fork.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"guarantees","heading":"What Zoltar guarantees","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Universe and child identities derive deterministically from their parent and outcome. Only valid outcomes for the fork question can create child universes or receive child REP. Each account cannot mint more REP into one child than its recorded migration balance permits. Child REP is controlled by Zoltar and remains tied to its universe identity. Every child starts with the parent's pre-fork theoretical REP supply , the per-universe supply figure from which fork thresholds are derived, less exactly the fork haircut .","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"non-guarantees","heading":"What Zoltar does not guarantee","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# It does not choose a truthful or canonical child. It does not copy ETH or application state into every child. Each child receives only the collateral that migrates to it, so a Statoblast child pool can remain impaired if too little ETH follows and its Truth Auction cannot raise the difference. It does not guarantee equal REP value, liquidity, or redemption across branches. It does not prove a supplied global question is relevant to the universe being forked. It does not guarantee that applications continue in every branch.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"accounting","heading":"Deterministic identities and migration accounting","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# A child universe ID is derived from its parent universe ID and selected outcome. Child REP uses a predictable deployment address derived from the Zoltar address and universe ID. Adding parent REP to a migration balance burns or transfers it from the parent ledger. That balance can then materialize the same branch-specific amount in multiple valid children, with per-child accounting preventing replay beyond the source amount. Starting a fork removes the fork threshold from parent supply. The threshold is the live universe theoretical REP supply divided by the threshold divisor, rounded up, so every universe with nonzero supply has a positive fork cost. The fork haircut, the threshold divided by the burn divisor and rounded down, is not credited to migration; the remainder becomes the initiator's migration balance. Both divisors are fixed when Zoltar is deployed. The configured defaults are a threshold divisor of 20 and a burn divisor of 5: the threshold is 5% of supply and the haircut is 20% of the threshold, about 1% of supply. Zoltar rejects a burn divisor below 5, so the haircut never exceeds 20% of the threshold. The full fork threshold leaves parent supply. Most becomes the initiator's migration balance and the fork haircut is not credited. Fork deposit. The default split, subject to integer rounding. fork threshold = ⌈live theoretical REP supply ÷ threshold divisor⌉ fork haircut = ⌊fork threshold ÷ burn divisor⌋ Each fork reduces theoretical supply by its fork haircut, so later thresholds decline along that lineage. Repeated forks. Integer-rounded fork haircuts reduce theoretical supply and therefore later fork thresholds.","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"encodings","heading":"Question and outcome encodings","keywords":[],"path":"explanation/zoltar.html","sectionTitle":"Explanations","summary":"Universes, question encoding, global forks, and REP splitting.","text":"# Question IDs hash the stored question data together with the outcome labels, which a categorical question must supply in strictly descending order of their hashes. A categorical answer is 0 for Invalid or a number from 1 to n that selects one of the n labels in that order. Scalar questions store a range and tick count; a valid packed answer allocates all ticks between its two payout fields. The all-zero word is canonical Invalid, while reserved-bit or payout-sum violations are malformed and rejected. A scalar answer contains reserved bits, a namespace bit, and first and second payout numerators. Valid payout fields sum to the question's tick count. Namespace bit First payout Second payout Packed scalar answer. Encoding validation keeps Invalid distinct from malformed input. Exact storage fields, permissions, and entrypoints are listed in the contract reference . Security assumptions are listed in the security model .","title":"Zoltar and branching universes","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["Trading","AMM","liquidity","prices"],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Explanation Trading is a separate on-chain exchange for Statoblast outcome shares , one of possibly many that can be built on Statoblast. Statoblast still owns market creation, collateral, migration, resolution, and redemption through each market's SecurityPool .","title":"How Trading works","topic":"Trading","weight":1},{"fragment":"complete-set-entry","heading":"From ETH to a directional position","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Each ETH entry first creates a complete set : one Yes, one No, and one Invalid share. A market's trading pool , a Yes/No pair, is an automated market maker (AMM) that holds only Yes and No reserves. The router sends the unwanted directional share into the pair, receives more of the selected directional share, and returns the directional position and the Invalid share to the user. The Invalid share never enters the AMM; it remains a separate claim if the market later resolves Invalid.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"prices","heading":"What the prices mean","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Yes and No prices are conditional on valid resolution. They describe the relative price of the two directional outcomes; they are not estimates of invalidity. Interfaces should therefore label the Yes and No values directly and present Invalid separately. Spot prices come from current reserves and are not an oracle . Settlement uses the SecurityPool's resolved outcome, while solvency-sensitive REP/ETH operations use OpenOracle.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"market-isolation","heading":"One pair per SecurityPool","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Each SecurityPool maps to its own pair. Parent and child pools therefore have separate pairs, reserves, prices, and liquidity-provider tokens; liquidity, like everything else in a fork , is not copied between them.","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"reading-paths","heading":"Where to go next","keywords":[],"path":"explanation/trading.html","sectionTitle":"Explanations","summary":"Complete sets, directional liquidity, conditional prices, and market isolation.","text":"Learn by doing Your first Trading market and your first trade . Get something done Set up development , configure the UI , deploy the contracts , seed alternative odds , exit a position , remove liquidity , handle resolution , and handle a fork . Understand the design The two-way market , Invalid insurance , conditional pricing , the LP position , early-exit limits , forks and resolution , architecture decisions and limitations . Look something up Contracts , router , events , SDK , deployment configuration , invariants , units and rounding , and the security model .","title":"How Trading works","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Escalation Game","disputes","deadlines","accounting"],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The Escalation Game gives a finished Statoblast market a local, REP-backed resolution path before a universe-wide fork is necessary. A report that nobody challenges wins three days after the first deposit opens the game. For a binary launch question, suppose Yes has 8 REP, No has 5 REP, and Invalid has 2 REP. The median balance, 5 REP, is the game's binding capital : the stake the strongest challenger has committed, and the amount that sets the scheduled deadline. A deposit that raises only the leading Yes balance does not move that deadline; a deposit that raises Invalid above 5 REP raises the median and moves it later. After the deadline, Yes wins only if it remains the unique strict leader. If two outcomes each reach the non-decision threshold before local finalization, the game records non-decision and the SecurityPool follows the Zoltar fork path. The threshold is half of Zoltar's fork threshold , rounded up, and is fixed when the game opens. A tie is never treated as a local winner. Any REP holder can deposit from a wallet, except in a game carried across a fork. A vault owner can instead deposit REP that already backs their vault; those deposits must additionally leave the vault and the pool sufficiently backed. Each deposit must meet the start bond , the larger of 1 REP and one ten-millionth of the universe's theoretical REP supply when the pool was deployed, unless it exactly fills an outcome to the non-decision threshold.","title":"Escalation Game","topic":"Protocol","weight":1},{"fragment":"escalation","heading":"Escalation","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The first deposit after the question ends opens the game. Each deposit adds to its outcome's cumulative balance; it does not have to exceed the leader. Meanwhile the required support rises along a fixed curve over time. The game's deadline is the moment required support overtakes binding capital, so the deadline moves later only when a deposit raises the median balance. A challenger that stops adding REP lets the rising requirement pass its stake, and the leader wins. Required support is zero through day 3, starts at the start bond just after day 3, and reaches the non-decision threshold on day 52. Required support. Nothing is required for the first three days. From day 3 the requirement climbs from the start bond to the non-decision threshold, reaching it on day 52. The EscalationGame reference gives the exact curve.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"escalation-game-example","heading":"Try a simplified escalation round","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"This simulator uses the contract model: a three-day activation delay, a 49-day escalation interval, and the fixed-point required-support curve. Change the configuration, then choose an outcome and requested deposit to see clipping, tie adjustment, acceptance, or rejection. Deposit result accepted: 1 REP Contract-model state activation pending Game settings Start bond 1 REP Non-decision threshold 10 REP Player positions Current Yes balance 1 REP Current No balance 1 REP Current Invalid balance 0 REP Player move Deposit outcome Yes No Invalid Requested deposit 1 REP Timeline Days since start 0 days Yes 1 → 2 REP No 1 → 1 REP Invalid 0 → 0 REP Configured start bond 1 REP Configured threshold 10 REP Projected leader Yes Projected median balance 1 REP Deposit before → after Yes 1 / 2 REP; No 1 / 1 REP; Invalid 0 / 0 REP Activation 3 days Scheduled deadline (before → after) day 3.0 → day 3.0","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"How the game ends","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"The game ends in one of three ways: Strict local winner. After the scheduled deadline, exactly one outcome has the greatest balance. Statoblast finalizes on that outcome. Local non-decision. Two outcomes reach the non-decision threshold. Statoblast uses its fork path instead of choosing one locally. Interruption by another fork. The pool's universe forks on a different question at or before the deadline. The game has no local result and continues in the child pools instead; see forks and migration . Settlement rewards the side that held its ground. Winning deposits get their principal back plus a bonus. The runner-up's stake, the binding capital, pays for it: three fifths becomes the bonus pool and two fifths, the escalation haircut , is burned, unless the fork this game triggered already burned it as the fork haircut . REP staked on a third outcome is forfeited: a local game sweeps it to the SecurityPool, while a game carried across a fork burns it. The bonus is only available on the portion of winning deposits up to the reward-eligible cap , one and a half times binding capital; deposits beyond that cap simply get their principal back. Settlement also compares the universe's current fork threshold, in full, with the non-decision threshold the game fixed when it opened. If the current fork threshold is the lower of the two, every winning withdrawal is multiplied by the current fork threshold divided by that non-decision threshold, which can push the final transfer below principal. The comparison is skipped when the universe forked after the game ended. The EscalationGame reference works one payout through with exact numbers.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"Escalation game continuation","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"When a fork interrupts an unresolved game, Statoblast's SecurityPoolForker restarts it in each child pool as a carried game with the parent's balances and elapsed time. In a child created by a fork on the pool's own question, the outcome is already fixed to that child's outcome, so the game only settles deposits on it. After an unrelated fork, the game resumes and can still be contested, but only with vault-backed deposits. Depositors claim their positions in a child with a Merkle Mountain Range carry proof against the parent's deposit history, so no child copies every deposit onchain.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"payouts","heading":"Design rationale","keywords":[],"path":"explanation/escalation-game.html","sectionTitle":"Explanations","summary":"How REP deposits resolve a market locally, when they force a fork, and how games continue across forks.","text":"Augur V2 cancelled active dispute games when a fork began and refunded their participants. Statoblast instead continues active games across the fork so a fork cannot erase the stakes players already put at risk. See the research note Zoltar forks should not cancel escalation games for the historical motivation.","title":"Escalation Game","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["liquidation","underwriting commitment","backing constraints","operator","receiver vault","approval","reservation","bad debt"],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Liquidation moves part or all of an unhealthy vault's underwriting commitment , with a capped REP award, to an authorized receiver vault. The receiver must back its entire resulting commitment. Total commitments remain constant, so unrelated vaults retain their proportional obligations. The account that submits the liquidation receives no automatic protocol payment.","title":"Vault liquidation","topic":"Economics","weight":1},{"fragment":"position-model","heading":"Target, receiver, and operator","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"The target vault is the unhealthy vault whose commitment is reduced. The receiver vault accepts the transferred commitment and receives the REP award. The operator requests and stages the liquidation, paying that transaction's gas and any oracle cost. If the liquidation remains staged, any account may execute it later and pay the execution transaction's gas. The operator recorded at staging does not change when another account executes. The receiver and target must differ. The operator may be either one, but identity alone is not a health or Sybil-resistance boundary. Staging through the generic requestPriceIfNeededAndStageOperation call makes the operator the receiver and requires no signed approval; requestPriceIfNeededAndStageLiquidation names the receiver explicitly; a receiver other than the operator also needs a delegated approval. The first release assumes the operator and receiver coordinate compensation externally; the protocol neither creates a keeper marketplace nor takes a fee from the award.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"capacity-and-health","heading":"When a vault is liquidatable","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Each owner sets an underwriting commitment separately from REP deposits. A price change affects health, not commitments. Each vault covers settlement collateral in proportion to its share of total commitments, but health is measured against its entire commitment, so a vault may be liquidatable with zero settlement collateral. Vault health combines two backing constraints, each evaluated with upward rounding at the coordinator's fresh accepted oracle price . That price is quoted as REP per ETH, so a higher price means cheaper REP and a larger REP requirement. The associated-REP constraint requires pool-held backing plus eligible dispute stake to cover the commitment's REP value times the pool's security multiplier . The pool-held constraint requires pool-held backing alone to cover that REP value times a second multiplier: halfway between one and the security multiplier, but never below the liquidation reserve of 10,500 BPS (one plus the 5% award bonus). The reserve means a vault that meets the pool-held constraint holds enough REP to pay a full liquidation award. A liquidation executes only when the target fails at least one constraint, the oracle price exceeds the price at which the target first fails a constraint by at least minLiquidationPriceDistanceBps of the oracle price (10% in the deployment configuration), and neither the target nor the receiver carries bad debt . The distance guard keeps a slightly wrong accepted price from liquidating a vault that is only marginally unhealthy. The SecurityPool reference specifies the exact checks. A delegated approval may demand that the receiver be healthier than the protocol minimum after the transfer. That requirement is checked against live post-liquidation state at execution; a queue-time preview is never a guarantee. The LiquidationApprovalRegistry reference defines the field.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"rule","heading":"Commitment transfer and residual exposure","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"The requested amount bounds the commitment transferred. The REP award is the moved commitment's REP value at that price plus a 5% bonus, capped by the target's transferable backing; a partial liquidation also leaves the target its minimum REP deposit. A sufficiently funded receiver can take the entire commitment even when the award is underfunded. Partial liquidation leaves the residual commitment with the target; it writes off nothing and deletes no settlement liabilities. Commitment and capped REP move from the target to the receiver. Total commitments stay constant. Residual commitments and earned fees remain with the target. Commitment transfer. The receiver authorizes the transferred commitment and backs its entire resulting commitment. The receiver must authorize the transferred commitment and satisfy both backing constraints for its entire resulting commitment. Remaining target commitments and receiver positions must meet the minimum sizes. Earned fees stay with their owners and are checkpointed before weights move. Retained underbacked commitments continue earning fees; poor health does not suspend fee rights. The contract reference specifies award rounding.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"receiver-approvals","heading":"Bounded receiver approval","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"A receiver can approve an operator directly or by a bounded signature. The approval is specific to a pool, limits how much commitment the receiver will accept, sets a validity window and minimum resulting health, and can be revoked for future liquidations. A liquidation that is already staged keeps its reservation. See the LiquidationApprovalRegistry reference for fields, nonce rules, and wallet-signature handling.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"queue-semantics","heading":"Reservation and queued execution","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"When the receiver is not the operator, the price coordinator reserves the receiver's approval quota when the liquidation is staged, whether it runs immediately on a fresh REP-per-ETH price or waits for one. Execution then rechecks the live target and receiver rather than trusting the earlier preview. Success consumes only the commitment actually moved and releases unused quota; expiration or terminal failure releases the reservation so the receiver is not blocked permanently. The REP/ETH oracle operations reference covers staging, recovery, and failure handling.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"fork-behavior","heading":"Fork isolation","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"Approvals and reservations belong to one pool and its coordinator and are not copied into child pools or universes; see what Zoltar does not guarantee . A receiver approving liabilities in one universe has not approved them in a child. Pending parent operations remain permissionlessly cleanable after the parent becomes unable to execute, releasing their reservations.","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"related-references","heading":"Related references","keywords":[],"path":"explanation/liquidations.html","sectionTitle":"Explanations","summary":"Liquidation eligibility, roles, REP awards, bounded receiver approvals, and reservation lifecycle.","text":"SecurityPool functions and accounting Liquidation approval fields and signatures Price-coordinator operations and recovery","title":"Vault liquidation","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["fees","open interest","retention","utilization","vaults"],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"Each SecurityPool charges an open-interest fee on its outstanding settlement collateral and pays it to the vaults that underwrite that collateral. The contracts express the fee as retention : the per-second fraction of collateral that stays with complete-set holders.","title":"Open-interest fees","topic":"Economics","weight":1},{"fragment":"why-fees-exist","heading":"Why the fee exists","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"Vault owners provide REP-backed security, keep their vaults healthy, and may need to take part in reporting and migration. In return, each fee-eligible underwriting commitment earns a share of the fee in proportion to its size. Collateral gradually decays into an unallocated fee reserve , and vault owners claim their shares from that reserve.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"rate","heading":"How the rate moves","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"The retention rate depends on utilization : settlement collateral divided by minting capacity , which equals the pool's total underwriting commitments, independent of price and backing. The per-second retention rate declines linearly as utilization rises and stops declining at the dip point, 80% utilization. Compounding the two per-second constants over a 365-day year, the annualized fee rises from about 9.5% at zero utilization to about 50.2% at the dip point and then holds. Security therefore becomes more expensive as open interest consumes underwriting slack. Retention and utilization curve. The annualized fee rises from its minimum at zero utilization to its maximum at the dip point, then remains flat. Annualized fee against utilization. Past the dip point the per-second retention rate is already at its minimum, so the fee stops rising. Minting capacity is zero when the pool has no commitments or once an Escalation Game has opened. The retention rate then returns to its maximum, MAX_RETENTION_RATE , which is the lowest fee, instead of treating the pool as fully utilized. The SecurityPool reference lists the constants, the dip point, and the formula clients use to annualize the rate.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"earning-and-cutoff","heading":"Who earns and when accrual stops","keywords":[],"path":"explanation/fees.html","sectionTitle":"Explanations","summary":"Why vaults earn a fee on open interest, how utilization sets the rate, and when accrual stops.","text":"A pool with no fee-eligible commitments accrues no fee. Fees charge only the fraction of settlement collateral assigned to fee-eligible commitments. Retained underbacked commitments keep earning fees, and previously earned fees remain claimable. Ordinary redemption reduces settlement collateral without retiring underwriting commitments. When a child pool's Truth Auction finalizes with no purchases, its unassigned commitment stays visible but has no fee recipient until a vault takes over the entire residual commitment and backing and fully backs the result. Fee eligibility starts at takeover, without retroactive rewards. Migrated commitments and sold auction commitments enter the fee denominator at finalization, even when a winning bidder claims later. Accrual stops at a cutoff. An origin pool uses question end. If its question remains unresolved when the universe forks, fork time replaces that cutoff in either direction: a fork before question end stops accrual early, and a fork during an unresolved Escalation Game moves the cutoff later, so the next accrual also charges the interval from question end to the fork. A later unrelated fork does not reopen fees for an already finalized question. A child starts a new epoch when migration and any Truth Auction finalize, then accrues until local resolution or another fork; a child with a fixed outcome and no continuation game accrues no further fees. Accrual is lazy: state-changing pool operations checkpoint a global fee index, and vault operations checkpoint each vault against it, so no call iterates over every vault. Fractional amounts wait in explicit remainders until they reach whole attoETH. See the subsystem guardrails for checkpoint and fork-reconciliation sequencing and the SecurityPool contract reference for exact state transitions.","title":"Open-interest fees","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["truth auction","clearing","settlement","repair"],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"When a universe forks, each unresolved Statoblast SecurityPool splits into child pools, one per child universe ( forks and migration ). Each vault owner moves its REP and its share of the parent's settlement collateral into one child of its choice, so a child receives only the collateral of the vaults that chose it. Suppose the parent held 100 ETH of settlement collateral when it forked and a child receives only 70 ETH through migration. The child inherits the parent's full share supply, so its Truth Auction tries to raise the missing 30 ETH by selling child REP. Full repair: bidders contribute 30 ETH, so the child reaches its 100 ETH target. Partial repair: bidders contribute 12 ETH, so the child operates with 82 ETH and remains impaired. No demand: no qualifying bid contributes ETH, so the child remains at 70 ETH. The auction repairs collateral and never selects truth. It sells REP belonging to an already-defined child universe. The child resumes with only the ETH that migration and accepted bids actually provide.","title":"Truth Auctions","topic":"Economics","weight":1},{"fragment":"lifecycle","heading":"Lifecycle","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"Auction Lifecycle. After migration closes, startTruthAuction either activates the child immediately when no sale is needed or opens bidding. During bidding, once demand establishes a clearing tick, bids below it may refund before finalization. Finalization later activates the child; paged calls then settle winning and partial bids plus any remaining refunds. Auction lifecycle. The no-sale branch skips bidding entirely. On the repair branch, early refunds are optional and every path reaches finalization before winning bids settle.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Starting the auction","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The start call is permissionless but not automatic. It is valid strictly after the parent pool's migration window , which lasts eight weeks from the call that put the parent pool into fork mode, and it records the actual auction start time. That timestamp starts the one-week bidding window.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Bidding","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"Bidders submit bids at discrete price ticks , where each tick represents a maximum price in ETH per REP that the bidder is willing to pay. This is the inverse of the REP-per-ETH oracle price that vault health uses. Ticks are spaced geometrically, so each step changes the price by the same small percentage, as in Uniswap. The auction reference gives the base price, the step factor, and the supported range. Losing bids can be settled before finalization once current demand is enough to find a clearing tick. Only ticks below that clearing tick can use the pre-finalization path; binding or potentially winning bids stay in the auction. Settlement credits refundable ETH to the recorded bidder without calling recipient code. The bidder then calls withdrawPendingEthRefund to pull the complete credit. Once a clearing tick is found, it cannot be lowered, so currently losing bids remain losing bids.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"lifecycle","heading":"Bidding end","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"When bidding ends, anyone may finalize the auction. Finalization clears the batch auction, sends the raised ETH to the child pool, and computes the accounting rates used to settle bidders. The child activates with the settlement collateral that migration delivered plus the accepted bid ETH, even when that total is below the parent's snapshot. Full repair is not guaranteed, and the remaining impairment is borne by the affected child's outcome-share holders, whose winning shares redeem below face value. Until winning bids are settled, the REP backing and commitment they bought sit in a position that no vault owns. Anyone may settle a winning bid, which credits the bidder's child-pool vault with its proportional REP backing units , underwriting commitment , and accrued fees; the auction does not send REP directly to the wallet. ETH pushed into the pool outside migration and the auction is not counted as collateral, so it cannot fake a successful repair.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"clearing","heading":"How clearing works","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The clearing process walks demand from the highest price downward. A bid above the clearing tick wins in full, a bid below it loses in full, and bids at the clearing tick share the last fill in the order they arrived. Two constraints limit how much the auction can clear: ETH raise cap. The auction raises no more ETH than the amount required to make share holders whole. REP sale cap. The auction sells no more REP than the child pool offers: its pool-held REP plus any REP staked in an unresolved Escalation Game, less a small retained residue. As soon as cumulative demand is enough to hit either cap at some price, that price becomes the clearing tick and all winning bids settle from it at one price. That is a valid uniform clearing even when the REP cap binds before the ETH repair target is fully met.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"clearing","heading":"When demand is too low","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"If demand never reaches either cap, only bids at or above the underfunded threshold participate: the price at which selling the whole REP sale cap would raise exactly the ETH raise cap. Lower bids receive refunds. Qualifying bidders share the whole REP sale cap in proportion to the ETH they contribute, so each pays the same effective price. With no qualifying demand, all bids refund and the child remains impaired. The contract uses bounded tick indexing and exact integer accounting so finalization does not loop over every possible price. See the auction contract reference for tick bounds, rounding, storage, and getter details, and the SecurityPoolForker reference for child-pool settlement accounting.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"interactive-example","heading":"Interactive clearing example","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The interactive example shows the uniform-clearing path, the underfunded path, and how the same bid ladder reacts when the ETH cap, REP cap, and bid sizes change.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"simple-auction-example","heading":"Try a simple auction clearing run","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The simplified calculator visualizes both finalized branches with three fixed price levels and real-number arithmetic. The clearing section specifies the contract's exact tick and cumulative-floor behavior. Mode uniform clearing near 3 ETH/REP ETH retained 12 ETH Auction settings ETH raise cap 12 ETH REP inventory 4 REP Player bids Alice bid near 5 ETH/REP 3 ETH Bob bid near 4 ETH/REP 4 ETH Carol bid near 3 ETH/REP 6 ETH High-price bids are considered first. If cumulative demand reaches the ETH raise cap or REP sale cap, the first binding tick sets normal uniform clearing. If neither cap is reached, finalization selects bids at or above the underfunded threshold and allocates the complete REP sale cap among them at one effective price. With no qualifying bids, every bid refunds. Interactive Demand Curve The stepped curve accumulates bids from the highest limit price to the lowest. The vertical rule is available REP, the horizontal rule is the current clearing price or underfunded threshold, and each bid point's shape and colour, named in the chart key, shows whether the bid wins in full, fills partly at the boundary, or is refunded. The chart updates as the auction controls change. Binding condition both caps Winning ETH kept not underfunded Underfunded threshold not underfunded Alice allocation 1.00 REP Bob allocation 1.33 REP Carol allocation 1.67 REP Total REP allocated 4 REP Refunds 1.00 ETH","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"three-auction-outcomes","heading":"What the contract reports","keywords":[],"path":"explanation/truth-auctions.html","sectionTitle":"Explanations","summary":"Auction clearing, settlement, and weak-demand loss allocation.","text":"The contract does not report full, partial, or no repair. It reports whether a cap bound: No auction runs when ETH migrated into the child already reaches the parent's settlement-collateral snapshot; the start call activates the child directly. A funded auction, reported by the funded field of the AuctionFinalized event, means a clearing cap bound. It is a full repair when the ETH raise cap bound and a partial repair when only the REP sale cap bound, so compare accepted ETH with the ETH raise cap. An underfunded auction means neither cap bound. It is a partial repair when some bids qualified at or above the underfunded threshold and no repair when none did. If the parent's Escalation Game was unresolved at the fork, part of the REP either kind of auction sells comes proportionally from REP staked in that game, and the child game's balances shrink to match. The SecurityPoolForker reference gives the allocation.","title":"Truth Auctions","topic":"Economics","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","price","coordinator","callback"],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"Explanation Statoblast needs a fresh REP/ETH exchange rate (quoted as REP per ETH) when it measures whether REP adequately secures ETH obligations. OpenOracle supplies an economically contestable price. A reporter posts a WETH/REP position at the claimed price, and anyone who believes the price is wrong can replace the report by trading against that position, so an inaccurate report is a profit opportunity. OpenOracle never decides whether a prediction-market answer is Yes, No, or Invalid.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":1},{"fragment":"protected-operations","heading":"Protected operations","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"A per-pool price coordinator protects REP withdrawals, liquidations, and staged changes to a vault's underwriting commitment , because each depends on REP value. Vault-backed Escalation Game deposits also require a fresh accepted price when the pool has any underwriting commitment; wallet deposits do not. Each SecurityPool still applies its own current health and authorization checks after a price is available.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"cached-and-fresh","heading":"Cached and fresh prices","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"An accepted report becomes the coordinator's cached price for a limited freshness window. An operation can use that cache while it remains fresh. When it is stale, a sponsor funds a new report and the coordinator stages eligible work until settlement. A child pool may inherit a numeric starting value, but it cannot use that value until the child accepts its own report. A cached fresh price may execute a guarded operation immediately. Otherwise an accepted settlement callback refreshes the price and runs a bounded batch; a rejected report terminally consumes its attached batch. Overflow operations remain active for later execution with a fresh price. Price-guarded operations. The price coordinator supplies a fresh input; the SecurityPool still enforces live safety.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"example","heading":"One request, dispute, and settlement","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"Alice requests a REP withdrawal from her own vault while the pool's cached price is stale. She funds an initial REP/ETH report plus a settlement bounty, and the coordinator records her pending operation. Bob believes the report is inaccurate, so he replaces it with the required opposing position before settlement. The dispute restarts the settlement window. If nobody replaces Bob's report before its new deadline, any account can settle it; that settler collects Alice's bounty, and OpenOracle calls the coordinator. The coordinator validates the report, refreshes its cache, and attempts Alice's withdrawal against the pool's live safety checks. Bob's replacement traded against Alice's position at her reported price, so she ends with a different mix of WETH and REP rather than her original deposit; the coordinator forwards whatever OpenOracle credits it for her report back to her. Her bounty is spent on settlement whether or not her withdrawal later succeeds. Alice's staged withdrawal expires once the settlement period plus her chosen validity window (at most five minutes) has passed since she queued it. Because Bob's dispute restarted the settlement window, the price may arrive after that point; her withdrawal then fails as expired and she must stage it again.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"limitations","heading":"Security limitations","keywords":[],"path":"explanation/open-oracle.html","sectionTitle":"Explanations","summary":"Why a contestable REP/ETH price guards solvency-sensitive operations, and where it stops.","text":"OpenOracle relies on participants noticing and profitably correcting inaccurate reports. Congestion, censorship, incorrect gas assumptions, insufficient economic incentives, or repeated disputes can delay or undermine that process. A fresh price is not a guarantee that an operation will succeed, and a settled price says nothing about the market question's outcome. Two limits are deliberate. First, the coordinator keeps no notional budget: one accepted price may authorize several operations during its freshness window, so the report position is a correction incentive rather than a bond sized to the value those operations move. Second, there is no absolute deadline: every valid dispute restarts the settlement clock, so a participant willing to keep funding replacements, each paying fees and posting the required position, can delay settlement indefinitely. The protocol does not claim liveness against such a participant. Each report is sized from a gas-cost assumption. The priority fee in that assumption is fixed when the origin pool is created and inherited by its children; it is not observed from the request block. If prevailing priority fees are higher, the modeled incentive for a disputer is weaker; a value set too high raises the sponsor's initial WETH and REP requirement and can make requests impractical. The reference's stress model estimates what it costs an attacker to hold a manipulated report against correction while collecting an outside payoff. Its results depend on a dispute barrier that the model does not derive: the default is only OpenOracle's fixed fees, and gas, priority fees, price impact, capital lockup, and price volatility over the settlement horizon all raise the real barrier (see OpenOracle's report-cost derivation ). A deployment analysis must calibrate that barrier and decide what interval one model step represents; the model's output is an estimate, not an exposure cap the contracts enforce. The OpenOracle integration reference specifies funding formulas, report sizing, sponsor rules, queues, callbacks, recovery paths, configuration, and interactive estimators. The security model states the participation assumptions.","title":"Why Statoblast uses OpenOracle","topic":"Protocol","weight":0},{"fragment":"","heading":"","keywords":["bots","liquidator","arbitrager","augurScan","research","README"],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Reference This site covers the protocol. The material below lives next to the code it describes and is not searchable from here. Each link opens the current version on GitHub.","title":"Further reading","topic":"Ecosystem","weight":1},{"fragment":"operators","heading":"Run something","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Document Who it is for What it covers Statoblast liquidator Vault operators and keepers Monitoring pool health, staging and executing liquidations, and the bot's dashboard. OpenOracle arbitrager Price correctors Finding mispriced REP/ETH reports, funding disputes against Uniswap quotes, executor deployment, and settlement tracking. Chaos bot and its operator reference Testnet operators Exercising permissionless protocol paths with real transactions, safety limits, and runtime controls. augurScan , its operations guide , API reference , and state model Indexer operators and integrators The read-only protocol explorer: deployment, backup and upgrade, the HTTP API, and how retained evidence differs from the current view. Local test network and Sepolia Reth node Developers and node operators Docker Compose setups for the repository-pinned Anvil chain and a pruned Sepolia execution and consensus pair.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"code","heading":"Read the code","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"Document Who it is for What it covers Repository README Contributors Setup, local development, simulation mode, common commands, and validation. Contract layout and the Statoblast contract directory Auditors and contract developers Why source paths are stable, which directory owns which contracts, and the OpenOracle vendoring boundary. Security regression suite Auditors The focused tests that reproduce past security findings and how to add one. Shared TypeScript packages and core UI ownership Front-end and tooling contributors Package boundaries, build dependencies, and which layer may import which. Statoblast test slices Contract developers How the split Statoblast suites are run individually and together. Security pool workflow test slices Front-end contributors How the split security-pool workflow suites of the Statoblast UI are run individually and together. Token authorization provenance Auditors Where the EIP-712 and ECDSA signature helpers come from and what was changed. augurScan backend boundaries Indexer contributors Which backend directory owns HTTP, scanning, storage, and evidence types. UI features , UI protocol client , and UI copy modules UI contributors Where feature components, typed contract reads and writes, and user-facing text live, and which may import which. Visual foundation UI contributors The shared design tokens, product accents, and status treatments used by every interface.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"research","heading":"Understand the design history","keywords":[],"path":"reference/further-reading.html","sectionTitle":"Reference","summary":"Operator, indexer, test, and research material that lives beside the code.","text":"The oracle-research repository holds the proposals, rejected alternatives, and open questions behind the protocol. It explains why the design looks the way it does; the deployed contracts and this site's reference pages describe what it actually does today.","title":"Further reading","topic":"Ecosystem","weight":0},{"fragment":"","heading":"","keywords":["OpenOracle","parameters","funding","callbacks","estimators"],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"OpenOracle supplies a fresh REP/ETH price for Statoblast's solvency-sensitive operations. It does not decide market truth; local Escalation Games and Zoltar remain responsible for truth and branching. The OpenOracle explanation covers why Statoblast uses a contestable price and which operations depend on it. This page specifies the integration: formulas, parameters, and settlement-callback behavior. Per-function callers, preconditions, and events are in the coordinator contract reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":1},{"fragment":"openoracle-role","heading":"Token pair and cached price","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Statoblast configures WETH as token1 and REP as token2 . Keeping WETH on the exact side lets the coordinator size the report directly from ETH-denominated gas costs without first assuming a REP/ETH conversion price. When a report settles, the coordinator converts the settled token amounts into REP per ETH: lastPrice = amount2 ⋅ 10 18 amount1 The settled REP amount ( amount2 ) is scaled by the fixed price precision and divided by the settled WETH amount ( amount1 ). This raw-amount ratio is valid because the configured WETH and REP contracts both use 18 decimals. The coordinator does not normalize token decimals in the settlement callback. An accepted report becomes the coordinator's cached REP/ETH price. Its freshness window is one hour on Sepolia and five minutes on other chains. The window starts at settlement eligibility (the final report timestamp plus settlementTime ), not when settle is called, and lastSettlementTimestamp records that start. A late settlement therefore cannot extend the life of a price that was frozen earlier. The coordinator does not meter how much operation volume uses that price during the freshness window.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"optional-upstream-capabilities","heading":"Report flags","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator always submits flags 7 : FLAG_TIME_TYPE ( 1 , a timestamp clock), FLAG_TRACK_DISPUTES ( 2 , per-dispute history), and FLAG_STORE_ALL ( 4 , the complete report state in storage). It never sets the optional flags 8 , 16 , 32 , or 64 ; the OpenOracle provenance record identifies the vendored source and build profile.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"statoblast-integration","heading":"Integration architecture","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Every security pool has its own OpenOraclePriceCoordinator . The coordinator connects users, the pool, and the shared OpenOracle instance. It keeps the pool's cached REP/ETH price, pending report state, staged-operation queue, and settlement callback state. Keeping this state per pool prevents one pool's pending report or freshness window from becoming a protocol-wide queue. OpenOraclePriceCoordinator is deployed with an immutable OpenOracle address. For each origin or child security pool, SecurityPoolFactory asks OpenOraclePriceCoordinatorFactory for a fresh coordinator wired to the shared OpenOracle instance, shared WETH, and that universe's REP token. SecurityPoolDeployer passes the coordinator to the pool, after which the factory calls setSecurityPool once with the nonzero pool address. Only the configured pool may seed the coordinator's inherited lastPrice . A child pool inherits the parent's numeric price as a starting value, but its settlement timestamp remains zero, so that number is unusable until the child accepts its own report. After OpenOracle settles, the coordinator validates the report. An accepted report refreshes the REP/ETH price and runs pending operations through local guardrails. A rejected report leaves the price cache unchanged and terminally fails the attached pending batch. Integration flow. The coordinator is the trust boundary between Statoblast operations and OpenOracle reports.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Price request lifecycle","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Liquidations, REP withdrawals, and staged underwriting-commitment changes ( OperationType.SetVaultUnderwritingLimit ) begin at the pool's coordinator. The coordinator validates and stages the operation, then uses a cached price or opens an OpenOracle report. Owners may also set commitments directly at the pool. REP deposits add backing without changing commitments. Exact permissions and guards are in the SecurityPool reference . Validate and stage the operation. The coordinator checks the caller, target vault, requested amount, and validity window before any report is requested. Check the cached price. If the cached REP/ETH price is fresh, the coordinator attempts the operation immediately. Open a report when the price is stale. The refresh sponsor supplies the request bounty and initial WETH/REP position, and the coordinator creates the report as its initial reporter. Allow corrections. Other participants may replace the report by posting the position required by OpenOracle. Every valid replacement installs a new reporter and restarts the settlement window. Settle the current report. Once the settlement deadline is reached without another dispute, any account can call OpenOracle's settle , which finalizes the report and calls the coordinator. Accept or reject the price. The coordinator validates the report identity, history, economics, amounts, and settlement-time base fee before updating the cache. Execute queued operations. An accepted fresh price allows the coordinator to attempt the queued pool operations, each of which still performs its own current safety checks.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Staging preconditions","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A request that violates a staging precondition reverts before any report is requested. The preconditions of each entry point, including amounts, the validity window, vault targets, liquidation approvals, and the pending-report sponsor rule, are listed in the coordinator contract reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Execution batches","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"For a single operation with a valid cached price, the coordinator records the operation and attempts it in the same transaction. A liquidation gate or another pool check can still fail; the transaction then succeeds and the operation is consumed with ExecutedStagedOperation reporting success = false . An operation that waits for a report can also fail when it is attempted: after its expiry ( Staged operation expired ), when a liquidation target's backing units or underwriting commitment changed after staging ( Stale liquidation ), or when a withdrawal now previews to zero REP ( Withdraw amount has no effect ). When a new report is needed, one settlement callback can automatically attempt up to MAX_PENDING_SETTLEMENT_OPERATIONS (four) price actions, counting each commitment change, liquidation, or withdrawal inside a vault bundle separately. Deposits use no callback slot. A bundle must fit the remaining capacity; additional single staged operations remain active outside the callback batch. If they have not expired and the accepted price remains fresh, they can be executed later with executeStagedOperation . For a vault bundle, a fresh-price failure reverts the entire submission. With a stale price, the deposit completes immediately and the deferred commitment changes, liquidations, and withdrawal later execute or fail together. See the coordinator interaction reference .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"report-lifecycle","heading":"Escalation Game deposits","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Escalation Game REP deposits do not use the staged callback path. When a pool has any underwriting commitment, depositToEscalationGame requires an already-fresh coordinator price and reverts when the price is stale. After previewing the accepted REP deposit, the pool uses lastPrice for the post-transfer vault and pool coverage checks.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"request-funding","heading":"Funding and report ownership","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Report funding is caller supplied. The coordinator's getRequestPriceCostAttoEth() getter calculates the minimum request bounty from the current base fee, callback gas limit, and the coordinator's own report processing budget: requestPriceCostAttoEth = block.basefee ⋅ 4 ⋅ ( callbackGasLimit + gasConsumedOpenOracleReportPrice ) + 101 callbackGasLimit is (gasConsumedSettlement + SETTLEMENT_GAS_OVERHEAD) × MAX_PENDING_SETTLEMENT_OPERATIONS , returned by getSettlementCallbackGasLimit() . 101 is the fixed REQUEST_BOUNTY_OFFSET_ATTO_ETH . With the configured values , the limit is 4,200,000 gas and the request cost is block.basefee × 17,200,000 + 101 attoETH: 0.516 ETH plus the offset at a 30 nanoETH base fee. Every entry point that can open a report takes an explicit bountyAttoEth . What happens to msg.value depends on the call: The call opens a report. bountyAttoEth must be at least getRequestPriceCostAttoEth() in the inclusion block, and msg.value must be at least bountyAttoEth . The coordinator forwards exactly bountyAttoEth to OpenOracle as the report's settlerReward and refunds the rest. The same transaction transfers the sponsor's initial WETH and REP position, so the sponsor funds the bounty and the position up front. A staging call finds a fresh cached price. No bounty is taken, and all of msg.value is refunded. A staging call adds an operation while a report is pending. No bounty is taken, and all of msg.value is refunded. requestPrice , requestPriceIfNeededAndStageOperation , and requestPriceIfNeededAndStageLiquidation refund msg.sender . stageVaultOperations , which only the coordinator's vaultOperations executor can call, refunds the bundle owner. Each refund is a low-level native-ETH call made only for a positive amount. If the recipient rejects it, the whole transaction reverts, including operation staging, immediate execution, and any report opened in the same transaction.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"rolling-dispute-exclusivity","heading":"Sponsor lane","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The sponsor lane is the exclusive right of pendingReportSponsor , the account that funded the pending report, to add operations to that report's settlement. Those follow-up operations pay no additional bounty; other callers must wait until the report finishes. requestPrice reverts while the cached price is fresh or a report is pending.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"security-guarantee","heading":"Report sizing and correction incentives","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator sizes each report so that correcting a price error of at least targetPriceErrorForDispute stays profitable after OpenOracle's fees and the modeled gas cost of one dispute multiplied by openOracleSecurityMultiplierBps . That multiplier is separate from a SecurityPool's backing multiplier, statoblastSecurityMultiplierBps . A report can be corrected in either direction. The formula assumes the less profitable one, in which the true REP/ETH price is (1 + targetError) times the reported price, and models the correction as releasing the fraction (targetError - fees) / (1 + targetError) of the WETH position before gas. The required position is the multiplied gas cost divided by that fraction. The minimum initial WETH position also has a floor of 1% of the pool's settlement collateral ( settlementCollateralAttoEth ), and the same floor applies to the escalation halt: reportAttoEth ( gasPriceAttoEthPerGas ) = ⌈ gasPriceAttoEthPerGas ⋅ gasUnitsForOneDispute ⋅ openOracleSecurityMultiplierBps ⋅ ( percentagePrecision + targetPriceErrorForDispute ) 10000 ⋅ ( targetPriceErrorForDispute - protocolFee - feePercentage ) ⌉ openInterestReportAttoEth = ⌈ settlementCollateralAttoEth 100 ⌉ minimumToken1ReportAttoEth = reportAttoEth ( initialReportPriorityFeeAttoEthPerGas ) + max ( reportAttoEth ( block.basefee ) , openInterestReportAttoEth ) escalationHaltAttoEth = max ( ⌊ initialWethReportAttoEth ⋅ escalationHaltMultiplierBps 10000 ⌋ , openInterestReportAttoEth ) All amounts are in attoETH. percentagePrecision is 10,000,000 , the denominator of targetPriceErrorForDispute , protocolFee , and feePercentage . No REP price, expected REP price movement, or individual protected-operation notional enters the minimum WETH calculation. The coordinator sets initialWethReportAttoEth = max(minimumToken1ReportAttoEth(), requestedInitialAttoWeth) , uses that value as OpenOracle's currentAmount1 , and derives amount2 = ⌈initialWethReportAttoEth * proposedRepPerEthPrice / 1e18⌉ in the same transaction.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"formula-inputs","heading":"Formula inputs","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The shared deployment configuration is the set of constants in shared/statoblast/ts/initialReport/oracleInitialReport.ts that the deployment passes to the coordinator factory constructor. Formula input Current value Source block.basefee Current request block EVM block context initialReportPriorityFeeAttoEthPerGas Origin-pool parameter; the UI defaults to 10 nanoETH Immutable lineage configuration inherited by child pools settlementCollateralAttoEth Current pool settlement collateral Configured security pool OPEN_INTEREST_DIVIDER 100 (a 1% floor) Coordinator constant gasUnitsForOneDispute 300,000 gas Factory constructor; shared deployment configuration ORACLE_GAS_UNITS_FOR_ONE_DISPUTE openOracleSecurityMultiplierBps 100,000 bps ( 10x ) Factory constructor; shared deployment configuration OPEN_ORACLE_SECURITY_MULTIPLIER_BPS targetPriceErrorForDispute 500,000 / 10,000,000 ( 5% ) Factory constructor; shared deployment configuration ORACLE_TARGET_PRICE_ERROR_FOR_DISPUTE protocolFee 100,000 / 10,000,000 ( 1% ) Factory constructor; shared deployment configuration ORACLE_PROTOCOL_FEE feePercentage (OpenOracle's reporter fee) 10,000 / 10,000,000 ( 0.1% ) Factory constructor; shared deployment configuration ORACLE_FEE_PERCENTAGE escalationHaltMultiplierBps 100,000 bps ( 10x ) Factory constructor; shared deployment configuration ORACLE_ESCALATION_HALT_MULTIPLIER_BPS","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"security-guarantee","heading":"Construction bounds and parameter effects","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Coordinator construction requires: positive dispute gas units positive request gas: gasConsumedSettlement or gasConsumedOpenOracleReportPrice is nonzero a nonzero initialReportPriorityFeeAttoEthPerGas a target error no greater than 100% an OpenOracle security multiplier of at least 1x and at most type(uint256).max / (percentagePrecision + targetPriceErrorForDispute) combined OpenOracle fees below the target error a nonzero escalationHaltMultiplierBps a timestamp clock with dispute tracking ( timeType and trackDisputes both true) maxSettlementBaseFeeMultiplierBps of at least 1x minLiquidationPriceDistanceBps no greater than 100% Construction also bounds initialReportPriorityFeeAttoEthPerGas so that the priority-fee component of the minimum report, reportAttoEth(initialReportPriorityFeeAttoEthPerGas) , does not exceed half of min(type(uint128).max, type(uint128).max × 10000 / escalationHaltMultiplierBps) ; a larger fee reverts with Initial report priority fee exceeds OpenOracle limits . OpenOraclePriceCoordinatorFactory stores the shared configuration without validating it, so an invalid configuration deploys the factory successfully and makes every later coordinator deployment revert. At a 30 nanoETH base fee, a configured 10 nanoETH priority fee, and 100 WETH of settlement collateral, the modeled gas cost of one dispute is 0.012 ETH , the minimum report is 3.230769230769230770 WETH , and the escalation halt is 32.307692307692307700 WETH .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"initial-report-estimator-example","heading":"Dynamic WETH report estimator","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"This calculator mirrors the onchain formula. The deployment parameters and caller-selected amount are shown as adjustable inputs to make their effect explicit. For a deployed coordinator, the base fee and pool settlement collateral can change from one request block to another. Selected initial WETH 3.2308 WETH Fee bound fees below target error Network costs Block base fee 30 nanoETH Initial-report priority fee 10 nanoETH Gas units for one dispute 300,000 gas Pool security Pool settlement collateral 100 WETH OpenOracle security multiplier 10.0x Target wrong-price error 5.0% Oracle fees OpenOracle protocol fee 1.0% OpenOracle reporter fee ( feePercentage ) 0.1% Coordinator policy Escalation halt multiplier 10x Report request Requested initial WETH 0.00 WETH Initial-derived halt 32.307692307692307700 WETH Open-interest halt floor 1.000000000000000000 WETH Minimum token1 report 3.230769230769230770 WETH Escalation halt 32.307692307692307700 WETH Modeled dispute gas cost 0.012000 ETH Buffered gas target 0.120000 ETH Correction profit fraction after fees 3.7143%","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Settlement validation, rejection, and recovery","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Low-level callback failure","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"OpenOracle invokes the coordinator through a low-level callback whose success is intentionally neither stored nor emitted. A failed callback does not automatically undo an otherwise valid OpenOracle settlement. The coordinator accepts callbacks only from the configured OpenOracle and only for the current pending report id. If those checks revert inside the low-level call, the report can still settle while the coordinator remains pending. If the settlement transaction cannot retain enough gas headroom after the callback attempt, OpenOracle reverts settlement with InvalidGasLimit . In that case, the report has not settled and coordinator recovery is not yet available.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"settlement-validation-scope","heading":"Coordinator settlement validation","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A callback that successfully enters the coordinator can still produce a rejected price. The coordinator clears the pending report state, emits PriceReportRejected with the quoted reason, and leaves the price cache unchanged when the first of the following conditions holds: the settlement block's base fee exceeds the request-time cap, which is the base fee implied by the committed bounty scaled by maxSettlementBaseFeeMultiplierBps : Base fee too high ; storedGame(reportId).numReports is saturated at the uint24 maximum: Counter saturated ; numReports is zero, or the settled WETH amount is below reportAttoEth(initialReportPriorityFeeAttoEthPerGas) + reportAttoEth(recordedBaseFee) from the sizing formula , where recordedBaseFee is the base fee OpenOracle stored for the final report in disputeHistory(reportId, numReports - 1) : Report uneconomic ; the freshness window measured from settlement eligibility has already closed: Report stale ; either settled token amount is zero: Empty oracle settlement ; the integer REP/ETH calculation produces a zero price: Oracle price is zero . These checks establish only that the final WETH position meets the modeled security floor and that the callback data is structurally acceptable. They do not prove that the accepted price is externally correct, that an independent corrector exists, or that a correcting transaction will obtain inclusion.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Rejected-price cleanup","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A rejected report does not replay its pending settlement operations. Instead, the coordinator terminally fails every operation attached to that report, removes it from the active and pending sets, and releases any liquidation-approval reservation. A caller must stage a new operation to try again with a later price.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"callback-rejection-and-recovery","heading":"Recovering a settled report after callback failure","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"When OpenOracle has already settled but the coordinator remains pending because the low-level callback did not complete, anyone can call recoverSettledPendingReport . Recovery clears the pending report, sponsor, and base-fee cap; withdraws the coordinator's OpenOracle WETH and REP balances to the sponsor; and terminally fails every pending settlement operation attached to the report, releasing each liquidation-approval reservation. It does not accept the report as a new price.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"intentional-economic-tradeoffs","heading":"Liveness and exposure limits","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"The coordinator has no notional exposure budget and no absolute settlement deadline; see excluded guarantees EG03 and EG04 and the OpenOracle explanation .","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"dispute-escalation","heading":"Dispute escalation amounts","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"In this integration, WETH is the escalation variable. Before escalationHalt , OpenOracle requires min(⌊oldAmount1 × multiplier / 100⌋, escalationHalt) . With the configured multiplier of 115 , integer flooring leaves token1 amounts from one through six attoETH unchanged; seven attoETH is the first amount that grows. At or above the halt, each replacement instead requires oldAmount1 + 1 , adding one attoETH of WETH.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"attack-model","heading":"Stress model: external payoff and censorship","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"This section defines an analytical model, not contract behavior. It estimates the cost to an attacker who posts a manipulated REP/ETH report and censors corrections until settlement, receiving an outside payoff only if the accepted price makes a liquidation executable. It is a continuous approximation; the OpenOracle explanation states how far its results can be relied on. honestDisputeBarrierFraction is a model input, not a coordinator field: the cost, as a fraction of the honest price, that an honest corrector must overcome. Its 1.1% default is the fixed-fee floor, protocolFee plus feePercentage . executionErrorThreshold = max ( 0 , liquidationThresholdPrice honestPrice ⋅ ( 1 - minLiquidationPriceDistanceBps 10000 ) - 1 ) manipulatedPriceError = max ( 0 , manipulatedPrice - honestPrice honestPrice ) liquidationExecutable = manipulatedPrice > liquidationThresholdPrice ∧ manipulatedPriceError ≥ executionErrorThreshold attackerPayoff = liquidationExecutable ? externalPayoff : 0 censorshipRate = max ( 0 , manipulatedPriceError - honestDisputeBarrierFraction ) censorshipCost = censorshipDuration ⋅ censorshipRate ⋅ oracleReportLiquidity Price errors and the dispute barrier are fractions of the honest price. externalPayoff and oracleReportLiquidity use the same ETH-denominated unit. The liquidation design owns the exact integer threshold and distance checks. targetGriefRatio is the desired attacker loss net of externalPayoff , divided by that payoff; 1 targets censorship cost equal to twice the payoff. One model step is the interval over which censorshipRate accrues; the model does not tie it to a block, second, or dispute round. oracleLiquidityRatio = oracleReportLiquidity externalPayoff durationToTargetCost = { targetGriefRatio + 1 censorshipRate ⋅ oracleLiquidityRatio , liquidationExecutable ∧ censorshipRate > 0 ∞ , liquidationExecutable ∧ censorshipRate = 0 not applicable , otherwise durationToTargetCost is the number of model steps of censorship after which censorshipCost reaches (targetGriefRatio + 1) × externalPayoff . It is not a maximum protocol delay.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"binary-censorship-example","heading":"Binary censorship stress test","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"Adjust the liquidation boundary, outside payoff, report liquidity, and censorship assumptions. Liquidation executable yes Censorship cost 11424.00 ETH Market boundary Honest price 100 Liquidation threshold 101 Liquidation distance 1000 bps Attacker inputs Manipulated price 113 External payoff 1000.00 ETH Oracle defense Report liquidity 4000.00 ETH Honest dispute barrier (model) 1.10% Censorship scenario Censorship duration (model steps) 24 steps Target excess-cost ratio 1.0 Execution error threshold 12.22% Manipulated price error 13.00% Attacker payoff 1000.00 ETH Oracle liquidity ratio 4.00 Duration to target cost (model steps) 4.20","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"parameters","heading":"OpenOracle parameters used","keywords":[],"path":"reference/open-oracle.html","sectionTitle":"Reference","summary":"Funding, report sizing, settlement validation, recovery, parameters, and a censorship stress model.","text":"A source constant is fixed in the Solidity source. Deployment configuration is the shared configuration that the deployment passes to the coordinator factory, named by its constant in shared/statoblast/ts/initialReport/oracleInitialReport.ts ; a deployed coordinator exposes each configured value through a public getter. The line under each value says where it is set. Parameter Value and source Use in Statoblast token1Address / token2Address WETH / REP The factory's WETH and the pool universe's REP token Defines the REP/ETH price pair used for security-pool solvency checks. minimumToken1ReportAttoEth() See Report sizing and correction incentives and the estimator . Derived per request Minimum initial WETH position for a coordinator report. OpenOracle initial currentAmount1 The greater of the minimum and the sponsor's requestedInitialAttoWeth Derived per request Initial WETH position; the sponsor may fund more than the minimum. escalationHalt See Report sizing and correction incentives . Derived per request Ends multiplicative escalation; see Dispute escalation amounts . settlerReward The committed bountyAttoEth ; at least the request cost Derived per request Paid to the account that settles the report. Sizing inputs: gasUnitsForOneDispute , openOracleSecurityMultiplierBps , targetPriceErrorForDispute , protocolFee , feePercentage , escalationHaltMultiplierBps , initialReportPriorityFeeAttoEthPerGas , OPEN_INTEREST_DIVIDER See Formula inputs . Size the report and the escalation halt. The two fees also set OpenOracle's dispute fee accounting. gasConsumedSettlement 1,000,000 gas Deployment configuration ORACLE_SETTLEMENT_GAS Per-operation component of the callback gas limit. SETTLEMENT_GAS_OVERHEAD 50,000 gas Source constant Per-operation allowance for coordinator bookkeeping. MAX_PENDING_SETTLEMENT_OPERATIONS 4 Source constant Price actions one settlement callback can attempt, counting each action inside a vault bundle. callbackGasLimit 4,200,000 gas ; see Funding and report ownership . Derived from the three rows above Gas forwarded to the settlement callback. Settlement also needs enough surrounding gas to satisfy OpenOracle's callback headroom check. gasConsumedOpenOracleReportPrice 100,000 gas Deployment configuration ORACLE_REPORT_GAS Added to the callback gas limit in the request cost . maxSettlementBaseFeeMultiplierBps 30,000 bps ( 3x ) Deployment configuration ORACLE_MAX_SETTLEMENT_BASE_FEE_MULTIPLIER_BPS Scales the base fee implied by the bounty into the settlement base-fee cap . minLiquidationPriceDistanceBps 1,000 bps ( 10% ) Deployment configuration ORACLE_MIN_LIQUIDATION_PRICE_DISTANCE_BPS Minimum price distance a liquidation must clear; see when a vault is liquidatable . settlementTime 480 seconds Deployment configuration ORACLE_SETTLEMENT_TIME Report settlement delay on the timestamp clock. A staged operation expires once this delay plus its validity window has passed since it was queued. disputeDelay 0 Deployment configuration ORACLE_DISPUTE_DELAY Allows disputes immediately after each report and strictly before its settlement deadline. At the deadline, settlement is valid and a dispute is too late. multiplier 115 ( 1.15x ) Deployment configuration ORACLE_MULTIPLIER Growth of the WETH amount per dispute before the halt; see Dispute escalation amounts . protocolFeeRecipient 0x000000000000000000000000000000000000dEaD Deployment configuration ORACLE_PROTOCOL_FEE_RECIPIENT Receives OpenOracle protocol fees for coordinator-created reports. timeType / trackDisputes true / true Deployment configuration; the constructor rejects any other value Timestamps let the coordinator measure freshness from settlement eligibility; dispute history lets settlement validate the final report's recorded base fee. callbackContract The pool's OpenOraclePriceCoordinator Set by the coordinator Routes settled amounts back into the price cache and staged-operation executor. PRICE_VALID_FOR_SECONDS / SEPOLIA_PRICE_VALID_FOR_SECONDS See Token pair and cached price . Source constant Freshness window of an accepted price. MAX_OPERATION_VALID_FOR_SECONDS 300 seconds Source constant Largest validForSeconds a staged operation may request.","title":"OpenOracle integration reference","topic":"Mechanisms","weight":0},{"fragment":"","heading":"","keywords":["Zoltar","question","registry","screenshots"],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Tutorial You will create a yes-or-no question in Zoltar's global registry and then find it again in the question browser. Every market and every fork starts from a question like this one.","title":"Your first Zoltar question","topic":"Zoltar","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Zoltar is the base layer: it records questions and keeps the REP ledger of each universe . Zoltar and branching universes explains the model. Run bun run app:serve:zoltar and open http://localhost:4153/?simulate=1&simScenario=deployed . That browser-local simulator has the contracts deployed and no questions yet; the screenshots below come from it. It never reflects live chain state.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"create","heading":"Write the question","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Create question and keep the Binary question type. Enter a Title , for example Will it rain in Lisbon on 1 June 2027? In Description , name the source and say when the answer is Invalid , for example Resolves Yes if IPMA reports measurable rain at its Lisbon station on 1 June 2027 (UTC). Invalid if IPMA publishes no reading. Enter an End time after the event. Leave Start time blank to start immediately. The question form. The draft preview shows exactly what will be recorded on chain. A question cannot be edited after it is created, so check the preview before you submit.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"submit","heading":"Create it","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Create question below the preview and confirm the transaction. The confirmation card shows the Question ID , the end time, and the Outcomes Yes, No, and Invalid. The new question. The question ID identifies the question in every universe.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"find","heading":"Find it in the registry","keywords":[],"path":"tutorials/zoltar-first-question.html","sectionTitle":"Tutorials","summary":"Create a yes-or-no question in the Zoltar registry and find it again.","text":"Select Browse questions . Your question appears automatically under Downloaded (1) . The registry. Questions are global: any universe can use this one, and anyone can find it here. That is a complete question. To put collateral behind a question, follow Your first security pool ; on a live network you could choose Use a question ID there with this question's ID, while each simulator keeps its own chain. Use for fork instead starts a universe fork, which Zoltar and branching universes explains.","title":"Your first Zoltar question","topic":"Zoltar","weight":0},{"fragment":"","heading":"","keywords":["Statoblast","SecurityPool","vault","underwriting commitment","OpenOracle","screenshots"],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Tutorial You will create a yes-or-no question and its SecurityPool , back the pool with 1,000 REP, commit to underwrite 10 ETH of it, and mint the pool's first complete set . At the end the pool shows 1 ETH of open interest against a 10 ETH commitment.","title":"Your first security pool","topic":"Statoblast","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Statoblast is the market layer built on Zoltar , the forkable oracle: a SecurityPool holds the ETH behind one question's outcome shares, and vault owners back it with REP . How Statoblast works explains the model; this tutorial only walks through it. Run bun run app:serve:statoblast and open http://localhost:12347/?simulate=1&simScenario=deployed . That browser-local simulator has the contracts deployed, no pools yet, and a wallet holding ETH and REP; the screenshots below come from it. It never reflects live chain state.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"create","heading":"Create the question and pool","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Select Create pool . Keep Create a new question and the Binary question type. Enter a Title , for example Will it rain in Lisbon on 1 June 2027? , and an End time after the event. Leave Security multiplier at 2 and Initial report priority fee at 10. Select Create question and pool and confirm the transaction. The pool form. The security multiplier sets how much REP must back each ETH a vault commits; every binary market has the three outcomes in the preview. The confirmation card lists the new question and pool. Select Open pool . The new pool. One transaction created both the Zoltar question and its SecurityPool.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"deposit","heading":"Back the pool with REP","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"On the pool page, open Vaults and select My vault . The Vault operations form is shown there. Enter 1000 in REP deposit amount (optional) , select Review vault operations , then Approve 1k REP and confirm the approval. Select Submit vault operations and confirm. The panel shows REP deposit confirmed ; your vault is now created. The REP deposit. Approval and deposit are separate transactions.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"commit","heading":"Commit to underwrite","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"REP alone does not let the pool take collateral. Your underwriting commitment is the ETH amount you agree to cover, and raising it needs a valid REP/ETH price from OpenOracle . A new pool has no price yet, so this first commitment requests one. Stay in My vault . Enter 3 in Initial report price . On a live network, Fetch from Uniswap fills in a market price; the simulator has no Uniswap pricing. Enter 10 in Commitment limit . Select Review vault operations to review the transaction and its funding requirements. Approve WETH and REP with their separate buttons. Each approval has an editable amount; use the suggested amounts for this tutorial. Select Submit vault operations , shown with the ETH amount to send, and confirm that transaction. It funds a new price report and stages your change; the panel shows Vault operations queued · awaiting oracle settlement . The vault operations review. At 3 REP per ETH and a security multiplier of 2, 1,000 REP backs about 166 ETH, so 10 ETH leaves the vault healthy.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"settle","heading":"Settle the price report","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"The report can be settled once it has stood unchallenged for eight minutes, and your staged change runs when it settles. The change expires a few minutes after the report becomes settleable, so settle promptly; an expired change must be staged again. In the simulator, select Show details in the banner, open QA controls, prices, and time travel , and select +10 min . On a live network, wait instead. On the pool page, select View report next to the OpenOracle price . When the page says Ready to settle , select Settle report and confirm. Whoever settles collects the report's settlement bounty. A settleable report. Settling accepts the price and runs the staged commitment change in the same transaction. Return to the pool with the browser's Back button. In My vault , Commitment limit now reads 10.00 ETH and the panel shows Vault operations executed . The applied commitment. The pool can now accept up to 10 ETH of collateral.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"mint","heading":"Mint a complete set","keywords":[],"path":"tutorials/statoblast-first-pool.html","sectionTitle":"Tutorials","summary":"Create a SecurityPool, back it with REP, commit to underwrite it, and mint a complete set.","text":"Select Open shares , then Mint complete sets . Enter 1 in ETH to mint with , select Mint complete sets , and confirm. Minting. Minting needs no oracle price; here it only has to fit within the pool's total commitments. Your wallet now holds the new Yes, No, and Invalid shares, and the pool summary's Open interest / commitment reads 1.00 ETH / 10.00 ETH. That is the whole underwriting loop: back a pool, commit capacity, and let collateral in. Open-interest fees explains what your commitment earns, and Your first Trading market opens a market for a pool like this one. The finished pool. One ETH of collateral now backs outstanding shares, inside the 10 ETH you committed.","title":"Your first security pool","topic":"Statoblast","weight":0},{"fragment":"","heading":"","keywords":["Trading","liquidity","initialize","pair","screenshots"],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Tutorial You will open trading for a SecurityPool by creating its trading pool and seeding it at a 70% conditional Yes price (the Yes price if the market does not resolve Invalid) with 0.01 ETH. You finish with LP tokens (the trading pool's liquidity-provider tokens) and separately held Invalid shares in your wallet, and the market listed as open.","title":"Your first Trading market","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Trading is an exchange for Statoblast outcome shares: a trading pool swaps the Yes and No shares of exactly one SecurityPool, and a SecurityPool without one has no market yet. In the UI, creating the trading pool is called creating a market . To practise without a wallet, run bun run app:serve:trading and open http://localhost:4163/?simulate=1&simScenario=deployed#/create-market . That simulator scenario has one SecurityPool, at 0x5e4EDB416494DbB62DD8C76E849aDee8e3c44d49 , and no trading pool; the screenshots below come from it. For a live network, follow Configure the Trading UI , and if the UI opens the deployment screen, complete Deploy the Trading contracts first. Fund the wallet with the deposit plus gas.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"find-pool","heading":"Open a SecurityPool without a market","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Select the Create tab and paste the SecurityPool address into Search security pools . In the simulator, use the address above; on a live network, copy it from Statoblast. Select Open security pool . The form opens with the badge MARKET NOT CREATED and Create market selected, and the SecurityPool is saved as a favorite. The next section continues from this form. To check the SecurityPool first, select Create again: the list shows your favorite SecurityPools in the selected universe that have no trading market yet, and Create market returns you to the form. Pools without a market. Create market reopens the form; Details opens the details page. The details page tells you whether the SecurityPool can take a market. An enabled Create market button means it can, and selecting it returns you to the form. When it cannot, the button is disabled and names the reason, such as Question ended. This market can no longer be created. Minting capacity shows the collateral already minted against the SecurityPool's ceiling (used / ceiling); your deposit must fit in the difference. An eligible SecurityPool. The SecurityPool is operational, its universe has not forked, and it has capacity for new collateral.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"initialize","heading":"Create and seed the trading pool","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Enter 0.01 in Amount and 70 in Conditional Yes price . Read the estimate: You provide 0.01 ETH, You receive ≈ LP tokens, 0.01 Invalid, and the Yes shares the trading pool did not need. Select Create market and add liquidity and confirm the one transaction that creates and seeds the trading pool. It reverts if it would mint fewer LP tokens than the estimate allows after your slippage tolerance, which you set under Settings . Seeding at a 70% conditional Yes price. The LP tokens represent only the Yes and No left in the trading pool; the Invalid and spare Yes return to your wallet.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"check","heading":"Check the result","keywords":[],"path":"tutorials/trading-first-market.html","sectionTitle":"Tutorials","summary":"Create and seed the trading pool for a SecurityPool in the UI.","text":"Open the Markets tab. The market is listed with the badge TRADING OPEN and a conditional price of 70% Yes. Then open Portfolio : the market shows your LP tokens, your Invalid, and the spare Yes as separate holdings. Portfolio after seeding. The 0.01 ETH deposit returned 0.01 Invalid, 0.0057 spare Yes, and the LP tokens. At a 70% conditional Yes price, the trading pool holds roughly 30 Yes for every 70 No. The No reserve is the larger one because in a constant-product market the opposite reserve sets the price; Conditional pricing explains why. Next: make your first trade against the trading pool you just created.","title":"Your first Trading market","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","buy","sell","enterPosition","slippage"],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Tutorial In this tutorial you buy Yes shares in an open market and then sell part of them back for ETH. You will see one ETH purchase become a complete set plus a swap, leaving you Yes shares and Invalid shares, and you will see the sale spend some of that Invalid to pay out ETH.","title":"Your first trade","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Trading is an exchange for Statoblast outcome shares: each market trades the Yes and No shares of one SecurityPool in a constant-product trading pool . To practise without a wallet, run bun run app:serve:trading and open http://localhost:4163/?simulate=1#/market/0x5e4EDB416494DbB62DD8C76E849aDee8e3c44d49 . The browser-local simulator is labeled at the top of the page, starts with one funded market, and never reflects live chain state; the screenshots below come from it. To trade for real, open the UI on a supported network as described in Configure the Trading UI and connect a wallet.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"choose","heading":"Choose a market","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"The simulator link above opens the market directly. On a live network, paste a SecurityPool address into Search markets and select Open security pool , or follow a shared market link. Opening a market saves it as a favorite. The Markets tab lists your favorites in the selected universe with conditional price , liquidity, and closing time; select a title to reopen it. The star removes a market from favorites. Markets. Only markets whose badge reads TRADING OPEN accept new trades.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"protect","heading":"Set your protection","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Open Settings in the header. Under Trade settings , choose a Slippage tolerance (0.01% to 5%) and how long a transaction stays valid ( Transaction valid for , 1 to 1440 minutes). A transaction reverts if the price moves further than the tolerance or it is included after its deadline, so tighter values mean fewer surprises and more reverts. The defaults, 0.5% and 20 minutes, are fine for this tutorial. Trade settings. Every quote repeats the current values, for example Slippage 0.5% · valid up to 20 min .","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"buy","heading":"Buy Yes","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"In the market's Trade tab, select Buy and Yes . Enter 0.001 in You pay . The estimate appears below the field: You receive ≈ shows the Yes and its payout if the question resolves Yes (0 ETH if it resolves No), with your Invalid insurance beside it. Below them are Average price , Profit if the question resolves Yes , and Minimum received , and Trade details lists the Trading fee . Check the Price impact : it reads 4.52%, with a note that smaller trades get a better average price. Larger impacts need a confirmation or are refused; the Trading configuration lists the thresholds. Select Buy Yes and confirm the single enterPosition transaction in your wallet. The client checks the price again before the wallet opens. A Yes purchase. The bar at the top of the estimate shows how far the purchase moves the conditional price. When the transaction confirms, the Yes and Invalid balances under Your position on the market page go up. The ETH became complete sets; the router sold their No for more Yes and sent you all the Yes plus the Invalid. Your Invalid insurance equals the number of complete sets, not the larger Yes total, and you hold no new No.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"sell","heading":"Sell Yes","keywords":[],"path":"tutorials/trading-first-trade.html","sectionTitle":"Tutorials","summary":"Buy Yes shares in the UI and sell part of them back for ETH.","text":"Select Sell and Yes , then enter 0.001 in Shares to sell . The 25% , 50% , and Max buttons fill in larger amounts. Read the estimate: You sell , You receive ≈ in ETH, Average price , Minimum received , and Invalid used . Select Sell Yes and confirm. No approval is needed: the sale is one ShareToken transfer of your Yes and Invalid to the router . A Yes sale. Invalid used is the insurance the sale spends: it is burned with matching Yes and No as complete sets, which pay out the ETH. When it confirms, the ETH is in your wallet, your Invalid has dropped by the amount used, and any Yes the router did not need has come back. If you ask to sell more than your Invalid can insure, the ticket offers the largest amount you can sell now; Exit an insured position covers that case and Why early ETH exits are limited explains the bound.","title":"Your first trade","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","development","commands","Docker"],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"How-to guide Use this guide to get the Trading contracts, SDK, and UI compiled and running on your machine.","title":"Set up Trading development","topic":"Trading","weight":1},{"fragment":"build-and-run","heading":"Build and run","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"From the repository root, confirm dependencies with test -d node_modules . If they are missing, run bun install --frozen-lockfile && bun run setup ; setup installs every project from its lockfile, compiles the contracts, and builds the UI apps and UI tests. Run bun run trading:compile . It compiles the contracts, builds the shared packages, and runs the Trading vendor build, which generates ui/trading/ts/generated/contractArtifact.ts . Never edit generated files. Run bun run trading:test , which runs the SDK, contract-facing, and UI Trading tests, and bun run trading:ui:build . Start bun run app:serve:trading , then open http://localhost:4163/?simulate=1 for the browser-local simulator. Configure the Trading UI lists the Trading scenarios. The setup works when the tests pass and the simulator page loads. To run the standalone UI in Docker instead, complete the repository-root setup first, then from ui/trading : docker network inspect zoltar >/dev/null 2>&1 \\ || docker network create zoltar docker compose up --build --force-recreate Then open http://localhost:4163/#/market . On Windows, ui/trading/start.bat runs the same Compose command. The final image runs as an unprivileged user and exposes a health check at / . The Docker image copies the core deployment addresses from docs/mainnet-deployment-addresses.json and docs/sepolia-deployment-addresses.json .","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"external-node","heading":"Test transactions against an external node","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"To exercise the contracts on a local Anvil node, follow Use local Anvil ; for script and integration tests, Deploy for script and integration tests covers bun run trading:deploy:local .","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"commands","heading":"Other commands","keywords":[],"path":"how-to/trading-set-up-development.html","sectionTitle":"How-to guides","summary":"Compile, test, build, and serve the Trading subsystem locally.","text":"bun run trading:check runs the tests plus the bigint-number-cast guard. bun run trading:coverage:contracts traces Solidity execution and requires at least 99% production-contract line coverage. bun run trading:gas-costs reports bytecode sizes and funded-fixture operation gas. cd ui/trading && bun run docker:build and docker:run build and run the standalone UI container without Compose. After a change that alters what the UI shows, run bun run docs:screenshots -- --app trading to recapture the documentation screenshots.","title":"Set up Trading development","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","UI","simulate","RPC","settings"],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"How-to guide Use this guide to choose between live and simulated mode and to point the Trading UI at the network and RPC you need.","title":"Configure the Trading UI","topic":"Trading","weight":1},{"fragment":"modes","heading":"Choose a mode","keywords":[],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"With no mode parameter, the UI reads live RPC and wallet state. ?simulate=1 boots a browser-local simulator with seeded contracts and balances. Add &simScenario=deployed for a SecurityPool with no trading pool , &simScenario=baseline for a chain without Statoblast or Trading contracts, &simScenario=trading-forked for the funded market after its universe forks, or leave it out for the default trading-funded scenario with one funded market. A banner labels the page as a simulation. Set up Trading development lists the commands that serve the UI.","title":"Configure the Trading UI","topic":"Trading","weight":0},{"fragment":"network","heading":"Select a network and RPC","keywords":[],"path":"how-to/trading-configure-ui.html","sectionTitle":"How-to guides","summary":"Live and simulation modes; network and RPC selection.","text":"Open Settings in the header. Choose the RPC network , and optionally enter a Fallback RPC URL and select Save RPC . A custom RPC must use HTTPS, or HTTP on a loopback address, and must serve the selected chain. It is used only until a wallet is connected on the selected chain; after that, the wallet's own RPC serves reads and transactions. The UI then checks the RPC chain and the core contracts, and derives the Trading factory and router addresses for that network. If either is not deployed, the deployment screen opens; Deploy the Trading contracts covers it. The configuration works when the Markets tab opens. The configuration reference describes what the client derives and checks.","title":"Configure the Trading UI","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","deploy","factory","router","Anvil"],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"How-to guide Trading needs one factory and one router at addresses derived from the Statoblast deployment. Use this guide to deploy them from the browser on a network where Statoblast is installed, or with the testnet deployer on a local Anvil node.","title":"Deploy the Trading contracts","topic":"Trading","weight":1},{"fragment":"before-you-start","heading":"Before you start","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The Statoblast core, including its SecurityPoolFactory , must already be deployed on the network. The manifests docs/mainnet-deployment-addresses.json and docs/sepolia-deployment-addresses.json list planned addresses; they do not prove the contracts are live, as the deployment status reference explains. Continue only after you have confirmed reviewed core code at those addresses. To install the core on a test network first, follow Deploy testnet contracts .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"deploy","heading":"Deploy from the browser","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"Serve the Trading UI as Set up Trading development describes, from source or in Docker. Open http://localhost:4163/#/deploy . To use another network or RPC URL, set it under Settings before connecting. Select Connect wallet . The Trading contracts panel shows the SecurityPoolFactory address and the status of the Trading factory ( TwoWayConstantProductFactory ) and Trading router ( TwoWayConstantProductRouter ). Select Deploy trading factory and confirm, then select Deploy trading router and confirm. Deployment progress reaches 2 / 2 once both contracts and their links are verified. If you leave and return with the same settings, the flow resumes at the first missing contract. A missing prerequisite. The SECURITY POOL FACTORY IS NOT DEPLOYED badge and the disabled deploy buttons mean Statoblast is not installed on this network yet. The factory's trading fee is fixed at 0.30% and cannot be changed after deployment. Creating a trading pool for a market is a separate step; see Your first Trading market .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"use-local-anvil","heading":"Use local Anvil","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The UIs do not offer Ethereum mainnet, so start Anvil with Sepolia's chain ID, 11155111 , and use the Sepolia address profile: bun run anvil -- --chain-id 11155111 --hardfork osaka Deploy to the node with the testnet deployer, following Deploy locally with --rpc-url=http://127.0.0.1:8545 and an Anvil account's key. It installs the core and the Trading factory and router. Its final explorer-verification step targets public Sepolia, so a failure there does not mean the local deployment failed. In your wallet, point the chain 11155111 network at http://127.0.0.1:8545 and import an Anvil account. Once a wallet is connected, the UI reads and sends through the wallet's RPC, so a wallet still on public Sepolia would use the real network. Start the Trading UI, connect the wallet, and open #/deploy . Deployment progress shows 2 / 2 .","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"deploy-script","heading":"Deploy for script and integration tests","keywords":[],"path":"how-to/trading-deploy-contracts.html","sectionTitle":"How-to guides","summary":"Deploy the Trading factory and router from the browser, with the testnet deployer on local Anvil, or as script-only copies for tests.","text":"The local deployment script deploys independent copies at ordinary CREATE addresses. The UI never finds them, because it looks only at the derived addresses; use them from scripts and integration tests only. The script needs a node whose chain ID equals the core manifest's, code at that manifest's SecurityPoolFactory , and an unlocked account on the node. For the Sepolia manifest below, complete step 1 of Use local Anvil first. ZOLTAR_DEPLOYMENT_MANIFEST=docs/sepolia-deployment-addresses.json \\ TRADING_RPC_URL=http://127.0.0.1:8545 \\ bun run trading:deploy:local The script deploys TwoWayConstantProductFactory(coreFactory, feeBps) and TwoWayConstantProductRouter(factory) , writes a manifest of its inputs, addresses, transaction hashes, and bytecode hashes to solidity/deployments/trading/local.json , and prints it. The configuration reference lists its environment variables and output.","title":"Deploy the Trading contracts","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","odds","initialize","basis points"],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"How-to guide Use this guide when you call the trading pool contract (the pair) yourself and want a new trading pool to open at a specific Conditional Yes price rather than 50%.","title":"Seed alternative conditional odds","topic":"Trading","weight":1},{"fragment":"prerequisites","heading":"Before you call initialize","keywords":[],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"Creating the trading pool and initializing it directly are separate transactions, so anyone can initialize it first at another price. Prefer the router's createPairAndInitializeWithEth , which creates and seeds in one transaction and takes the price in basis points; the UI's Initialize form uses it, as Your first Trading market shows. Continue only if you must call initialize yourself. The question has not ended, its universe has not forked, and the SecurityPool is Operational and unresolved. The smaller deposit must exceed MINIMUM_LIQUIDITY (1,000 share base units). The trading pool mints that many LP base units to a lock address that no key controls, so you receive the smaller deposit minus 1,000. The pair reference lists the remaining preconditions of initialize .","title":"Seed alternative conditional odds","topic":"Trading","weight":0},{"fragment":"steps","heading":"Seed the trading pool","keywords":[],"path":"how-to/trading-seed-alternative-odds.html","sectionTitle":"How-to guides","summary":"Seed a new trading pool at a chosen Conditional Yes price by calling its contract directly.","text":"Create complete sets by sending ETH to the SecurityPool's createCompleteSet() . Let q be the Yes balance it minted to you, in share base units; the ETH-to-share rate is not fixed, so read the balance. Create the trading pool with the factory's createPair(securityPool) , unless it already exists. Choose the Conditional Yes price p in basis points with 0 < p < 10,000 and compute the deposits: If p ≥ 5,000 , deposit all q No and ⌊q × (10,000 − p) / p⌋ Yes. If p < 5,000 , deposit all q Yes and ⌊q × p / (10,000 − p)⌋ No. Approve the trading pool as an operator on the canonical ShareToken with setApprovalForAll ; initialize pulls both deposits from the caller. Call initialize(yesAmount, noAmount, minLiquidity, recipient) on the trading pool with those deposits. Set minLiquidity to the smaller deposit minus 1,000. Check the result: getReserves() returns your two deposits and tradingStatus() returns Open . If initialize reverted with Already initialized , someone else seeded the trading pool first. Conditional pricing works through the 70% example and explains why the larger reserve is the side you are betting against.","title":"Seed alternative conditional odds","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","exit","sell","maximumInsuredExit","Invalid"],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"How-to guide Use this guide to turn Yes or No shares back into ETH while the market's trading pool is open. The exit spends one Invalid share for each complete set it redeems, so your Invalid balance limits it.","title":"Exit an insured position","topic":"Trading","weight":1},{"fragment":"in-the-ui","heading":"Exit in the UI","keywords":[],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"Open the market, select Sell and the side you hold. Select Max to fill Shares to sell with the largest amount you can sell now, or enter a smaller amount. The hint under the field shows your holding and that limit. Check You receive ≈ , Minimum received , and Invalid used , then select Sell Yes (or Sell No ) and confirm. An insured Yes exit. The hint under the amount is the limit set by your Invalid, your Yes, and the trading pool's liquidity. If Invalid is the binding limit and you enter more than it covers, the ticket shows Not enough Invalid shares to insure this sale. and offers Sell … instead with the largest amount. The shares you do not sell stay in your wallet. Acquiring more Invalid helps only when Invalid is the binding limit; Why early ETH exits are limited works through the bounds. When the sale confirms, the Invalid balance under Your position has dropped by Invalid used and the ETH is in your wallet.","title":"Exit an insured position","topic":"Trading","weight":0},{"fragment":"through-the-sdk","heading":"Exit through the SDK","keywords":[],"path":"how-to/trading-exit-a-position.html","sectionTitle":"How-to guides","summary":"Sell shares for ETH in the UI or find the largest insured exit with the SDK.","text":"Call maximumInsuredExit from the SDK , a private workspace package in this repository, with your wallet balances and the trading pool's reserves and fee. It returns the largest number of complete sets q that your Invalid, your long shares , and the opposite reserve all allow. For a Yes position, q complete sets need q Invalid, q Yes to redeem, and enough extra Yes to buy exactly q No. Choose maxLongSharesIn , minEthOut , payoutRecipient , refundRecipient , and deadline explicitly, and encode the request with encodeReceiveRequest . Send a ShareToken safeBatchTransferFrom to the router carrying q Invalid and maxLongSharesIn long shares with the encoded request. Simulate it, simulate again immediately before submission, and submit only if the result still satisfies maxLongSharesIn and minEthOut . The router reference lists the request fields, their constraints, and what the router delivers. A successful exit emits PositionExitedByTransfer with the long shares used and refunded.","title":"Exit an insured position","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","liquidity","removeLiquidity","permit"],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"How-to guide Use this guide to withdraw an LP position from a trading pool .","title":"Remove liquidity","topic":"Trading","weight":1},{"fragment":"in-the-ui","heading":"Remove in the UI","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Open the market and select the Liquidity tab, then Remove . Enter the LP tokens to remove in Amount . You receive ≈ shows the Yes and No you get back. Select Remove liquidity and confirm. The transaction reverts if it would return less than the estimate allows after your slippage tolerance. Removing liquidity. The UI calls the trading pool directly, so it never asks for a router allowance.","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"through-the-pair","heading":"Remove through the trading pool contract","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Compute the outputs from getEffectiveReserves() : each reserve × liquidity ÷ LP total supply, rounded down. Removal first synchronizes the reserves, so donated shares count. Call the trading pool's removeLiquidity(liquidity, minYes, minNo, recipient, deadline) with minYes and minNo set from those outputs and your tolerance. The deadline is enforced on chain. After either path, your LP balance has fallen by liquidity , your Yes and No balances have risen by the outputs, and the trading pool has emitted LiquidityRemoved . Integrations that need router-based removal call the router's removeLiquidityWithPermit , whose bounds are named minYesOut and minNoOut . The router reference gives the values the permit must sign and the allowance fallback. Never grant a permanent or infinite allowance.","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"what-removal-does-not-do","heading":"What removal does not do","keywords":[],"path":"how-to/trading-remove-liquidity.html","sectionTitle":"How-to guides","summary":"Withdraw an LP position as raw Yes and No in any lifecycle phase.","text":"Removal always returns raw Yes and No, before and after question end, resolution, and forks. It does not use your wallet Invalid, redeem complete sets, settle winning shares, choose a child branch, or migrate liquidity. For those, see Handle resolution and Handle a universe fork .","title":"Remove liquidity","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","resolution","settlement","redeemShares","Invalid"],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"How-to guide A trading pool closes to swaps and added liquidity when its question ends; the market finalizes later, when its outcome is final. Use this guide from question end onward to turn LP tokens, complete sets, and winning shares back into ETH.","title":"Handle resolution","topic":"Trading","weight":1},{"fragment":"steps","heading":"Unwind after question end","keywords":[],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"Remove your LP tokens from the trading pool into Yes and No shares ( Remove liquidity ). Redeem matching Invalid, Yes, and No as complete sets while the SecurityPool is Operational and its universe has not forked. If the universe forks while the question is unresolved, follow Handle a universe fork . After the market finalizes, redeem the winning share through SecurityPool.redeemShares , which requires the SecurityPool to be Operational . Keep redeeming through this pool if its universe forks later; resolved shares cannot migrate. On an Invalid result, Invalid is the only winning share. Yes and No balances, including trading fees earned as LP, are worth nothing once they lose. Each redemption burns the redeemed shares and pays ETH at the SecurityPool's current collateral rate.","title":"Handle resolution","topic":"Trading","weight":0},{"fragment":"in-the-ui","heading":"In the UI","keywords":[],"path":"how-to/trading-handle-resolution.html","sectionTitle":"How-to guides","summary":"Unwind LP and redeem complete sets after question end, then claim winning shares once the market finalizes.","text":"Open the market. A closed market opens on its Settlement tab. To redeem complete sets, select Redeem sets , enter an amount in ETH to redeem , check You receive ≈ , and select Redeem complete sets . Once the market finalizes, a Redeem Yes , Redeem No , or Redeem Invalid option appears for the winning outcome. It redeems your entire balance of that share through this exact SecurityPool. Before finalization the option is absent. Settlement after the question ends. The market has not finalized yet, so only complete-set redemption and fork migration are offered. Every settlement transaction is simulated again at the latest block before your wallet opens, and stops if it would now fail.","title":"Handle resolution","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","fork","migrate","ShareToken"],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"How-to guide A fork closes the parent trading pool for swaps and additions and leaves every migration decision to you. This guide walks through moving a position into the child universe or universes you choose.","title":"Handle a universe fork","topic":"Trading","weight":1},{"fragment":"steps","heading":"Migrate a position","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Check the market's outcome. If it has already finalized, follow Handle resolution to redeem winning shares through its SecurityPool. Continue below only while the question is unresolved. Remove parent LP into parent Yes and No shares ( Remove liquidity ). Decide the destination child universe or universes for each of your Invalid, Yes, and No balances. Nothing in Trading chooses a child universe or migrates LP for you. For every nonzero parent balance you intend to migrate, submit one ShareToken.migrate(fromId, targetOutcomeIndexes) call with that token ID and the explicitly chosen, strictly increasing target outcome indexes. Each call mints the matching child-universe share balance. The parent balance stays visible, but that source token ID is locked for the wallet and can no longer be transferred. After each call, verify the expected child token ID and balance, then refresh or discover the canonical child SecurityPool. Wait until migration and Truth Auction processing return the child SecurityPool to Operational , then create a new trading pool for it. A child SecurityPool can take a trading pool only if it is back to Operational before the question's end date. Parent and child token IDs and reserves stay separate.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"choosing-targets","heading":"Choose fork targets","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Source and destination are independent: a parent Invalid, Yes, or No share can migrate into any valid child universe of the fork question, and the child receives the same share outcome as the source. Migrating parent Yes into three scalar child universes, for example, produces child Yes shares in all three children. For a categorical fork, select Invalid or one or more labeled answers. For a scalar fork, select Invalid or add one or more exact scalar ticks. The UI displays the human value and derives the packed onchain outcome index. A single-target call may create a missing child SecurityPool. A multi-target call must reference children whose canonical pools already exist. To migrate one source share to several new scalar outcomes, submit each missing outcome by itself; locking prevents transfers but not later migration of the same source into a new child. Once those children exist, another source share can target all of them in one call. Every call must add at least one source-and-child entitlement the wallet has not migrated before.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"in-the-ui","heading":"In the UI","keywords":[],"path":"how-to/trading-handle-a-fork.html","sectionTitle":"How-to guides","summary":"Migrate parent shares into chosen child branches and open a child trading pool.","text":"Open the market's Settlement tab and select Migrate . Choose the Share to migrate (Invalid, Yes, or No). Pick one or more child universes from the fork question's categorical answers or scalar ticks. Tick the acknowledgment that the migration moves your entire balance and permanently locks that share's transfers in the parent universe. Select Migrate to N child universes . The transaction copies and locks your entire balance of the selected source share. Repeat for each source share you want to move. Forks and resolution explains why the trading pool behaves this way.","title":"Handle a universe fork","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","constant product","complete set","Yes","No"],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"Explanation Trading is the two-reserve constant-product design from How To Build: Augur Constant Product with Invalid Insurance , adapted to Statoblast. This page explains what happens inside one entry.","title":"The two-way market","topic":"Trading","weight":1},{"fragment":"mental-model","heading":"Mental model","keywords":[],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"A SecurityPool is the Statoblast contract that holds ETH collateral for one question , universe , and pool configuration. Its canonical ShareToken is ERC-1155: creating one complete set mints equal Invalid, Yes, and No shares for that pool's universe-specific token IDs; redeeming a complete set burns those three shares and returns collateral at the pool's current dynamic rate. The Trading factory maps the exact SecurityPool address to one immutable-fee pair . The pair is both the Yes/No constant-product reserve and the transferable LP token; it never accepts Invalid shares. The router , which holds no balances or positions between calls, coordinates complete-set creation or redemption, pair swaps, and bounded asset delivery. Users and liquidity providers keep Invalid shares separately in their wallets. The invariant to remember is: shareToken.balanceOf ( pair , invalidTokenId ) = 0 Swaps and added liquidity are open only while the market is live; Forks and resolution lists what closes a pair. Parent and child SecurityPools are distinct markets and therefore use distinct pairs.","title":"The two-way market","topic":"Trading","weight":0},{"fragment":"one-entry","heading":"One entry, step by step","keywords":[],"path":"explanation/trading/two-way-market.html","sectionTitle":"Explanations","summary":"One ETH entry as a complete set, a swap, and Invalid insurance.","text":"The pair maintains k = Yes reserve × No reserve . Entering Yes looks like this; entering No is the mirror image. User → Router: enterPosition(pair, YES) with ETH Router → SecurityPool: createCompleteSet{value: ETH}() SecurityPool → Router: q Invalid + q Yes + q No Router → Pair: swap q No for Yes Pair → Router: additional Yes Router → User: q Invalid + total Yes Entering a Yes position. The trader ends up holding the Invalid shares from the complete set; the pair never sees them. Suppose the reserves are 1,000 Yes and 1,000 No, the fee is zero, and 100 complete-set shares are created. Contract math uses attoShares, where one displayed share is 10 18 attoShares. Swapping 100 No therefore yields 90.909090909090909090 Yes after flooring to a whole number of attoShares. The wallet receives 190.909090909090909090 Yes and 100 Invalid; the reserves become 909.090909090909090910 Yes and 1,100 No. Flooring the output favors existing liquidity providers. A No purchase simply reverses the reserves. No position record is created anywhere: wallet Yes, No, Invalid, and LP balances are the complete accounting state.","title":"The two-way market","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","Invalid","insurance"],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Explanation Invalid shares are held, not traded. This page explains what that buys a trader and what it cannot tell them.","title":"Invalid insurance","topic":"Trading","weight":1},{"fragment":"how-it-works","heading":"How it works","keywords":[],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Each ordinary ETH entry returns one Invalid share for each complete set created. If the question resolves Invalid, the holder redeems those shares with the SecurityPool 's redeemShares() at the current collateral value. Keeping Invalid shares out of the pair removes the on-chain three-reserve quadratic and makes an ordinary entry insured against an Invalid result. The cost is that nothing in the AMM can detect a suspicious market from an Invalid price, because no such price exists.","title":"Invalid insurance","topic":"Trading","weight":0},{"fragment":"worked-example","heading":"A worked Invalid result","keywords":[],"path":"explanation/trading/invalid-insurance.html","sectionTitle":"Explanations","summary":"Why Invalid is held rather than traded and what it pays.","text":"Alice entered with enough ETH to mint 100 complete-set shares, received 190 Yes after her swap, and kept 100 Invalid. The market resolves Invalid. The pair's Yes and No balances do not become valuable merely because they are nonzero. Alice redeems her 100 winning Invalid shares through the SecurityPool. Because of protocol retention , the refund is the current net collateral value, not necessarily her original gross ETH. Liquidity providers hold Invalid shares separately in exactly the same way. Selling or transferring LP tokens never moves that insurance.","title":"Invalid insurance","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","price","conditional","oracle"],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"Explanation A two-reserve pair produces exactly two prices, and both are conditional on the market resolving validly.","title":"Conditional pricing","topic":"Trading","weight":1},{"fragment":"formula","heading":"What the prices are","keywords":[],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"The constant-product marginal relationship prices one outcome using the opposite reserve: conditionalYes = noReserve yesReserve + noReserve conditionalNo = yesReserve yesReserve + noReserve The two values sum to 100% because they partition the valid outcomes only. That does not imply Invalid has zero probability; there is no unconditional Yes or No probability in this AMM. At 428.571 Yes and 1,000 No, Conditional Yes is about 70% and Conditional No about 30%. The larger No reserve makes Yes the more expensive side, which is why initializing at 70% Conditional Yes deposits more No than Yes.","title":"Conditional pricing","topic":"Trading","weight":0},{"fragment":"not-an-oracle","heading":"Not an oracle","keywords":[],"path":"explanation/trading/pricing.html","sectionTitle":"Explanations","summary":"What Conditional Yes and No mean and why the spot price is not an oracle.","text":"The displayed before-and-after price is a trade-impact aid, nothing more. Reserve spot values can be moved within a block, donated to, sandwiched, or go stale before inclusion. Protocol logic must never consume this price as an oracle; Trading includes no TWAP.","title":"Conditional pricing","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","LP","liquidity","minimum liquidity"],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"Explanation An LP token is a proportional claim on a pair 's Yes and No reserves and nothing else. This page explains how that claim is minted and what it does not cover.","title":"The liquidity-provider position","topic":"Trading","weight":1},{"fragment":"supply","heading":"How LP supply is scaled","keywords":[],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"Initial LP supply uses the smaller reserve as an accounting scale. The pair permanently mints 1,000 units to MINIMUM_LIQUIDITY_LOCK ( address(1) ), then mints min(Yes, No) − 1,000 to the initializer, so total initial supply is min(Yes, No) . At attoShare scales this avoids an overflowing geometric-mean multiplication. The absolute LP supply is arbitrary; wallet LP / total LP defines ownership. LP → Router: addLiquidityWithEth with ETH Router → SecurityPool: createCompleteSet() SecurityPool → Router: equal Invalid, Yes, No Router → Pair: add largest proportional Yes + No Pair → LP: LP tokens Router → LP: all Invalid + unused Yes/No Adding liquidity with ETH. The LP token covers only the Yes and No shares that entered the pair; the Invalid shares stay with the provider.","title":"The liquidity-provider position","topic":"Trading","weight":0},{"fragment":"what-it-claims","heading":"What the token claims","keywords":[],"path":"explanation/trading/liquidity-provider-position.html","sectionTitle":"Explanations","summary":"How LP supply is scaled and what an LP token claims.","text":"A holder of wallet LP / total LP can withdraw that fraction of both reserves as raw Yes and No shares at any time, including after trading closes. Swap fees are taken from the input and stay in the reserves, and direct Yes or No donations are synchronized into them, so both accrue to existing LPs. The claim is on shares, not ETH. Its mix of Yes and No shifts as trades move the price, and neither share redeems for anything if the question resolves Invalid. The pair cannot hold Invalid shares, so the Invalid minted with a provider's complete sets stays in the provider's wallet, outside the token; Invalid insurance explains what it covers.","title":"The liquidity-provider position","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","exit","bounds","Invalid"],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"Explanation Turning a directional position back into ETH means rebuilding complete sets. Three wallet and pair quantities cap how many you can rebuild.","title":"Why early ETH exits are limited","topic":"Trading","weight":1},{"fragment":"bounds","heading":"The three bounds","keywords":[],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"An insured exit of q complete sets from a wallet holding long Yes shares needs q Invalid shares, q Yes shares for the sets, and extra Yes shares to buy exactly q No shares from the pair : q ≤ wallet Invalid q + required Yes input(q) ≤ wallet Yes q < pair No reserve The SDK binary-searches these monotonic conditions; the chosen candidate is then simulated through the router . All three bounds also presume a live market: the swap reverts once the pair closes, and the SecurityPool redeems complete sets only while it is operational. Forks and resolution covers what closes a pair and how to settle afterwards. User → ShareToken: batch transfer of q Invalid + maximum Yes input to the router, with the encoded request ShareToken → Router: receive callback with the shares and request Router → Pair: exact-output swap for q No Pair → Router: q No Router → SecurityPool: redeemCompleteSet(q) SecurityPool → Router: current ETH value Router → User: measured ETH delta Router → User: unused Yes shares An insured exit. The exit starts with a share transfer to the router , not a router call. Pre-existing ETH in the router is never mixed into the delta the user receives.","title":"Why early ETH exits are limited","topic":"Trading","weight":0},{"fragment":"example","heading":"Example","keywords":[],"path":"explanation/trading/early-exit-limit.html","sectionTitle":"Explanations","summary":"The three bounds on redeeming complete sets from a directional wallet.","text":"A wallet holds 150 Invalid and 260 Yes shares. If buying 100 No requires 112 Yes, redeeming 100 sets needs 212 Yes and succeeds. Trying 150 might require 181 extra Yes, or 331 in total, and fails on Yes even though Invalid would cover it. If the wallet instead had only 60 Invalid, at most 60 sets are insured. Whatever Yes cannot be insured remains a valid directional asset; it has not disappeared.","title":"Why early ETH exits are limited","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","fork","resolution","lifecycle"],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Explanation A pair closes when its market can no longer be traded safely, but it never traps a position. This page explains which events close it and what a holder does next.","title":"Forks and resolution in Trading","topic":"Trading","weight":1},{"fragment":"what-closes","heading":"What closes a pair","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Swaps, initialization, and added liquidity close permanently at question end, when the universe forks, or when the SecurityPoolForker exposes a final outcome . They are also blocked while the SecurityPool is not operational or is awaiting fork continuation . LP removal deliberately has none of those guards. tradingStatus() reports which condition applies.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"after-a-fork","heading":"After a fork","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"LP → Parent pair: removeLiquidity() Parent pair → LP: parent Yes + No LP → ShareToken: migrate(fromId, chosen outcomes) ShareToken → LP: selected child shares Wait until migration and any Truth Auction return the child pool to Operational LP → Factory: createPair(exact child pool) Factory → LP: isolated child pair Carrying liquidity across a fork. Every step is the LP's own decision; nothing here happens automatically. A fork does not select a branch or migrate LP. A child pair can be initialized only if the child SecurityPool is back to Operational before the question's end date, which requires a fork caused by another question: pairs refuse initialization and swaps once the question has ended, and a fork caused by disputing this question always comes after its end date. Parent and child pools may share one ShareToken contract, but they have different universe-specific token IDs and different pair addresses. Handle a universe fork gives the step-by-step procedure.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"after-resolution","heading":"After resolution","keywords":[],"path":"explanation/trading/forks-and-resolution.html","sectionTitle":"Explanations","summary":"What closes a pair and what a holder does after a fork or resolution.","text":"Pair → Forker: getQuestionOutcome(pool) Forker → Pair: current Yes / No / Invalid outcome Pair → Pair: swaps and additions closed Holder → Pair: removeLiquidity remains available Pair → Holder: raw Yes + No Holder → SecurityPool: redeemShares() for the winning token SecurityPool → Holder: current collateral value Settling after resolution. The pair only closes; value is redeemed at the SecurityPool, never at the pair. If the question resolves Invalid, the Invalid shares held in the wallet are the settlement insurance. Fee growth in the pair's Yes and No reserves creates no redemption value on an Invalid result. Handle resolution gives the procedure.","title":"Forks and resolution in Trading","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","security","permit","reentrancy","reporting"],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Reference Trading has not been audited. Tests and internal reviews are not substitutes for an independent security assessment. This page states what the contracts defend against, what they assume, and what they leave to the user.","title":"Trading security model","topic":"Trading","weight":1},{"fragment":"authorization","heading":"Signature and callback authorization","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"LP permits use the standard ERC-2612 nonce, deadline, chain-bound EIP-712 domain, owner, spender, and exact value. The LP ledger is the repository's vendored ERC20.sol , sourced from the MIT-licensed OpenZeppelin Contracts v5.2.0 release . Its local changes pin Solidity 0.8.35, use repository formatting and descriptive revert strings, and substitute Augur unit terminology in comments; its state-transition and allowance algorithms are unchanged. TradingLiquidityToken.sol adapts the MIT-licensed v5.2.0 ERC20Permit by using the repository's shared OpenZeppelin-derived EIP-712/ECDSA primitive, a fixed version 1 , descriptive revert strings, and the stable Zoltar Two-Way LP domain name. It omits Nonces , IERC20Permit , and EIP712 inheritance only because their exact storage and hashing behavior is implemented directly by the local nonce mapping and shared authorization primitive. No signature or curve algorithm is reimplemented in the pair. OpenZeppelin ERC-20 prohibits minting to the zero address. The pair therefore locks MINIMUM_LIQUIDITY at MINIMUM_LIQUIDITY_LOCK , address(1) , which no key controls, instead of treating the zero address as an LP holder. Only pair operations can invoke the inherited internal mint and burn functions. A signature is authorization, not transaction privacy: integrations should use short deadlines and exact amounts. The router reference gives the allowance alternative for signers without ECDSA permits. Receive-based ERC-1155 operations use no off-chain signature. The ShareToken call must be submitted by the owner, while the versioned payload binds all contract identities, operation inputs, recipients, slippage, and deadline. Copying an observed payload cannot redirect assets and cannot separately consume an allowance because the router requires operator == from .","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"custody","heading":"Custody and reentrancy","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"The pair rejects foreign ShareTokens, Invalid shares, and noncanonical universe IDs in both single and batch callbacks. A reentrancy lock covers every reserve-changing operation and every LP mint or burn; LP transfer , approve , and permit change no reserves and are not locked. Recipient callbacks can execute arbitrary code, so final reserves are read from authoritative balances after transfers. Recorded-balance deficits revert; valid Yes and No donations synchronize upward and accrue to current LPs. The router recognizes pairs only through its immutable factory, opens callback state only around one expected pool and share token, and restores its starting share balances. Its ETH receiver opens only around redemption from that pool. This prevents unsolicited callbacks and keeps forced ETH separate from exit proceeds. Factory checks prevent a malicious pool from borrowing another question's ShareToken or universe identity. CREATE2 plus one immutable fee gives one canonical pair per exact pool without privileged replacement. Because an ERC-1155 transfer to an address without code cannot invoke a receiver callback, an attacker can send shares to a predicted CREATE2 address before deployment. The factory's predeployment quarantine removes those canonical balances during pair construction, so initialization starts with zero canonical balances, including zero Invalid. Foreign token contracts cannot be enumerated and may still assign irrelevant balances to the address; the pair never recognizes or moves them.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"assumptions","heading":"Assumptions","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"The configured Statoblast SecurityPoolFactory , pool, ShareToken , forker , question data, and universe state are canonical and behave as implemented in the matching core release. Users set realistic slippage and deadlines and obtain a fresh simulation in the current block immediately before submission. Wallets and RPC endpoints accurately report account, chain, balances, approvals, and receipts.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"known-risks","heading":"Known risks","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Spot prices are not an oracle and expose users to front-running and sandwiches. A lifecycle transition, fork, resolution, reserve donation, retention update, or intervening trade can invalidate a quote; contract guards and slippage bounds make the transaction revert rather than promise execution. Initial liquidity determines the starting conditional price and should be initialized atomically. LP tokens cover only Yes/No reserves; separately held Invalid can be lost, transferred, or insufficient. A valid-resolution LP can suffer directional loss, and Yes/No reserves may have no redemption value after an Invalid result. Remaining risks also include first-price choice, stale simulation, lifecycle races, recipient denial of ETH or ERC-1155 reception, core-contract bugs, and approval misuse. Slippage and deadlines bound execution but do not remove MEV. The immutable factory fee is a deployment choice, not a claim of economic optimality.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"reporting","heading":"Reporting a vulnerability","keywords":[],"path":"reference/trading/security-model.html","sectionTitle":"Reference","summary":"Authorization, custody, assumptions, known risks, and vulnerability reporting.","text":"Report a suspected vulnerability through GitHub private vulnerability reporting . Include the affected commit, contracts and functions, prerequisites, a minimal reproduction, expected impact, and whether funds or deployment keys may be at immediate risk. If private reporting is unavailable, open a public issue asking maintainers to establish a private channel, but do not include vulnerability details. Do not exploit a live deployment or publish details before maintainers have had a reasonable opportunity to respond.","title":"Trading security model","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","design","limitations","non-goals"],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"Explanation Trading is deliberately small. This page records why each decision was made and which features are out of scope, so that future work does not weaken the pair's one hard invariant.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":1},{"fragment":"decisions","heading":"Decisions","keywords":[],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"Two reserves only. A pair holding Yes × No shares avoids the three-way quadratic and does not price Invalid . Exact SecurityPool identity. A pair is keyed by the pool address, so parent and child branch pools always map to different pairs even when they share one ShareToken . The factory's canonical validation stops a pool from borrowing another market's identity. One immutable fee per factory. There is no owner, protocol fee switch, or mutable parameter. Balance-delta integration. The router measures complete-set creation and redemption by observed share and ETH balance deltas because retention changes the ETH-to-share rate; it never assumes a fixed ratio. Its custody checks are listed in the router reference. Minimum-reserve LP scale. Initial LP supply follows the smaller reserve rather than a geometric mean, which would overflow at large share scales; only proportional ownership matters. The liquidity-provider position gives the rule. Donations accrue to LPs. Reserve-dependent operations first synchronize reserves up to actual balances, so unsolicited Yes or No shares benefit existing LPs instead of the next trader. The security model covers the related custody defenses. No automatic fork behavior. Parent liquidity is removed as parent shares. The user explicitly chooses migration targets and initializes distinct child pairs.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":0},{"fragment":"limitations","heading":"Limitations and non-goals","keywords":[],"path":"explanation/trading/architecture-decisions.html","sectionTitle":"Explanations","summary":"The seven design decisions and the features the MVP leaves out.","text":"The MVP intentionally does not implement a three-way invariant, Invalid-share trading, an invalidity-probability oracle, weighted reserves, quadratic solvers, flash swaps, a protocol fee, governance controls, upgradeable proxies, automatic branch selection, automatic LP migration, an insured-position NFT, or per-user on-chain position accounting. It also has no TWAP, routing across markets, guaranteed deep liquidity, or mechanism to withdraw more early ETH than complete-set insurance and reserves permit. Trading is unaudited; the Trading security model states what it defends against and what it assumes. Future work may add separate Invalid markets, safer oracle observations, routing, or bounded convenience flows. Those are distinct designs and must not weaken the invariant that this pair never accepts or holds Invalid shares.","title":"Trading architecture decisions and limitations","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","factory","pair","tradingStatus","CREATE2"],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Reference All Trading contracts compile with Solidity 0.8.35 for Osaka. Revert strings are operational diagnostics, not stable compatibility commitments.","title":"Trading contracts","topic":"Trading","weight":1},{"fragment":"factory","heading":"TwoWayConstantProductFactory","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"constructor(ISecurityPoolFactory, uint256 feeBps) fixes the core factory and fee; feeBps < 10,000 . createPair(ISecurityPool) validates the exact canonical pool, deploys with CREATE2, and returns the existing canonical pair on duplicate calls. getPair(ISecurityPool) → pair maps exact pool identity to a pair. isPair(address) → bool recognizes router-eligible pairs. predictPair(ISecurityPool) → address calculates the CREATE2 address. securityPoolFactory() , feeBps() , and predeploymentShareSink() expose immutable configuration. Canonical validation requires the pool's own securityPoolFactory , the factory's (originId, universeId) lookup, and shareToken.canonicalPoolByUniverse(universeId) all to agree. CREATE2 pair addresses exist counterfactually before code is deployed, when ERC-1155 receiver checks cannot run. Each factory therefore deploys an ownerless PredeploymentShareSink . A pair constructor transfers any canonical Invalid, Yes, or No already present at its future address into that sink before returning. Those quarantined shares are permanently inaccessible; do not send shares to a predicted pair address.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"pair","heading":"TwoWayConstantProductPair","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Immutable accessors expose factory , securityPool , shareToken , universeId , questionId , invalidTokenId , yesTokenId , noTokenId , and feeBps . Constants are MINIMUM_LIQUIDITY (1,000) and MINIMUM_LIQUIDITY_LOCK ( address(1) ), which holds the locked minimum liquidity. LP ERC-20 accessors are name , symbol , decimals , totalSupply , balanceOf , allowance , approve , transfer , and transferFrom . ERC-2612 accessors are permit(owner, spender, value, deadline, v, r, s) , nonces(owner) , and DOMAIN_SEPARATOR() . constructor(factory, securityPool, feeBps, predeploymentShareSink) is called only by the factory. It requires nonzero addresses and feeBps < 10,000 , reads the ShareToken, universe, question, and token IDs from the SecurityPool, and quarantines any canonical shares already at its address, emitting PredeploymentSharesQuarantined . getReserves() returns the recorded Yes and No reserves as of the last pair mutation or sync() . getEffectiveReserves() returns the pair's current Yes and No balances, including unsynchronized donations, and reverts if either balance is below its recorded reserve or the pair holds Invalid shares. The router's enterPosition reads it for the before-trade Conditional Yes price. tradingStatus() returns Open , QuestionEnded , PoolInactive , AwaitingForkContinuation , UniverseForked , QuestionResolved , or Uninitialized . initialize(yesAmount, noAmount, minLiquidity, recipient) pulls the first reserves, locks MINIMUM_LIQUIDITY , and mints the remainder once. It requires an uninitialized pair ( Already initialized ), a nonzero recipient, zero Invalid, Yes, and No balances at the pair ( Nonzero initial balance ), min(yesAmount, noAmount) > MINIMUM_LIQUIDITY ( Initial liquidity too small ), and minted liquidity of at least minLiquidity ( Minimum liquidity ). addLiquidity(maxYes, maxNo, minLiquidity, recipient) synchronizes donations, selects the largest proportional amounts, pulls them, and mints LP. It reverts with Liquidity rounds to zero when either used amount is zero and with Minimum liquidity when the minted LP is zero or below minLiquidity . removeLiquidity(liquidity, minYes, minNo, recipient, deadline) burns caller LP and returns proportional raw shares when called at or before deadline . It has no lifecycle-close guard. It reverts with Liquidity slippage below minYes or minNo and with Liquidity output is zero when either output rounds to zero, so a dust LP amount cannot be removed on its own. swapExactInput(yesForNo, amountIn, minAmountOut, recipient) pulls the gross input and sends the floor-rounded output; it reverts with Swap slippage below minAmountOut . swapExactOutput(yesForNo, amountOut, maxAmountIn, recipient) pulls the ceil-rounded required input and sends the exact output; it reverts with Swap slippage above maxAmountIn . quoteExactInput(yesForNo, amountIn) → (amountOut, feeAmount) and quoteExactOutput(yesForNo, amountOut) → (amountIn, feeAmount) quote against effective reserves. sync() records current balances as reserves. It reverts when the pair is uninitialized, a balance fell below its reserve, or the pair holds Invalid shares. onERC1155Received , onERC1155BatchReceived , and supportsInterface implement receiver discovery. Only the canonical ShareToken 's exact Yes/No IDs are accepted. Pre-initialization transfers must be initiated by the pair's own pull. initialize , addLiquidity , and both swaps require an open lifecycle and otherwise revert with Question ended , Universe forked , Fork continuation pending , Pool inactive , or Question resolved ; all but initialize also revert with Uninitialized before the first deposit. tradingStatus() is a concise action blocker, not an authoritative settlement summary. The first matching condition wins in this order: Uninitialized , UniverseForked , AwaitingForkContinuation , PoolInactive , QuestionResolved , QuestionEnded , then Open . An uninitialized forked pair therefore reports Uninitialized , and a finalized question reports QuestionResolved even after its end time. Read SecurityPoolForker.getQuestionOutcome(pool) when the finalized outcome itself is required.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"sink","heading":"PredeploymentShareSink","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"Accepts ERC-1155 transfers and has no withdrawal or administrative method. It exists only to preserve clean pair initialization and the zero-Invalid invariant after counterfactual-address poisoning attempts.","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"math","heading":"TwoWayConstantProductMath","keywords":[],"path":"reference/trading/contracts.html","sectionTitle":"Reference","summary":"Factory, pair, math library, and predeployment sink constructors, entrypoints, and revert conditions.","text":"The internal library provides exact-input and exact-output quotes, ceil rounding through the repository's full-precision Math.mulDiv , proportional deposits, initial odds, and conditional price basis points. Production paths never multiply reserve products. Rounding directions are listed in Units and rounding .","title":"Trading contracts","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","router","enterPosition","receive request","permit"],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"Reference Trading deploys one canonical factory and one canonical router. The router handles entry and liquidity operations, share-transfer exits and complete-set redemption, and permit-assisted LP removal.","title":"Trading router","topic":"Trading","weight":1},{"fragment":"entrypoints","heading":"Entrypoints","keywords":[],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"TwoWayConstantProductRouter(factory) fixes the only eligible factory. All user mutations enforce a deadline and a reentrancy guard. The router's receiver callbacks accept only the active pool's canonical share token and universe IDs. receive() accepts ETH only during redemption and only from the expected SecurityPool. enterPosition(pair, longOutcome, minLongSharesOut, recipient, deadline) is payable. It creates actual complete-set shares from msg.value , verifies equal Invalid/Yes/No deltas, swaps all opposite shares, and delivers long shares plus Invalid. It reverts with Minimum long shares below minLongSharesOut . It returns EnterResult : ethSpent , completeSetShares , oppositeSharesSwapped , additionalLongShares , totalLongShares , invalidInsurance , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . createPairAndInitializeWithEth(pool, conditionalYesBpsValue, minLiquidity, recipient, deadline) creates or reuses the deterministic pair and requires it to be uninitialized ( Pair already initialized ) before atomically seeding it at a Conditional Yes price strictly between 0 and 10,000 basis points. initializeWithEth(pair, conditionalYesBpsValue, minLiquidity, recipient, deadline) initializes an already created canonical pair. addLiquidityWithEth(pair, maxYesUsed, maxNoUsed, minLiquidity, recipient, deadline) creates complete sets, deposits the authoritative proportional maximum, and returns Invalid and unused shares. It reverts with Liquidity price slippage when yesUsed > maxYesUsed or noUsed > maxNoUsed . minLiquidity alone does not bound the price: a swap toward even odds before the call raises both the deposit of the side with the smaller reserve and the minted LP. removeLiquidityWithPermit(pair, liquidity, minYesOut, minNoOut, recipient, deadline, v, r, s) calls the pair's permit for the caller as owner, the router as spender, exactly liquidity as value, and the same deadline ; the signature must cover those values. A failing permit is ignored when the router's allowance already covers liquidity ; otherwise the call reverts with LP permit or allowance . The router then pulls the LP and returns raw Yes/No directly to the recipient. factory() exposes the immutable factory. onERC1155Received , onERC1155BatchReceived , and supportsInterface exist only for the receive-based operations described below and for the pair callbacks inside an operation. The payable entrypoints require nonzero msg.value ( ETH input is zero ). Every entrypoint requires a recipient that is neither zero nor the router ( Invalid recipient ) and block.timestamp ≤ deadline ( Deadline expired ); those that take a pair require it to be the factory's canonical pair for its SecurityPool ( Unrecognized pair , Noncanonical pair ). The three liquidity entrypoints that take ETH return LiquidityResult : pair , completeSetShares , yesUsed , noUsed , yesReturned , noReturned , invalidInsurance , and liquidity . Every successful share-custody operation, including the receive-based operations below, asserts that the router's Invalid, Yes, and No balances equal their starting values, preserving pre-existing forced shares.","title":"Trading router","topic":"Trading","weight":0},{"fragment":"approval-free","heading":"Exits and complete-set redemption by share transfer","keywords":[],"path":"reference/trading/router.html","sectionTitle":"Reference","summary":"Router entrypoints, custody guarantees, and approval-free share operations.","text":"The router has no exitPosition or redeemCompleteSet entrypoint. Users exit and redeem by calling the ShareToken 's safeBatchTransferFrom with themselves as both caller and owner, the router as recipient, and an encoded request in the data field. No setApprovalForAll is required. The request is the ABI-encoded ReceiveRequest struct with fields in this order: version (must equal CALLBACK_VERSION , currently 1), operation (0 ExitPosition , 1 RedeemCompleteSet ), shareToken , securityPool , pair , universeId , questionId , invalidTokenId , yesTokenId , noTokenId , longOutcome , completeSetShares , maxLongSharesIn , minEthOut , payoutRecipient , refundRecipient , and deadline . encodeReceiveRequest produces it. The router accepts only owner-initiated top-level transfers ( operator == from ); internal pair callbacks are distinguished from top-level user callbacks. Insured exit . The transfer carries exactly two IDs in the order [invalidTokenId, long token ID] with the values [q, maxLongSharesIn] , where q is completeSetShares , and longOutcome is Yes (1) or No (2). The router buys exactly q opposite shares with an exact-output swap, redeems q complete sets at the pool, and returns any unused long shares to the bound refund recipient. It emits PositionExitedByTransfer . Complete-set redemption. The transfer carries exactly three IDs in the order [invalidTokenId, yesTokenId, noTokenId] , each with the value completeSetShares ; longOutcome must be None (3) and maxLongSharesIn zero. The router redeems them at the exact canonical SecurityPool and emits CompleteSetRedeemedByTransfer . Both operations require completeSetShares > 0 , a payoutRecipient and a refundRecipient that are neither zero nor the router, and a pair that is the factory's canonical pair for securityPool , with every identity field matching it. Complete-set redemption through the router therefore needs an existing pair; without one, call the SecurityPool's redeemCompleteSet directly. Both operations measure the ETH the redemption produced, require that delta to be positive and at least minEthOut , and forward exactly that delta to the payout recipient. Pre-existing forced ETH in the router is never mixed into a payout. For LP removal through the router, Safes and integrations without signature support may use ordinary exact allowances instead of a permit. The first-party UI calls the pair directly and needs no router allowance.","title":"Trading router","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","events","Swap","indexer"],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"Reference The factory and pair emit every reserve and LP state change. The router emits an event only for the two share-transfer operations it executes itself. Parameters prefixed with indexed are log topics.","title":"Trading events","topic":"Trading","weight":1},{"fragment":"factory","heading":"Factory","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"PairCreated(indexed securityPool, indexed shareToken, indexed universeId, pair, feeBps) identifies one exact branch market and its immutable fee.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"pair","heading":"Pair","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"LiquidityInitialized(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records the first reserve contribution and circulating LP minted; locked minimum liquidity is separate. LiquidityAdded(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records proportional reserve use. LiquidityRemoved(indexed provider, indexed recipient, yesAmount, noAmount, liquidity) records raw-share output. Swap(indexed sender, indexed recipient, yesForNo, exactOutput, amountIn, amountOut, feeAmount, resultingYesReserve, resultingNoReserve) provides authoritative direction, mode, amounts, fee, and resulting state. Sync(yesReserve, noReserve) records reserves after synchronization or mutation. PredeploymentSharesQuarantined(invalidAmount, yesAmount, noAmount) records canonical shares removed from a counterfactual pair address during construction. The destination is the factory's immutable predeploymentShareSink . Standard ERC-20 Transfer and Approval events describe LP ownership and allowances.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"router","heading":"Router","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"PositionExitedByTransfer(indexed owner, indexed pair, completeSetShares, longSharesUsed, longSharesRefunded, payoutRecipient) records an insured exit initiated by owner 's share transfer. CompleteSetRedeemedByTransfer(indexed securityPool, completeSetShares, payoutRecipient) records a complete-set redemption initiated by share transfer.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"attribution","heading":"Attributing router operations","keywords":[],"path":"reference/trading/events.html","sectionTitle":"Reference","summary":"Factory, pair, and router events and indexer attribution rules.","text":"For router-mediated operations, pair provider / sender fields and SecurityPool creator / redeemer fields identify the router, not the initiating wallet. Pair recipient identifies the explicit asset recipient only for direct pair calls and router liquidity operations; router entry and insured-exit swaps name the router, which then forwards the assets. Insured exits carry the owner in PositionExitedByTransfer . For complete-set redemptions, take the owner from the ShareToken TransferBatch log's from field, since CompleteSetRedeemedByTransfer records only the pool and payout recipient. Entry and liquidity operations emit no router event, so for those an indexer must combine the transaction sender, the called router method, pair and core logs, and the recipient from calldata or the ShareToken TransferBatch log; it must not infer wallet attribution from the immediate-caller fields alone. Router return tuples are available from authoritative call simulation only; they are not stored in a transaction receipt. Complete-set and ETH-flow evidence comes from the SecurityPool's CompleteSetCreated and CompleteSetRedeemed events plus transaction logs.","title":"Trading events","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","SDK","quoteExactOutput","maximumInsuredExit","encodeReceiveRequest"],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Reference The private workspace package @zoltar/trading-shared holds the pure Trading math that the UI and the Solidity parity tests share. All chain quantities are bigint .","title":"Trading SDK","topic":"Trading","weight":1},{"fragment":"pure-math","heading":"Pure math","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/math mirrors the quote and price functions of TwoWayConstantProductMath . It has no counterpart of the library's initial-odds and proportional-deposit functions; the UI estimates those in ui/trading/ts/features/live/liquidityEstimate.ts . quoteExactInput(reserveIn, reserveOut, amountIn, feeBps) and quoteExactOutput(reserveIn, reserveOut, amountOut, feeBps) return a SwapQuote , { amountIn, amountOut, netInput, feeAmount } , with the contract's floor (exact input) and ceil (exact output) rounding. They throw on empty reserves, an out-of-range output, or feeBps ≥ 10,000 . conditionalYesBps(yesReserve, noReserve) returns the Conditional Yes price in basis points, floor-rounded.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"positions","heading":"Position quotes","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/positions takes { yesReserve, noReserve, feeBps } and a longOutcome of 'YES' or 'NO' : quoteEnterPosition(longOutcome, completeSetShares, reserves) mirrors enterPosition after minting and returns an EnterPositionQuote : longOutcome , completeSetShares , oppositeSharesSwapped , additionalLongShares , totalLongShares , invalidInsurance , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . quoteExitPosition(longOutcome, completeSetShares, reserves) mirrors the insured exit and returns an ExitPositionQuote : longOutcome , completeSetShares , longSharesSwapped , totalLongShares , invalidRequired , feeAmount , conditionalYesBpsBefore , and conditionalYesBpsAfter . largestExitForLongShares({ ...reserves, longOutcome, longShares, completeSetCap? }) binary-searches the largest complete-set amount whose total long-share cost fits within longShares and stays below the opposite reserve. The optional completeSetCap bounds the result further. maximumInsuredExit({ ...reserves, longOutcome, longBalance, invalidBalance }) calls largestExitForLongShares with the long balance as longShares and the Invalid balance as completeSetCap .","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"receive-request","heading":"Receive request encoding","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Module @zoltar/trading-shared/trading/receiveRequest exports encodeReceiveRequest(request) , which ABI-encodes the data argument for a share transfer to the router. The request, typed ReceiveRequest , is a positional tuple in the field order of the router's ReceiveRequest struct, which the router reference lists.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"transaction-helpers","heading":"Transaction helpers","keywords":[],"path":"reference/trading/sdk.html","sectionTitle":"Reference","summary":"Shared bigint math, exit search, receive-request encoding, and simulation-pinning helpers.","text":"Transaction-facing helpers live in the Trading UI at ui/trading/ts/protocol/tradeQuote.ts , not in the shared package: minimumAfterSlippage(amount, slippageBps?) floors and maximumAfterSlippage(amount, slippageBps?) ceils a bound; slippage defaults to UI_SLIPPAGE_BPS (50). requireTransactionSlippageBps throws outside MINIMUM_SLIPPAGE_BPS (1) to MAXIMUM_SLIPPAGE_BPS (500). stableSimulation(client, simulate) reads the latest block with latestBlockIdentity(client) and passes its blockNumber , blockHash , and blockTimestamp to simulate , whose reads must all use that block number. A reorg during those reads is not detected. simulateWithDeadline(client, expiry, simulate, resolveDeadline?) does the same and also resolves expiry , a TransactionExpiry that is either an absolute deadline or { validityMinutes } between 1 and 1,440 ( requireTransactionValidityMinutes ), against the pinned block's timestamp. The optional resolveDeadline(block, requestedDeadline) can replace that deadline, and simulate receives (block, deadline) . retainApprovedMinimum(approved, refreshed, label) and retainApprovedMaximum(approved, refreshed, label) return the approved bound, or throw when the submission-time simulation no longer satisfies it. Pure math is a responsive preview only. A quote does not expire when a new block arrives: immediately before wallet submission the client simulates the actual call again at the latest block, and submits with the bounds and deadline approved in the quote only if that simulation succeeds within them.","title":"Trading SDK","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","configuration","manifest","environment"],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"Reference The local deployment script solidity/ts/trading/deploy/deploy-local.mts reads the environment variables below. No public trading deployment manifest is bundled; the client derives and checks its contracts at startup.","title":"Trading deployment configuration","topic":"Trading","weight":1},{"fragment":"environment","heading":"Environment variables","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"Name Meaning Default TRADING_RPC_URL JSON-RPC endpoint http://127.0.0.1:8545 TRADING_DEPLOYER Unlocked RPC account First eth_accounts entry ZOLTAR_DEPLOYMENT_MANIFEST Existing matching core manifest Required TRADING_FEE_BPS Immutable trading fee 30 TRADING_FEE_BPS must be a whole number from 0 to 9999. The script stops when the RPC chain ID differs from the core manifest's, when the manifest's SecurityPoolFactory has no code on that chain, or when the RPC exposes no account. Manifests must not contain secrets.","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"manifest","heading":"Deployment manifest","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"bun run trading:deploy:local writes solidity/deployments/trading/local.json for scripts and integration environments. The file is git-ignored because local addresses are ephemeral. A generated manifest contains: network : decimal and hexadecimal chain IDs plus the deployment RPC; core : the SecurityPoolFactory address, checked to have code on the RPC chain, and the source manifest path; trading : factory, router, and immutable feeBps ; transactions : factory and router objects shaped as { hash, blockNumber: \"\" } . blockNumber is a JSON string, not a JavaScript number, so large receipt block numbers remain exact; compilerProfiles : exact versions and settings from the main Solidity artifact; bytecodeHashes : creation-bytecode commitments; deployer and deployedAt . Pairs never appear as static deployment inputs. Discover them dynamically with getPair(pool) , verify with isPair , or derive the deterministic address with predictPair . Review a manifest before publishing it, and never copy local ephemeral addresses into a public-network file.","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"client","heading":"What the client derives","keywords":[],"path":"reference/trading/configuration.html","sectionTitle":"Reference","summary":"Deployment script environment variables, the local manifest, and what the client derives and stores.","text":"The standalone client reads no environment variables. At startup it uses: Networks: the build writes core-deployments.json from the mainnet and Sepolia deployment manifests in docs/ , with each network's default public RPC URL. Mainnet is listed but disabled in the UI build, and the default network is Sepolia. RPC override: Settings beside the wallet selects another supported network or accepts an optional HTTPS or loopback HTTP RPC URL. URL parameters: network ( sepolia ) pins the network instead of following the wallet, rpcUrl overrides the saved RPC URL, universe selects the universe shown, and simulate=1 with an optional simScenario selects the simulator . Trading contracts: the factory and router addresses are computed with the fixed 30 basis-point fee through the core deployment's canonical CREATE2 proxy, and each address is checked for code. If either contract is missing, the connected wallet can deploy it. Markets: the market and SecurityPool lists show favorites saved in the browser. Opening an address reads that SecurityPool and checks it against the canonical SecurityPoolFactory , Zoltar, and ShareToken; no market address is hard-coded. Mint capacity follows BAL-03 . Trade settings: slippage tolerance (1 to 500 basis points, default 50) and transaction validity (1 to 1,440 minutes, default 20) are kept in browser local storage under zoltar.trading.tradeSettings . Price impact: the trade ticket cautions above 2%, requires an explicit confirmation above 5%, and refuses the trade above 15%. Quote and simulation behavior is described in the Trading SDK .","title":"Trading deployment configuration","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","invariants","custody","k"],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Reference These conditions are required at every successful external state transition. Reverting calls leave the prior state unchanged. Protocol-wide invariants are catalogued separately in Protocol invariants .","title":"Trading invariants","topic":"Trading","weight":1},{"fragment":"pair-custody","heading":"Pair custody","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"The pair's Yes balance is greater than or equal to its stored Yes reserve. The pair's No balance is greater than or equal to its stored No reserve. The pair's Invalid balance is exactly zero. An LP withdrawal cannot claim more Yes or No shares than the pair owns. Withdrawal amounts are proportional to synchronized reserves and the liquidity burned. Unsolicited Yes or No donations can make a balance greater than its stored reserve. Before reserve-dependent mutations, the pair synchronizes stored reserves upward to those effective balances. Invalid shares are never a trading asset and cannot be donated through an accepted ERC-1155 callback.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"router-custody","heading":"Router custody","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Every successful router operation ends with the same Invalid, Yes, and No balances with which that operation began. This deliberately preserves any pre-existing balances while preventing the operation from accumulating new share residue.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"swaps","heading":"Swaps","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"For every successful exact-input or exact-output swap, k_after ≥ k_before , where k is the synchronized effective Yes reserve multiplied by the synchronized effective No reserve. An exact-output swap delivers exactly the requested output amount. An exact-output swap never charges more than the caller's maxAmountIn . The product comparison starts from effective reserves so a donation cannot be mistaken for swap-created growth.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"lifecycle","heading":"Lifecycle","keywords":[],"path":"reference/trading/invariants.html","sectionTitle":"Reference","summary":"Custody, swap, and lifecycle conditions at every state transition.","text":"Once the question has ended, the question has resolved, or the universe has forked, initialization, liquidity addition, and both swap forms revert permanently. While fork continuation is pending or the SecurityPool is not operational, the same operations also revert for as long as that state lasts. Proportional liquidity removal has no lifecycle guard, so LP tokens never become trapped.","title":"Trading invariants","topic":"Trading","weight":0},{"fragment":"","heading":"","keywords":["Trading","attoShares","rounding","token ID"],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"Reference Every Trading quantity is an integer in an atomic unit, and swap rounding always favors existing liquidity providers.","title":"Trading units and rounding","topic":"Trading","weight":1},{"fragment":"units","heading":"Units","keywords":[],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"ETH and collateral outputs use attoETH (10 −18 ETH). Shares and LP tokens use attoShares, the 18-decimal atomic uint256 unit: one displayed share is 10 18 attoShares. At an empty SecurityPool, one attoETH creates one attoShare of every outcome: 1 ETH creates one Yes, one No, and one Invalid share. Protocol retention makes the later collateral-to-share ratio dynamic, so clients must use the current mutation result rather than assuming this initial rate. Fees, slippage, initial conditional price, and displayed conditional price use basis points over 10,000 where applicable. Deadlines and question end times are Unix seconds. Universe IDs are uint248 . A token ID is (universeId << 8) | outcome , with local outcomes Invalid = 0, Yes = 1, No = 2.","title":"Trading units and rounding","topic":"Trading","weight":0},{"fragment":"rounding","heading":"Rounding","keywords":[],"path":"reference/trading/units-and-rounding.html","sectionTitle":"Reference","summary":"Atomic units, token ID layout, and rounding directions.","text":"Exact input computes net = ⌊gross × (10,000 − fee) / 10,000⌋ and out = ⌊reserveOut × net / (reserveIn + net)⌋ . Exact output computes net = ⌈reserveIn × out / (reserveOut − out)⌉ and gross = ⌈net × 10,000 / (10,000 − fee)⌉ . These directions favor existing LPs. Liquidity deposits round reserve use down, and the LP minted is the smaller of ⌊yesUsed × supply / yesReserve⌋ and ⌊noUsed × supply / noReserve⌋ . Removal rounds each reserve output down. Initial alternative odds round the smaller deposited reserve down. Conditional Yes is NO / (YES + NO) and Conditional No is YES / (YES + NO) ; in basis points, Conditional Yes is ⌊10,000 × NO / (YES + NO)⌋ . Client slippage bounds round a minimum down and a maximum up.","title":"Trading units and rounding","topic":"Trading","weight":0}] diff --git a/docs/assets/screenshots/fingerprints.json b/docs/assets/screenshots/fingerprints.json index 4cd4cf6fa..4f42b8bf4 100644 --- a/docs/assets/screenshots/fingerprints.json +++ b/docs/assets/screenshots/fingerprints.json @@ -1,5 +1,5 @@ { - "statoblast": "487cdc36b7605a2395ea65ecc7e4ec43afb50dba6faecbac82e4563640b68749", - "trading": "74aecfb9d3e51bab1f81bb4f11d68fa0ebc4789a514b59cbd68f93c033ec6ec0", - "zoltar": "1548ee8ea4238e46e3739c45cd6036b0342ebc3b82200e0652a6de88ee18fc67" + "statoblast": "c8d137337852527cf72797fca2a19ee46b5d71bb21af739e0ccd78da6ae7b468", + "trading": "ea95fbb9c6acfca0409063ee85942317f6e670606680f1e9ba93b009fd501a03", + "zoltar": "0d05898b3ed1a7604918846952ced9ff64a66db92cdf3e6afe4b6b9d615a32fe" } diff --git a/docs/assets/screenshots/statoblast/pool-after-mint.png b/docs/assets/screenshots/statoblast/pool-after-mint.png index 5307112aa..f0cd70029 100644 Binary files a/docs/assets/screenshots/statoblast/pool-after-mint.png and b/docs/assets/screenshots/statoblast/pool-after-mint.png differ diff --git a/docs/assets/screenshots/zoltar/discover-questions.png b/docs/assets/screenshots/zoltar/discover-questions.png index 838e4dee1..7a6d2243f 100644 Binary files a/docs/assets/screenshots/zoltar/discover-questions.png and b/docs/assets/screenshots/zoltar/discover-questions.png differ diff --git a/docs/tutorials/zoltar-first-question.html b/docs/tutorials/zoltar-first-question.html index fbe3e4448..b52e82649 100644 --- a/docs/tutorials/zoltar-first-question.html +++ b/docs/tutorials/zoltar-first-question.html @@ -46,7 +46,7 @@

Create it

Find it in the registry

  1. Select Browse questions.
  2. -
  3. Select Discover questions. The browser scans the registry and lists your question under Downloaded.
  4. +
  5. Your question appears automatically under Downloaded (1).
The Questions list with the Downloaded tab selected, showing Will it rain in Lisbon on 1 June 2027?, marked Binary, with its end time and a Use for fork button. diff --git a/tooling/docs/ui-screenshot-specs/zoltar.mts b/tooling/docs/ui-screenshot-specs/zoltar.mts index a3712d150..905c7f777 100644 --- a/tooling/docs/ui-screenshot-specs/zoltar.mts +++ b/tooling/docs/ui-screenshot-specs/zoltar.mts @@ -37,8 +37,8 @@ export const ZOLTAR_SCREENSHOTS: readonly UiScreenshotSpec[] = [ id: 'discover-questions', app: 'zoltar', scenario: 'deployed', - steps: [...createQuestion, { click: 'Browse questions' }, { click: 'Discover questions' }, { waitForText: 'Will it rain in Lisbon on 1 June 2027?' }], - expectText: ['Questions', 'Downloaded', 'Will it rain in Lisbon on 1 June 2027?'], + steps: [...createQuestion, { click: 'Browse questions' }, { waitForText: 'Will it rain in Lisbon on 1 June 2027?' }], + expectText: ['Questions', 'Downloaded (1)', 'Will it rain in Lisbon on 1 June 2027?'], viewport: pageViewport, crop: { selector: '.section-block', containing: 'Will it rain in Lisbon on 1 June 2027?' }, usedBy: tutorial, diff --git a/ui/coreShared/css/base.css b/ui/coreShared/css/base.css index 0b85282e8..1687e6fdb 100644 --- a/ui/coreShared/css/base.css +++ b/ui/coreShared/css/base.css @@ -930,11 +930,6 @@ button.quiet:disabled { text-transform: inherit; color: inherit; white-space: inherit; - opacity: 0.72; -} - -button .loading-value { - opacity: 1; } .currency-value-wrap { diff --git a/ui/coreShared/ts/components/LocalBrowseControls.tsx b/ui/coreShared/ts/components/LocalBrowseControls.tsx index 344edd2ce..edf657ec4 100644 --- a/ui/coreShared/ts/components/LocalBrowseControls.tsx +++ b/ui/coreShared/ts/components/LocalBrowseControls.tsx @@ -34,22 +34,17 @@ type DiscoveryState = { totalCount: bigint | undefined } -/** Scanning the chain is an explicit, one-page-at-a-time action so public RPC users only pay for what they ask for. */ -function DiscoveryControl({ discovery, discoverLabel, disabled = false, emphasize = false, nounPlural }: { disabled?: boolean; discoverLabel: string; discovery: DiscoveryState; emphasize?: boolean; nounPlural: string }) { - const label = (() => { - if (!discovery.hasScanned) return discoverLabel - return discovery.hasMore ? favoritesCopy.discoverMore : favoritesCopy.rescan - })() +/** The first page loads automatically; users request only additional bounded pages. */ +function DiscoveryControl({ discovery, disabled = false, emphasize = false, nounPlural }: { disabled?: boolean; discovery: DiscoveryState; emphasize?: boolean; nounPlural: string }) { + if (!discovery.hasScanned) return discovery.loading ? {favoritesCopy.discovering} : undefined + if (!discovery.hasMore) return undefined return (
- {/* Progress only matters while pages remain; a finished scan is already told by the Scan again label. */} - {discovery.totalCount === undefined || !discovery.hasMore ? undefined : ( -

- {favoritesCopy.formatDiscoveredProgress(discovery.scannedItemCount.toString(), discovery.totalCount.toString(), nounPlural)} -

- )} +

+ {favoritesCopy.formatDiscoveredProgress(discovery.scannedItemCount.toString(), discovery.totalCount?.toString() ?? '', nounPlural)} +

) @@ -66,19 +61,18 @@ type LocalBrowseDirectoryState = { type LocalBrowseBarProps = { directory: LocalBrowseDirectoryState - discoverLabel: string disabled?: boolean /** Shown once a scan has run. */ freshness?: DataFreshness | undefined nounPlural: string } -export function LocalBrowseBar({ directory, discoverLabel, disabled = false, freshness, nounPlural }: LocalBrowseBarProps) { +export function LocalBrowseBar({ directory, disabled = false, freshness, nounPlural }: LocalBrowseBarProps) { return (
{directory.discovery.hasScanned && freshness !== undefined ? : undefined} - +
) } @@ -98,7 +92,6 @@ type LocalCollectionEmptyStateProps = { action?: ComponentChildren copy: { downloadedEmpty: string - downloadedEmptyDetail: string favoritesEmpty: string favoritesEmptyDetail: string favoritesEmptyWithDownloadsDetail: string @@ -127,5 +120,5 @@ export function LocalCollectionEmptyState({ action, copy, directory, registryEmp ) if (directory.discovery.hasScanned && directory.discovery.totalCount === 0n) return <>{registryEmpty} if (directory.collection === 'favorites') return - return + return } diff --git a/ui/coreShared/ts/copy/favorites.ts b/ui/coreShared/ts/copy/favorites.ts index 55590b966..ce53c6ed2 100644 --- a/ui/coreShared/ts/copy/favorites.ts +++ b/ui/coreShared/ts/copy/favorites.ts @@ -8,7 +8,6 @@ export const downloaded = 'Downloaded' export const formatCollectionTab = (label: CopyTemplateValue, count: CopyTemplateValue) => `${label} (${count})` export const collectionAriaLabel = 'Favorites collection' export const recentlySaved = 'Recently added' -export const discoverMore = 'Discover more' -export const discovering = 'Discovering…' -export const rescan = 'Discover again' +export const discoverMore = 'Show more' +export const discovering = 'Loading…' export const formatDiscoveredProgress = (discovered: CopyTemplateValue, total: CopyTemplateValue, noun: CopyTemplateValue) => `${discovered} of ${total} ${noun} checked` diff --git a/ui/coreShared/ts/hooks/useLocalBrowseDirectory.ts b/ui/coreShared/ts/hooks/useLocalBrowseDirectory.ts index 993536a90..23980d6cc 100644 --- a/ui/coreShared/ts/hooks/useLocalBrowseDirectory.ts +++ b/ui/coreShared/ts/hooks/useLocalBrowseDirectory.ts @@ -21,14 +21,13 @@ type LocalBrowseDirectoryOptions = { } /** - * Browsing runs over entities already downloaded to this browser: favorites by default, every downloaded summary on - * request. Scanning the chain is an explicit, paged action whose results join the downloaded cache. + * Browsing runs over entities already downloaded to this browser: favorites when available, or downloaded summaries otherwise. The first registry page loads automatically; additional pages join the downloaded cache on request. */ export function useLocalBrowseDirectory({ app, contextKey, externalLoading = false, kind, loadPage, pageSize, receivedPage, refreshedItems, store, toDownloadedItem }: LocalBrowseDirectoryOptions) { - const [collection, setCollection] = useState('favorites') const [searchText, setSearchText] = useState('') const favorites = useFavorites(app, kind) const downloaded = useDownloadedEntities(app, kind, store) + const [collection, setCollection] = useState(() => (favorites.entries.length > 0 ? 'favorites' : 'downloaded')) const discovery = usePagedDiscovery({ contextKey, loadPage, diff --git a/ui/coreShared/ts/hooks/usePagedDiscovery.ts b/ui/coreShared/ts/hooks/usePagedDiscovery.ts index 2ef3b4d1f..2e87dce2d 100644 --- a/ui/coreShared/ts/hooks/usePagedDiscovery.ts +++ b/ui/coreShared/ts/hooks/usePagedDiscovery.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'preact/hooks' +import { useCallback, useEffect, useRef, useState } from 'preact/hooks' export type DiscoveredPage = Readonly<{ items: readonly TItem[] @@ -31,8 +31,8 @@ function matchesDiscoveryRequest(page: DiscoveredPage, request: Di } /** - * Scans a paged on-chain registry one page per user request. Received items are handed to `onItems` (normally the - * downloaded cache) exactly once per request, so browsing and search run over the local cache instead of the page. + * Loads the first registry page automatically, then one additional page per user request. + * Each result joins the downloaded cache once, so search covers every downloaded page. */ export function usePagedDiscovery({ contextKey, loadPage, onItems, pageSize, receivedPage }: PagedDiscoveryOptions) { const [scan, setScan] = useState<{ contextKey: string; scannedPageCount: number; totalCount: bigint | undefined }>({ contextKey, scannedPageCount: 0, totalCount: undefined }) @@ -41,40 +41,51 @@ export function usePagedDiscovery({ contextKey, loadPage, onItems, pageSi const lastRequestRef = useRef(undefined) const requestNonceRef = useRef(0) const onItemsRef = useRef(onItems) + const loadPageRef = useRef(loadPage) + const receivedPageRef = useRef(receivedPage) + const pageBeforeRequestRef = useRef | undefined>(undefined) onItemsRef.current = onItems + loadPageRef.current = loadPage + receivedPageRef.current = receivedPage const currentScan = scan.contextKey === contextKey ? scan : { contextKey, scannedPageCount: 0, totalCount: undefined } - useEffect(() => { - if (scan.contextKey === contextKey) return - lastRequestRef.current = undefined - setPendingRequestKey(undefined) - setLoadFailed(false) - setScan({ contextKey, scannedPageCount: 0, totalCount: undefined }) - }, [contextKey, scan.contextKey]) - const loading = pendingRequestKey !== undefined useEffect(() => { const request = lastRequestRef.current - if (receivedPage === undefined || request?.contextKey !== contextKey || !matchesDiscoveryRequest(receivedPage, request, pageSize, loading)) return + if (receivedPage === undefined || receivedPage === pageBeforeRequestRef.current || request?.contextKey !== contextKey || !matchesDiscoveryRequest(receivedPage, request, pageSize, loading)) return lastRequestRef.current = undefined onItemsRef.current(receivedPage.items) setScan({ contextKey, scannedPageCount: receivedPage.pageIndex + 1, totalCount: receivedPage.totalCount }) }, [contextKey, loading, pageSize, receivedPage]) - const requestPage = (pageIndex: number) => { - requestNonceRef.current += 1 - const requestKey = getDiscoveryRequestKey(contextKey, pageIndex, pageSize, requestNonceRef.current) - lastRequestRef.current = { contextKey, key: requestKey, pageIndex } - setLoadFailed(false) - setPendingRequestKey(requestKey) - void Promise.resolve(loadPage(pageIndex, requestKey)) - .catch(() => { - if (lastRequestRef.current?.key === requestKey) setLoadFailed(true) - }) - .finally(() => { - setPendingRequestKey(current => (current === requestKey ? undefined : current)) - }) - } + const requestPage = useCallback( + (pageIndex: number) => { + requestNonceRef.current += 1 + const requestKey = getDiscoveryRequestKey(contextKey, pageIndex, pageSize, requestNonceRef.current) + lastRequestRef.current = { contextKey, key: requestKey, pageIndex } + pageBeforeRequestRef.current = receivedPageRef.current + setLoadFailed(false) + setPendingRequestKey(requestKey) + const load = loadPageRef.current + void Promise.resolve() + .then(() => load(pageIndex, requestKey)) + .catch(() => { + if (lastRequestRef.current?.key === requestKey) setLoadFailed(true) + }) + .finally(() => { + setPendingRequestKey(current => (current === requestKey ? undefined : current)) + }) + }, + [contextKey, pageSize], + ) + + useEffect(() => { + setScan({ contextKey, scannedPageCount: 0, totalCount: undefined }) + requestPage(0) + return () => { + lastRequestRef.current = undefined + } + }, [contextKey, requestPage]) const scannedItemCount = (() => { const scanned = BigInt(currentScan.scannedPageCount * pageSize) diff --git a/ui/zoltar/ts/tests/features/questions/questionsView.test.tsx b/ui/zoltar/ts/tests/features/questions/questionsView.test.tsx index 093112bef..51b8df32d 100644 --- a/ui/zoltar/ts/tests/features/questions/questionsView.test.tsx +++ b/ui/zoltar/ts/tests/features/questions/questionsView.test.tsx @@ -5,6 +5,7 @@ import { readFavoriteEntries, resetLocalEntityStoreForTesting, setEntityFavorite import { installDomTestLifecycle } from '@zoltar/ui-core-shared/tests/testUtils/domTestLifecycle.js' import { fireEvent, within } from '@zoltar/ui-core-shared/tests/testUtils/queries.js' import { renderIntoDocument } from '@zoltar/ui-core-shared/tests/testUtils/renderIntoDocument.js' +import { createDeferred } from '@zoltar/ui-core-shared/tests/testUtils/deferred.js' import type { MarketDetails, MarketDetailsPage } from '@zoltar/ui-core-shared/types/contracts.js' import { QuestionsView } from '@zoltar/ui-zoltar-shared/features/zoltarSurface/components/QuestionsView.js' import { questionDownloadStore } from '@zoltar/ui-zoltar-shared/lib/questionBrowse.js' @@ -87,7 +88,54 @@ describe('QuestionsView', () => { }, }) - test('renders favorite questions from the local cache without cross-application actions or a chain scan', async () => { + test('loads the first registry page on entry without a discovery click', async () => { + const loadPage = mock(async () => undefined) + const renderedComponent = await renderIntoDocument(view({ loadPage })) + cleanupRenderedComponent = renderedComponent.cleanup + + expect(loadPage).toHaveBeenCalledTimes(1) + expect(loadPage).toHaveBeenCalledWith(0, 10) + await act(async () => { + render(view({ loadPage, zoltarQuestionPage: { pageIndex: 0, pageSize: 10, questionCount: 1n, questions: [question] } }), renderedComponent.container) + await Promise.resolve() + await Promise.resolve() + }) + expect(getRenderedQuestionTitles()).toEqual([question.title]) + expect(loadPage).toHaveBeenCalledTimes(1) + }) + + test('keeps cached questions visible while the initial page loads', async () => { + seedQuestions([question]) + const request = createDeferred() + const loadPage = mock(() => request.promise) + const renderedComponent = await renderIntoDocument(view({ loadPage })) + cleanupRenderedComponent = renderedComponent.cleanup + + expect(getRenderedQuestionTitles()).toEqual([question.title]) + expect(within(document.body).getByRole('status').textContent).toContain('Loading') + expect(loadPage).toHaveBeenCalledTimes(1) + await act(async () => request.resolve(undefined)) + }) + + test('ignores an old request failure after switching contexts', async () => { + const oldRequest = createDeferred() + const oldLoadPage = mock(() => oldRequest.promise) + const renderedComponent = await renderIntoDocument(view({ loadPage: oldLoadPage })) + cleanupRenderedComponent = renderedComponent.cleanup + const newLoadPage = mock(async () => undefined) + await act(async () => { + render(view({ loadPage: newLoadPage, requestContextKey: 1 }), renderedComponent.container) + await Promise.resolve() + }) + expect(newLoadPage).toHaveBeenCalledTimes(1) + await act(async () => { + oldRequest.reject(new Error('Old network failed')) + await Promise.resolve() + }) + expect(document.body.textContent).not.toContain('Questions could not be loaded.') + }) + + test('renders favorite questions from the local cache while refreshing without cross-application actions', async () => { seedQuestions([question]) const loadPage = mock(async () => undefined) const activeViews: string[] = [] @@ -113,18 +161,17 @@ describe('QuestionsView', () => { }) expect(selectedQuestionIds).toEqual([question.questionId]) expect(activeViews).toEqual(['fork']) - expect(loadPage).not.toHaveBeenCalled() + expect(loadPage).toHaveBeenCalledTimes(1) }) - test('scans the registry on request and favorites a question when its details are opened', async () => { + test('loads the registry automatically and favorites a question when its details are opened', async () => { const loadPage = mock(async () => undefined) const renderedComponent = await renderIntoDocument(view({ loadPage })) cleanupRenderedComponent = renderedComponent.cleanup const documentQueries = within(document.body) - expect(documentQueries.getByText('No favorite questions yet')).not.toBeNull() + expect(loadPage).toHaveBeenCalledWith(0, 10) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() }) expect(loadPage).toHaveBeenCalledWith(0, 10) @@ -146,7 +193,7 @@ describe('QuestionsView', () => { expect(documentQueries.getByRole('button', { name: 'Favorites (1)' })).not.toBeNull() }) - test('records refreshed question pages and shows their age only after a scan', async () => { + test('records refreshed question pages and shows their age after its automatic initial read', async () => { const loadPage = mock(async () => undefined) const freshness = { refreshing: false, updatedAt: Date.now() - 15_000 } const page = (title: string): MarketDetailsPage => ({ pageIndex: 0, pageSize: 10, questionCount: 1n, questions: [{ ...createQuestion(1), title }] }) @@ -158,7 +205,6 @@ describe('QuestionsView', () => { expect(documentQueries.getByRole('button', { name: 'Downloaded (0)' })).not.toBeNull() await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() }) await act(async () => { @@ -211,7 +257,6 @@ describe('QuestionsView', () => { cleanupRenderedComponent = renderedComponent.cleanup const documentQueries = within(document.body) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() await Promise.resolve() }) @@ -231,7 +276,6 @@ describe('QuestionsView', () => { cleanupRenderedComponent = renderedComponent.cleanup const documentQueries = within(document.body) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() }) await act(async () => { @@ -275,7 +319,6 @@ describe('QuestionsView', () => { cleanupRenderedComponent = renderedComponent.cleanup const documentQueries = within(document.body) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() }) await act(async () => { @@ -283,7 +326,7 @@ describe('QuestionsView', () => { await Promise.resolve() }) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover more' })) + fireEvent.click(documentQueries.getByRole('button', { name: 'Show more' })) await Promise.resolve() }) expect(loadPage).toHaveBeenLastCalledWith(1, 10) @@ -293,7 +336,6 @@ describe('QuestionsView', () => { await Promise.resolve() }) await act(async () => { - fireEvent.click(documentQueries.getByRole('button', { name: 'Discover questions' })) await Promise.resolve() }) expect(loadPage).toHaveBeenLastCalledWith(0, 10) diff --git a/ui/zoltarShared/ts/copy/market.ts b/ui/zoltarShared/ts/copy/market.ts index 29a66911c..2bc6edde7 100644 --- a/ui/zoltarShared/ts/copy/market.ts +++ b/ui/zoltarShared/ts/copy/market.ts @@ -13,14 +13,12 @@ export const questionRegistryDescription = 'Find reusable questions in the globa export const questionRegistryDescriptionWithoutUniverse = 'Find reusable questions in the global registry and inspect their resolution terms.' export const createQuestionDescription = 'Define a reusable onchain question and review its outcomes and timing before submitting it.' export const searchDownloadedQuestions = 'Search downloaded questions' -export const discoverQuestions = 'Discover questions' export const questionsNoun = 'questions' export const noFavoriteQuestions = 'No favorite questions yet' -export const noFavoriteQuestionsDetail = 'Discover questions from the registry. Questions you open or use for a fork are added here.' +export const noFavoriteQuestionsDetail = 'Questions you open or use for a fork are added here.' export const noFavoriteQuestionsWithDownloadsDetail = 'Star a downloaded question, or open its details, to keep it here.' export const showDownloadedQuestions = 'Show downloaded questions' export const noDownloadedQuestions = 'No downloaded questions yet' -export const noDownloadedQuestionsDetail = 'Discover questions to download them to this browser.' export const questionSearchPlaceholder = 'Question ID, title, or description' export const questionSearchNoMatches = 'No downloaded questions match the current search.' export const answerUnitPlaceholder = 'USD' diff --git a/ui/zoltarShared/ts/features/zoltarSurface/components/QuestionsView.tsx b/ui/zoltarShared/ts/features/zoltarSurface/components/QuestionsView.tsx index 33e0c3aa4..f0b0371fc 100644 --- a/ui/zoltarShared/ts/features/zoltarSurface/components/QuestionsView.tsx +++ b/ui/zoltarShared/ts/features/zoltarSurface/components/QuestionsView.tsx @@ -34,7 +34,7 @@ type QuestionsViewProps = { requestContextKey: number } -/** Questions are browsed from this browser's favorites and downloaded summaries; the registry is scanned one page at a time on request. */ +/** The first registry page loads on entry; favorites and downloaded summaries remain searchable while it refreshes. */ export function QuestionsView({ canFork, hasForked, loadingZoltarQuestions, onActiveViewChange, onLoadZoltarQuestionPage, onZoltarForkQuestionIdChange, requestContextKey, zoltarQuestionPage, zoltarQuestionsError, zoltarQuestionsFreshness }: QuestionsViewProps) { const receivedPage = useMemo((): DiscoveredPage | undefined => { if (zoltarQuestionPage === undefined) return undefined @@ -57,12 +57,13 @@ export function QuestionsView({ canFork, hasForked, loadingZoltarQuestions, onAc const questions = entries.map(entry => entry.data).filter(question => questionMatchesSearch(question, directory.normalizedSearchText)) const loadError = zoltarQuestionsError ?? (discovery.loadFailed ? marketCopy.questionPageLoadError : undefined) const content = (() => { + if (entries.length === 0 && discovery.loading) return undefined + if (entries.length === 0 && loadError !== undefined) return undefined if (entries.length === 0) return ( - + {content}