OpenOracle Integration

Placeholder uses OpenOracle for one narrow job: getting a fresh REP/ETH price when a pool needs to check solvency. It does not use OpenOracle to decide market truth; truth still comes from local escalation and, if necessary, Zoltar forks.

The core lifecycle is simple. A user stages a liquidation, withdrawal, or allowance update with the pool's coordinator. The coordinator requests OpenOracle when needed, and after settlement it either executes the restricted pool action with that fresh price or leaves a recovery path if execution conditions no longer hold.

A stale or missing price sends solvency-sensitive operations into staging because Placeholder would rather delay a withdrawal, liquidation, or allowance change than let an old REP/ETH quote distort pool solvency checks.

The OpenOracle report instance uses REP as token1 and WETH as token2. The coordinator converts the settled amounts into a REP-per-ETH price because WETH is the ETH-denominated leg of the report.

The contract and research context lives in: OpenOracle documentation, the OpenOracle paper, the local OpenOracle contract, the OpenOraclePriceCoordinator integration, and the Placeholder whitepaper's REP/ETH Price Oracle section. Current oracle research lives in the OpenOracle Technical Details sidebar, especially Attack Vectors and Attack Vectors (Inclusion).

OpenOracle Role

The generic oracle lifecycle comes first. Placeholder's coordinator is only a consumer of the report that OpenOracle settles.

OpenOracle creates report instances for a token pair. Reporters submit token amounts, later reporters can dispute by posting a larger report, and a report can settle after its timing window. When a callback contract is configured, settlement calls that contract with the settled amounts.

In this repository the pair is REP as token1 and WETH as token2. The coordinator converts the callback amounts into the following REP per ETH price:

lastPrice = amount1 1018 amount2

REP/ETH PriceThe settled REP amount is scaled by the fixed price precision and divided by the settled WETH amount.

After the coordinator accepts a settlement, that accepted REP/WETH report becomes a REP/ETH coordinator price. The price is reusable only while it remains inside the freshness window; operation volume is not metered by the accepted report.

Four coordinator terms drive the rest of the integration behavior: staged operation, fresh price, liquidation threshold, and report liquidity.

A staged operation is a liquidation, REP withdrawal, or allowance update queued behind the coordinator until it can use a fresh price, meaning a settled coordinator price still inside PRICE_VALID_FOR_SECONDS, currently a five-minute cache window.

For liquidations, the relevant boundary is the liquidation threshold. A staged liquidation can execute only when the current REP/ETH price is strictly above that threshold and at least the configured liquidation distance beyond it, with that extra margin currently set by minLiquidationPriceDistanceBps.

OpenOracle disputes scale with report liquidity, the REP/WETH report size posted into the oracle. Larger report liquidity gives honest reporters more economic weight to dispute a bad price. The coordinator sizes the initial report from dispute profitability assumptions, not from the amount of outside value protected by the price.

Placeholder Integration

In Placeholder, every pool gets its own coordinator. That keeps pending operations, freshness windows, and callback state local to one pool instead of sharing one global queue across the protocol.

OpenOraclePriceCoordinator is deployed with an immutable OpenOracle address. A security pool stages liquidation, REP-withdrawal, and security-bond-allowance operations through the coordinator when a fresh REP/ETH price is needed.

Deployment is per pool. SecurityPoolFactory asks PriceOracleManagerAndOperatorQueuerFactory for a fresh coordinator for each origin or child security pool, wiring it to the shared OpenOracle, shared WETH, and that universe's REP token. SecurityPoolDeployer passes the coordinator into the pool, and the factory then calls setSecurityPool exactly once so only that pool can seed and execute through the coordinator. Child pools inherit the parent's last price as a starting value, but freshness is still controlled by the coordinator's settlement timestamp and validity window.

The factory contract still uses its older internal name, but it is the active deployment path for OpenOraclePriceCoordinator instances.

OpenOracle integration flow Placeholder queues solvency-sensitive operations behind a bounded OpenOracle REP/ETH report and executes them only with a fresh accepted price. User Operation liquidate, withdraw REP, allowance Coordinator price cache, staging guards OpenOracle reporter posts disputer may replace settler finalizes Settle callback Execution Guardrails fresh price, pending report, and local safety checks Expired operations, stale liquidations, zero-effect withdrawals, and too-close liquidations are consumed.

Integration FlowThe coordinator is the trust boundary between Placeholder operations and OpenOracle reports. It applies guardrails before request and staging, then again after callback before execution.

If the cached price is valid, the coordinator attempts immediate execution after staging the operation record. Liquidation-specific gates, snapshot staleness, zero-effect withdrawals, or downstream pool checks can still consume the operation as a failed staged operation. Otherwise the coordinator can create one OpenOracle report and attach up to four staged operations to the settlement callback. Additional staged operations remain active but outside the auto-executed callback batch; if the fresh price remains valid and they have not expired, they require a later manual executeStagedOperation call.

Staged operation inputs are constrained before any oracle report is requested. Liquidation and withdrawal amounts must be non-zero, allowance updates may set zero, validForSeconds must be positive and no more than five minutes, liquidation must target a different vault, non-liquidation operations must target the caller's own vault, and staging is disabled after the security pool's local escalation has already resolved. Same-vault liquidation is rejected with Caller bad before the coordinator requests or uses an oracle report.

Report funding is caller supplied. The coordinator computes requestPriceEthCost, the caller-funded request bounty, from the current base fee, the callback gas limit, and the gas the coordinator expects to spend inside openOracleReportPrice:

requestPriceEthCost = block.basefee 4 ( callbackGasLimit + gasConsumedOpenOracleReportPrice ) + 101

Oracle Request CostcallbackGasLimit is the gas reserved for the settlement callback, gasConsumedOpenOracleReportPrice is the coordinator's own report-price callback work, and the small 101 offset keeps the forwarded bounty strictly above the computed gas product so the OpenOracle-funded reward path has a positive buffer instead of landing exactly on the boundary.

If a cached price is usable, the staged operation pays no oracle request cost and unused ETH is refunded. If a new report is needed, only the first pending settlement slot retains the request cost; requestPrice forwards exactly that bounty to OpenOracle and refunds any excess. That call creates an OpenOracle report instance; external reporters still submit the initial REP/WETH amounts, disputes can replace those amounts, and settlement returns the final amounts through the callback.

Once a report is pending, only the original pendingReportSponsor can queue more staged operations against that in-flight settlement. Those follow-up queues pay no additional ETH join fee, and other callers must wait for settlement before staging their own operations.

The money flow is easiest to follow if each role is separated. The triggering caller pays the ETH request bounty, the initial reporter posts the REP/WETH report amounts, and the eventual settler receives the settler reward. Those roles can be different accounts or the same account.

Worked example using a market snapshot taken at 2026-07-09 09:49:35 UTC: at that moment Ethereum base fee was 69,594,403 wei per gas (0.069594403 gwei), ETH traded at $1,750.34, and REP traded at $0.792188 or 0.00045231 ETH per REP. The USD quotes and the ETH-per-REP quote are independently rounded snapshot values, so reconstructing one from the other may differ by a few basis points. With the coordinator defaults used in this documentation revision, gasConsumedOpenOracleReportPrice = 100,000, gasConsumedSettlement = 1,000,000, and MAX_PENDING_SETTLEMENT_OPERATIONS = 4, the callback gas limit is:

callbackGasLimit = 1,000,000 4 = 4,000,000

Worked Callback Gas LimitThe current coordinator parameters reserve four settlement-operation gas budgets inside one callback.

requestPriceEthCost = 69,594,403 4 ( 4,000,000 + 100,000 ) + 101 = 1,141,348,209,200,101  wei

Worked Trigger CostThe caller who opens a fresh price request sends 0.001141348209200101 ETH, about $2.00 at that snapshot's ETH/USD price. This bounty is separate from the normal gas burned by the caller's own transaction.

The initial reporter then posts the configured exactToken1Report, 259.332023575638507216 REP, plus the matching WETH side at the chosen report price. Using the same market snapshot:

amount2 259.332023575638507216 0.00045231 0.11729846758349706  ETH

