Skip to content

fix(core): revalidate OOv3 whitelists and reject duplicate relayers#4954

Draft
tcoatswo wants to merge 2 commits into
UMAprotocol:masterfrom
tcoatswo:codex/fix-oov3-stale-whitelist-cache
Draft

fix(core): revalidate OOv3 whitelists and reject duplicate relayers#4954
tcoatswo wants to merge 2 commits into
UMAprotocol:masterfrom
tcoatswo:codex/fix-oov3-stale-whitelist-cache

Conversation

@tcoatswo

@tcoatswo tcoatswo commented Jun 6, 2026

Copy link
Copy Markdown

Motivation

This PR addresses two validation assumptions where cached or downstream state could diverge from the authoritative input.

OptimisticOracleV3 caches positive collateral and identifier whitelist results to avoid repeated external calls. The positive-cache fast paths treated those results as non-revocable: after governance removed a previously cached currency or identifier, assertTruth continued to accept it until an external caller invoked syncUmaParams.

A removed identifier has an additional failure mode because the DVM revalidates the identifier when a dispute requests a price. OOv3 could accept the assertion from its stale cache while the DVM rejected the dispute against the live whitelist. The reverted dispute left the assertion undisputed, allowing it to settle as true after liveness.

ChainBridge also accepted duplicate addresses in initialRelayers. AccessControl deduplicated role membership, but _totalRelayers incremented for every array element, causing recorded quorum membership to diverge from the actual authorized relayer set.

Summary

  • Revalidate identifier support against the live identifier whitelist for every new assertion.
  • Revalidate currency support against the live collateral whitelist for every new assertion.
  • Preserve final-fee caching: the Store is queried only when a whitelisted currency is first added or re-added to the OOv3 cache.
  • Reject duplicate initial ChainBridge relayers before role assignment and accounting.
  • Add focused Foundry regressions for stale whitelist removals and duplicate relayer initialization.

Details

The identifier path no longer returns early on a cached true value. It updates the cached value from IdentifierWhitelist.isIdentifierSupported on every validation.

The currency path first checks AddressWhitelist.isOnWhitelist live. If the currency has been removed, validation returns false. If it is live-whitelisted but is not currently represented by a positive cache entry, OOv3 restores the entry and fetches its final fee. Existing positive entries continue to reuse their cached final fee.

The ChainBridge constructor now rejects an initial relayer already granted RELAYER_ROLE, ensuring _totalRelayers always matches unique role membership.

Testing

  • Ran end-to-end test, running the code as in production
  • New unit tests created
  • Existing tests adequate, no new tests required
  • All relevant existing tests pass
  • Untested

Commands:

forge test --match-path 'test/foundry/optimistic-oracle-v3/OptimisticOracleV3.*.t.sol'
forge test --match-contract BridgeTest -vvv

Results:

OOv3: 33 tests passed; 0 failed; 0 skipped
ChainBridge: 2 tests passed; 0 failed; 0 skipped

Issue(s)

Security-sensitive fixes. No public issue was opened before the patches to avoid publishing vulnerable behavior without proposed remediations.

Signed-off-by: Tyler Coatsworth <tyler@coatsworth.me>
@tcoatswo tcoatswo force-pushed the codex/fix-oov3-stale-whitelist-cache branch from 0e04fdb to 62eaa1f Compare June 6, 2026 02:07
@tcoatswo tcoatswo changed the title fix(oo-v3): revalidates cached whitelist entries fix(core): revalidate OOv3 whitelists and reject duplicate relayers Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant