Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/mainnet-deployment-addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{
"id": "deploymentStatusOracle",
"label": "Deployment Status Oracle",
"address": "0x4e87d565E3ceF63cb61EeF32FBfe26494521cEFE"
"address": "0xCad079A327DE2a40FDfE391f7A6e33A101fb4406"
},
{
"id": "multicall3",
Expand Down Expand Up @@ -53,34 +53,34 @@
{
"id": "shareTokenFactory",
"label": "ShareTokenFactory",
"address": "0x4F29b2459140e40ed4C582Cb13D1ab54e9412D4A"
"address": "0x347eca006F009575C3d855D9708C1B0d03c667AE"
},
{
"id": "priceOracleManagerAndOperatorQueuerFactory",
"label": "OpenOracle Price Coordinator Factory",
"address": "0x73DEa9f9394838d05e3dE0743d154a024fbb9B99"
"address": "0x49a261187dC63FBf6893Dd810281990d83e04CB6"
},
{
"id": "securityPoolForker",
"label": "Security Pool Forker",
"address": "0xAab444A64E2866a5Cd2642B6666cB523D3FEA807"
"address": "0x3AaAa3Bb6cB143974Ab04476665a9D1cC77b648E"
},
{
"id": "escalationGameFactory",
"label": "Escalation Game Factory",
"address": "0x7C372b65ef83BAca130CF336d8007C7875eFC75e"
"address": "0x26A53cB8337C6C19B99BEE76fEE807f6A8B14451"
},
{
"id": "securityPoolFactory",
"label": "Security Pool Factory",
"address": "0xE5e583B470FD93F603ed279fd7d5C75eeaC446fA"
"address": "0x9b8923195555C3560CFdA0d93D881E15A8620148"
}
],
"derivedContracts": [
{
"id": "escalationGameProofVerifier",
"label": "Escalation Game Proof Verifier",
"address": "0xBbf8C7c730Ea881C39eEF426eFacaC3289a39C1E"
"address": "0x32f0b7cEF63043d0Ba95923bA92975C254A022e7"
}
]
}
53 changes: 30 additions & 23 deletions docs/openOracleIntegration.html
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ <h2>Placeholder Integration</h2>
OpenOracle
</text>
<text class="svg-small" x="678" y="119" text-anchor="middle">
reporter posts
sponsor posts initial report
</text>
<text class="svg-small" x="678" y="135" text-anchor="middle">
disputer may replace
Expand Down Expand Up @@ -386,25 +386,30 @@ <h2>Placeholder Integration</h2>
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;
<code>requestPrice</code> 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.
<code>requestPrice(amount2)</code> forwards exactly that bounty to
OpenOracle and refunds any excess. That call also submits the initial
REP/WETH report inside the same transaction, so the refresh sponsor
funds the ETH bounty plus the initial OpenOracle position up front.
Disputes can still replace those amounts, and settlement returns the
final accepted amounts through the callback.
</p>
<p>
The coordinator refuses <code>requestPrice(amount2)</code> while its
cached price is still fresh, so callers cannot open a redundant
pending report on top of a usable price. Once the cached price has
gone stale and a new report is pending, only the original
<code>pendingReportSponsor</code> 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.
</p>
<p>
Once a report is pending, only the original
<code>pendingReportSponsor</code> 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.
</p>
<p>
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.
triggering caller pays the ETH request bounty, posts the initial
REP/WETH report amounts, and becomes the queue owner for that stale
refresh window. The eventual settler still receives the settler
reward, and disputes can replace the initial report before
settlement.
</p>
<p>
Worked example using a market snapshot taken at
Expand Down Expand Up @@ -478,7 +483,7 @@ <h2>Placeholder Integration</h2>
</p>
</figure>
<p>
The initial reporter then posts the configured
The refresh sponsor's coordinator call atomically posts the configured
<code>exactToken1Report</code>,
<code>259.332023575638507216 REP</code>, plus the matching WETH side
at the chosen report price. Using the same market snapshot:
Expand All @@ -502,7 +507,7 @@ <h2>Placeholder Integration</h2>
</math>
<p class="equation-caption">
<span class="equation-label">Worked Initial Report Stake</span>The
reporter posts about <code>259.3320 REP</code> and
refresh sponsor posts about <code>259.3320 REP</code> and
<code>0.11729847 WETH</code>, roughly <code>$205</code> of each
token side at that snapshot. The displayed WETH decimal is an
explanatory approximation from the rounded REP/ETH quote rather than
Expand Down Expand Up @@ -1186,16 +1191,18 @@ <h2>Callback Rejection and Recovery</h2>
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 <code>requestPrice</code> directly. When OpenOracle has
already settled but the coordinator is still pending because the
need to call <code>requestPrice(amount2)</code> directly with the ETH
bounty plus the REP/WETH funding and approvals needed for the atomic
initial report. When OpenOracle has already settled but the coordinator is still pending because the
low-level callback did not complete, anyone can call
<code>recoverSettledPendingReport</code>. Recovery clears the pending
report, resets the settlement base-fee cap, and consumes only
<code>pendingOperationSlotId</code> 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 <code>requestPrice()</code> call followed by
successful settlement.
example a direct <code>requestPrice(amount2)</code> call that opens a
new report and atomically submits its initial REP/WETH position
before successful settlement.
</p>
</section>