Worked Initial Report StakeThe reporter posts about 259.3320 REP and 0.11729847 WETH, roughly $205 of each token side at that snapshot. The displayed WETH decimal is an explanatory approximation from the rounded REP/ETH quote rather than an exact atomic-unit contract input.

If no dispute replaces the report, settlement returns the full REP and WETH amounts to the current reporter. The ETH bounty is split between the initial reporter reward and the settler reward:

settlerReward = 69,594,403 2 100,000 = 13,918,880,600,000  wei reporterReward = 1,141,348,209,200,101 - 13,918,880,600,000 = 1,127,429,328,600,101  wei

Worked No-Dispute PayoutIf the same account triggers the request, submits the initial report, and settles it undisputed, that account gets back the full REP stake, the full WETH stake, and the entire ETH bounty in two pieces: 0.001127429328600101 ETH as reporter reward and 0.0000139188806 ETH as settler reward. If different accounts fill those roles, the REP/WETH principal goes to the current reporter, the larger ETH reward goes to the initial reporter, and the smaller ETH reward goes to the settler.

Escalation-game REP deposits are the exception to the staged callback path. When the pool has active security-bond allowance, depositToEscalationGame requires a fresh coordinator price and reverts if it is stale. After previewing the accepted REP deposit, the pool uses lastPrice for the post-transfer vault and pool coverage checks instead of queueing the deposit behind a report.

Security Guardrails

Placeholder uses the oracle to preserve solvency accounting around ETH obligations backed by REP. The guarantee is conditional: operations that can change REP backing or security-bond exposure must use a fresh, economically contestable REP/ETH price and must pass local coordinator checks before they can affect the pool.

The initial report size is computed from the minimum dispute profitability target. The numerator estimates the REP value of one dispute's gas cost with a profit buffer. The denominator is the price-error room left after OpenOracle reporter/protocol fees and expected adverse REP/ETH movement during settlement. If that denominator is non-positive, the parameter set is unsafe because the target wrong price cannot be disputed profitably under the stated assumptions.

exactToken1Report = ceil ( requiredDisputerProfitBuffer gasUnitsForOneDispute assumedGasPriceInEthPerGas repPerEthPrice targetPriceErrorForDispute - ( openOracleProtocolFeeFraction + openOracleReporterFeeFraction ) 1 + targetPriceErrorForDispute - disputeReportSizeMultiplier expectedRepEthPriceMoveDuringSettlement )

Initial Report SizeThe coordinator's configured REP-side report amount is sized from dispute profitability assumptions, not from protected external value.

The canonical deployment calculation lives in shared/ts/oracleInitialReport.ts, exported as @zoltar/shared/oracleInitialReport. The UI deployment helper and simulator deployment helper both consume that shared value. With the current inputs, the denominator is positive and the configured output is 259332023575638507216 atomic REP, or 259.332023575638507216 REP.

Formula input Current value Canonical shared source
requiredDisputerProfitBuffer 2x ORACLE_REQUIRED_DISPUTER_PROFIT_BUFFER
gasUnitsForOneDispute 300,000 gas ORACLE_GAS_UNITS_FOR_ONE_DISPUTE
assumedGasPriceInEthPerGas 30 gwei ORACLE_ASSUMED_GAS_PRICE_WEI_PER_GAS
repPerEthPrice 1,000 REP / ETH ORACLE_ASSUMED_REP_PER_ETH_PRICE
targetPriceErrorForDispute 10% ORACLE_TARGET_PRICE_ERROR_FOR_DISPUTE
openOracleProtocolFeeFraction 1% ORACLE_PROTOCOL_FEE / ORACLE_PERCENTAGE_PRECISION
openOracleReporterFeeFraction 0.1% ORACLE_FEE_PERCENTAGE / ORACLE_PERCENTAGE_PRECISION
disputeReportSizeMultiplier 1.15x ORACLE_MULTIPLIER / 100
expectedRepEthPriceMoveDuringSettlement 1% ORACLE_EXPECTED_REP_ETH_PRICE_MOVE_DURING_SETTLEMENT

If the denominator is zero or negative, those assumptions do not leave enough price-error room for a profitable dispute, so deployment must choose a larger target error, lower fee/move assumptions, or a different initial report size model.

The helpers evaluate the displayed equation with ORACLE_FORMULA_PRECISION = 1e18 fixed-point integers. openOracleProtocolFeeFraction, openOracleReporterFeeFraction, disputeReportSizeMultiplier, disputeProfitFraction, and priceMoveFraction use integer division that floors at that precision. The final exactToken1Report then uses ceiling division by ORACLE_FORMULA_PRECISION * denominator. Those helper rounding rules produce the current atomic REP value above.

Initial report estimator

The estimator stresses the formula inputs. It treats the displayed equation as a continuous model so the sensitivity curves are easy to read; deployment still uses the fixed-point rounding rules described above. The REP/ETH movement input is an adverse movement buffer during settlement, not an average signed drift.

Estimated initial report259.332024 REP
Dispute gas cost0.0090 ETH
Buffered gas cost18.00 REP
Effective denominator6.9409%
Fee drag1.10%
Adverse move penalty1.15%
Minimum viable target error2.28%
Max viable adverse move7.04%
Safety statepositive denominator
Report size vs. target error unsafe below 2.28% max min current 1% 50% Report size vs. gas price max min current 1 gwei 200 gwei Report size vs. expected adverse REP/ETH move unsafe above 7.04% max min current 0% 10%

The target-error and adverse-move curves can go vertical near the unsafe denominator boundary. Shaded regions show parameter values where a wrong report at the target error no longer leaves enough room to pay fees, absorb adverse REP/ETH movement, and still make a dispute profitable.

Once a REP/ETH price is fresh, the coordinator relies on local operation guards: withdrawals must have an effect, liquidations must pass their queue-time snapshot checks and liquidation-distance check, and allowance updates execute against the current vault state.

Callback Rejection and Recovery

OpenOracle settles with a low-level callback and emits whether that callback succeeded. It does not automatically undo settlement when the callback returns false. 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 OpenOracle report can still be settled while the coordinator remains pending. If the settlement transaction cannot leave enough gas headroom after attempting the callback, OpenOracle reverts settlement with InvalidGasLimit instead; in that case the report is not settled yet and coordinator recovery is not available.

Coordinator-level price rejections are separate from low-level callback failures. After a callback successfully enters the coordinator, a settlement with base fee above the request-time cap, zero amounts, or a computed zero price clears the pending id, emits PriceReportRejected, and does not update the price cache or replay pending operations. Those pending settlement operations remain queued for a later valid price report, but a later call to stage another operation will not automatically fund a retry while that pending settlement list is still non-empty; an operator or user may need to call requestPrice directly. When OpenOracle has already settled but the coordinator is still pending because the low-level callback did not complete, anyone can call recoverSettledPendingReport. Recovery clears the pending report, resets the settlement base-fee cap, and consumes only pendingOperationSlotId without treating it as a successful price update. Queue bookkeeping can still leave other staged operations active; those operations need a later valid price path, for example a direct requestPrice() call followed by successful settlement.

Attack Model and Defenses

The security question is not whether OpenOracle can discover market truth. It is whether an attacker can profit by forcing Placeholder to use a bad REP/ETH price long enough for a solvency-sensitive operation to execute. Honest reporters can dispute bad reports, so the model compares the attacker's outside payoff with the liquidity, delay, and censorship cost needed to keep an honest correction out.

OpenOracle's inclusion analysis models an attacker who posts a wrong price and pays for censorship until the report can settle. For linear payoffs the settle payoff scales with price error, but Placeholder's most relevant liquidation payoff is binary: the attacker wins a fixed payoff only if the manipulated REP/ETH price is strictly above the liquidation threshold and satisfies the configured liquidation distance check. OpenOracle's inclusion analysis notes that binary payoffs therefore replace the linear settle payoff with externalPayoff, while keeping the same censorship-spend term.