Expand Down
3 changes: 3 additions & 0 deletions docs/operator-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,12 @@ callback behavior, stale-operation handling, and liquidation boundaries.
| Callback gas | Callback gas is `gasConsumedSettlement * MAX_PENDING_SETTLEMENT_OPERATIONS`. With current parameters that is `1,000,000 * 4 = 4,000,000`. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Price cache | One accepted REP/ETH price inside the coordinator, reusable only while it remains inside the freshness window. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Initial report size | The configured `exactToken1Report` is sized from dispute economics: target error, OpenOracle fees, dispute gas, assumed gas price, REP/ETH price, dispute multiplier, and expected adverse REP/ETH movement during settlement. It does not scale with the outside funds protected by the price. The shared `@zoltar/shared/oracleInitialReport` helper computes `259.332023575638507216 REP` from those inputs; UI deployment helpers and simulator deployment helpers consume that shared value. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol), [oracleInitialReport.ts](../shared/ts/oracleInitialReport.ts), [deploymentHelpers.ts](../ui/ts/contracts/deploymentHelpers.ts), [deployPeripherals.ts](../solidity/ts/testsuite/simulator/utils/contracts/deployPeripherals.ts) |
| Atomic initial report | Every coordinator-opened report also submits its initial REP/WETH report inside the same transaction. The sponsor must fund the ETH bounty plus the REP and WETH posted into OpenOracle. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Immediate execution | If a price is still valid, the operation executes immediately and the caller's ETH is refunded. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Fresh-price request guard | `requestPrice` reverts while the cached coordinator price is still valid, so callers cannot open a redundant pending report on top of a fresh cache. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Staging guardrails | Withdraw and liquidation amounts must be non-zero; allowance updates may set zero. Validity must be positive and no more than five minutes. Non-liquidation operations must target the caller's own vault. Liquidation must target a different vault; same-vault liquidation is rejected with `Caller bad` before oracle request or execution. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Pending report bound | At most four operations are attached to one settlement callback. Operations can still be tracked as active even when they do not fit into the pending callback batch. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/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. This exclusivity is the intended reward for paying the stale-price refresh cost. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| High settlement basefee | The callback clears the pending report but no-ops if settlement basefee is above the stored maximum multiplier from request time. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Zero report values | A callback with zero amount, zero denominator, or a computed zero price does not update `lastPrice`. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
| Recovery path | Anyone can call `recoverSettledPendingReport`; it reads settlement data, clears the pending report, and consumes the associated pending operation slot. | [OpenOraclePriceCoordinator.sol](../solidity/contracts/peripherals/OpenOraclePriceCoordinator.sol) |
Expand Down
43 changes: 25 additions & 18 deletions docs/whitepaper_placeholder.html
Original file line number Diff line number Diff line change
Expand Up @@ -7621,10 +7621,11 @@ <h2>9. REP/ETH Price Oracle</h2>
</p>
<p>
The OpenOracle path is contestable before the coordinator can use
it: the coordinator requests a REP/WETH report, a reporter posts
token amounts, disputers can replace a bad report with a larger one,
a settler finalizes the report after the timing window, and the
settlement callback returns the final amounts to the coordinator.
it: the coordinator requests a REP/WETH report and atomically posts
the sponsor-funded initial token amounts, disputers can replace a bad
report with a larger one, a settler finalizes the report after the
timing window, and the settlement callback returns the final amounts
to the coordinator.
Request, dispute, settlement, and callback safety checks are
detailed in the dedicated
<a href="./openOracleIntegration.html">OpenOracle integration</a>
Expand Down Expand Up @@ -7760,12 +7761,12 @@ <h2>9. REP/ETH Price Oracle</h2>
height="82"
rx="10"
></rect>
<text class="svg-label" x="793" y="219" text-anchor="middle">
OpenOracle
</text>
<text class="svg-small" x="793" y="239" text-anchor="middle">
reporter posts
</text>
<text class="svg-label" x="793" y="219" text-anchor="middle">
OpenOracle
</text>
<text class="svg-small" x="793" y="239" text-anchor="middle">
sponsor posts initial report
</text>
<text class="svg-small" x="793" y="255" text-anchor="middle">
disputer may replace
</text>
Expand Down Expand Up @@ -7822,9 +7823,9 @@ <h3>Oracle-Staged Operation Trace</h3>
</tr>
<tr>
<td>Create report</td>
<td><code>requestPrice</code></td>
<td>Funds one pending OpenOracle report and records callback gas/basefee bounds.</td>
<td>The requester pays for the contestable price path when the cache is stale.</td>
<td><code>requestPrice(amount2)</code></td>
<td>Funds one pending OpenOracle report, atomically submits the sponsor-funded initial stake, and records callback gas/basefee bounds.</td>
<td>The requester pays for the contestable price path when the cache is stale and cannot open a redundant report while the cache is still fresh.</td>
</tr>
<tr>
<td>Accept callback</td>
Expand All @@ -7847,8 +7848,12 @@ <h3>Oracle-Staged Operation Trace</h3>
operations can remain queued.
</td>
<td>
Remaining operations need a later valid price path, such as a
direct <code>requestPrice()</code> followed by settlement.
Remaining operations need a later valid price path. If the
pending settlement list is empty, another staged request can
fund a replacement report. If pending settlement operation IDs
still remain, an operator or user must call direct
<code>requestPrice(amount2)</code> with the ETH bounty and
initial-report funding, then let that replacement report settle.
</td>
</tr>
<tr>
Expand All @@ -7862,9 +7867,11 @@ <h3>Oracle-Staged Operation Trace</h3>
</div>
<p>
When no fresh price is available, the caller funds the OpenOracle
request bounty. The coordinator sizes that ETH cost from the current
base fee, the callback gas limit, and the configured gas budget for
reporting the price.
request bounty and the initial REP/WETH position. The coordinator
sizes the ETH cost from the current base fee, the callback gas
limit, and the configured gas budget for reporting the price, while
the caller also chooses the initial <code>amount2</code> for the
atomic report submission.
</p>
<p>
While a report remains pending, only the original pending report
Expand Down
12 changes: 12 additions & 0 deletions scripts/check-docs-reference-values.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getMainnetProtocolConfig } from '../shared/ts/protocolConfig'