The minimal attack story is: an attacker posts a manipulated REP/ETH report, an honest reporter would normally dispute it, and the attacker must keep that honest dispute or settlement correction out until the bad report can settle. The payoff is binary because the liquidation either becomes executable or it does not. The cost side scales with oracleReportLiquidity, the report's ETH value liquidity after converting the REP-side report amount at the honest REP/ETH price; censorshipRate, the modeled per-step pressure needed to keep honest activity out; and censorshipDuration, how long the attacker must maintain that pressure.

In the equations below, price errors are fractions of the honest price, externalPayoff is the attacker's outside ETH-denominated payoff, and oracleLiquidityRatio compares report liquidity with that payoff. The bound is useful when the denominator is large enough that delaying honest correction costs more than the liquidation can pay.

The first boundary is how far the manipulated price must move before the liquidation can execute. The distance guard discounts the honest price, then the execution threshold and reported price error are measured against that honest baseline. The formulas in this attack model are continuous approximations for reasoning about payoff and censorship cost; the contract guard below them shows the integer check that actually gates staged liquidation execution.

liquidationDistanceFraction = minLiquidationPriceDistanceBpsBPS_DENOMINATOR discountedHonestPrice = honestPrice(1-liquidationDistanceFraction) executionErrorThreshold = max(0,liquidationThresholdPricediscountedHonestPrice-1) manipulatedPriceError = max(0,manipulatedPrice-honestPricehonestPrice)

Execution Error ThresholdThe manipulated price only creates liquidation payoff when its fractional error meets the guarded liquidation threshold.

thresholdPrice = floor(vaultRepPRICE_PRECISIONsnapshotTargetAllowancesecurityMultiplier) currentPrice > thresholdPrice distanceBps = floor((currentPrice-thresholdPrice)BPS_DENOMINATORcurrentPrice) distanceBps minLiquidationPriceDistanceBps

Contract Liquidation GuardThe coordinator computes the floored threshold and distance checks before calling the pool. SecurityPool then rechecks the scaled liquidation-threshold inequality and rejects chunks that fail target, caller, or floor checks. Equality passes only at the distance check; currentPrice must still be strictly above thresholdPrice.

The attack model separates attacker payoff from delay cost. The payoff is binary: only a price strictly above the liquidation threshold and far enough past the guarded distance unlocks externalPayoff; everything else unlocks nothing. The censorship cost grows with duration, the dispute barrier, and the report liquidity honest reporters can use.

liquidationExecutable = manipulatedPrice>liquidationThresholdPricemanipulatedPriceErrorexecutionErrorThreshold attackerProfit = { externalPayoff , liquidationExecutable 0 , otherwise censorshipRate = max(0,manipulatedPriceError-honestDisputeBarrierFraction) censorshipCost = censorshipDurationcensorshipRateoracleReportLiquidity

Binary Payoff and Censorship CostHere externalPayoff is the attacker's outside ETH-denominated payoff, and oracleReportLiquidity is the report's ETH value liquidity after converting the REP-side report amount at the honest REP/ETH price.

The final bound is how long censorship would need to remain cheap for the attack to be attractive. The safety duration shrinks as the censorship rate and liquidity ratio grow.

oracleLiquidityRatio = oracleReportLiquidityexternalPayoff safeCensorshipDuration = targetGriefRatio+1censorshipRateoracleLiquidityRatio

Safe Censorship DurationThe bound is strongest when report liquidity is large relative to the payoff and each additional unit of price error is costly to keep undisputed.

Adjust a binary censorship example

The liquidation distance, manipulated price, report liquidity, and payoff determine the attacker's payoff and delay cost.

Price error needed vs. supplied threshold 12.22% error 13.00% payoff 1000.00 ETH
  • Execution error threshold: 12.22%
  • Manipulated price error: 13.00%
  • Liquidation executable: yes
  • Attacker payoff: 1000.00 ETH
  • Censorship cost: 11520.00 ETH
  • Oracle liquidity ratio: 4.00
  • Safe censorship duration (steps): 4.17

Placeholder defends this model by making wrong reports profitable to dispute at the target error, forcing liquidations to be meaningfully past threshold, and rejecting bad settlement environments. This assumes honest arbitragers are monitoring the REP/ETH price and their dispute or arbitrage transactions can be included; the report size is not scaled by the outside payoff protected by the price.

The dynamic-programming section of OpenOracle's inclusion analysis is a template for the inclusion tradeoff, not a drop-in Placeholder proof. For a simplified binary censorship bound, replace the linear price-error payoff with a thresholded payoff that only pays after the manipulated report is strictly above the liquidation threshold and far enough past the guarded distance. A full binary-delay model also needs state for distance to threshold, price evolution, and continuation value. Locally, OpenOracle escalation is also capped: once escalationHalt is reached, disputes can continue, but the required token1 amount advances by 1 atomic token1 unit instead of multiplying by reportEscalationMultiplier.

liquidationExecutable = manipulatedPrice>liquidationThresholdPricemanipulatedPriceErrorexecutionErrorThreshold binarySettlePayoff(manipulatedPriceError) = { externalPayoff , liquidationExecutable 0 , otherwise censorshipBribeAtStep(manipulatedPriceError) = max(0,manipulatedPriceError-honestDisputeBarrierFraction)reportSizeAtSteprepPerEthPrice nextReportSize = min(escalationHalt,reportEscalationMultiplierreportSizeAtStep) before halt nextReportSize = reportSizeAtStep+1 atomic token1 unit after halt

Binary Dynamic Programming TerminalThe simplified terminal payoff pays only after the reported error crosses the threshold distance. The censorship bribe still scales with report size, but local report-size growth is capped by escalationHalt before continuing by one atomic unit per step.

Adjust report escalation and censorship bribe growth

OpenOracle disputes multiply the required report size until the halt is reached. After that, the next required amount advances by +1 atomic token1 unit, which is 0.000000000000000001 REP for REP. The REP-scale visual therefore remains effectively pinned at the halt while the exact amount and per-step bribe continue to advance by one wei of REP. The bribe output converts REP-side report size to ETH value through the selected REP/ETH price.

Report size by step halt 2593.32 REP latest bribe 2.59 ETH value
Final report size2593.320000000000000002 REP
Growth modehalt reached; +1 wei of REP per step
Latest per-step bribe2.59 ETH value
Cumulative bribe proxy24.66 ETH value

OpenOracle Parameters Used

The integration depends on the OpenOracle fields below. The canonical exhaustive current-value table remains the Placeholder whitepaper's Current Parameters section.

Parameter Current integration value Use in Placeholder
token1Address / token2Address REP / WETH Defines the REP/ETH price pair used for security-pool solvency checks.
exactToken1Report Computed by the initial report-size formula: 259.332023575638507216 REP (259332023575638507216 atomic REP units) Sets the initial report size used for dispute profitability.
escalationHalt 2,593.32023575638507216 REP (2593320235756385072160 atomic REP units) Stops multiplicative report-size escalation at 10x; later disputes add one atomic REP unit at a time.
settlerReward block.basefee2gasConsumedOpenOracleReportPrice Pays the account that settles the report and triggers the callback.
settlementTime 480 seconds (8 minutes) Sets the timestamp-based report settlement delay. The 40 * 12 derivation assumes twelve-second blocks, but the configured OpenOracle timeType uses seconds. Staged operations expire after this delay plus their operation-specific validity window.
disputeDelay 0 Allows disputes immediately after each report; the dispute opportunity still lasts until the settlement delay elapses.
callbackGasLimit gasConsumedSettlement4 Sets the callback gas limit for up to MAX_PENDING_SETTLEMENT_OPERATIONS staged operations; settlement still needs enough surrounding gas to satisfy OpenOracle's callback headroom check.
feePercentage / protocolFee 10000 / 100000 Configures OpenOracle reporter and protocol fee accounting, and creates the fee boundary behind the honestDisputeBarrierFraction dispute barrier in the attack model.
protocolFeeRecipient 0x000000000000000000000000000000000000dEaD Receives OpenOracle protocol fees for the coordinator-created report instance.
multiplier 115 Requires each dispute report to increase the REP side to 1.15x the prior report until halt.
timeType / trackDisputes true / true Uses timestamps and keeps dispute history visible for report inspection.
callbackContract OpenOraclePriceCoordinator Routes settled amounts back into Placeholder's price cache and staged-operation executor.