const html = await readFile('docs/escalation-game-architecture.html', 'utf8')
const zoltarWhitepaper = await readFile('docs/whitepaper_zoltar.html', 'utf8')
const whitepaperPlaceholder = await readFile('docs/whitepaper_placeholder.html', 'utf8')
const bytecodeSnapshot = readBytecodeSnapshot(await readFile('solidity/ts/tests/fixtures/escalationGameBytecode.snapshot.json', 'utf8'))
const interfaceRegressionTest = await readFile('solidity/ts/tests/escalationGameInterfaceRegression.test.ts', 'utf8')

Expand All @@ -16,6 +17,7 @@ assertBudgetHeadroomRow('Project deployed-bytecode budget headroom', formatNumbe
assertBudgetHeadroomRow('EIP-170 headroom', formatNumber(expectedEip170Budget - bytecodeSnapshot.deployedBytes), formatNumber(expectedEip170Budget))
assertContinuationIdentifierExplanation()
assertZoltarForkDepths()
assertCoordinatorRecoveryBranch()

function assertContinuationIdentifierExplanation(): void {
assert.ok(html.includes('uint256(keccak256(abi.encode(address(this), outcomeIndex, depositIndex)))'), 'docs/escalation-game-architecture.html must explain the fork-continuation stable parent deposit identifier formula')
Expand Down Expand Up @@ -59,6 +61,16 @@ function assertZoltarForkDepths(): void {
}
}

function assertCoordinatorRecoveryBranch(): void {
const normalizedPlaceholder = whitepaperPlaceholder.replaceAll(/\s+/g, ' ')
for (const documentedClaim of [
'If the pending settlement list is empty, another staged request can fund a replacement report.',
'If pending settlement operation IDs still remain, an operator or user must call direct <code>requestPrice(amount2)</code> with the ETH bounty and initial-report funding, then let that replacement report settle.',
]) {
assert.ok(normalizedPlaceholder.includes(documentedClaim), `Missing coordinator recovery-branch claim: ${documentedClaim}`)
}
}

function assertSimpleByteRow(label: string, expectedValue: string): void {
const escapedLabel = escapeRegExp(label)
const match = html.match(new RegExp(`<td>${escapedLabel}</td>\\s*<td><code>([^<]+)</code> bytes</td>`))
Expand Down
Loading