Skip to content

managed-oracle: add partial-success SignedProposer batching - #72

Open
chrismaree wants to merge 4 commits into
chrismaree/signed-proposerfrom
chrismaree/signed-proposer-try-multicall
Open

managed-oracle: add partial-success SignedProposer batching#72
chrismaree wants to merge 4 commits into
chrismaree/signed-proposerfrom
chrismaree/signed-proposer-try-multicall

Conversation

@chrismaree

Copy link
Copy Markdown
Member

What Changed

  • Added executor-only tryMulticall(bytes[]), gated by DELEGATED_PROPOSER_ROLE, for partial-success proposal batches.
  • Prevalidates every child as SignedProposer.propose before execution and enforces bounds of 8 calls, 96 KiB combined inner calldata, and 1,500,000 gas per child.
  • Executes children with self-delegatecall, preserving the original relayer as msg.sender and each proposal's existing Permit2 spender, funding, whitelist, refund, payment, nonReentrant, ProposalExecuted, and Managed OO ProposePrice behavior.
  • Returns a per-child bool[] and emits bounded ProposalCallFailed(index, callHash, errorSelector, revertDataHash) evidence for each failure without logging full calldata, signatures, or revert data.
  • Keeps inherited OpenZeppelin atomic multicall(bytes[]) unchanged and does not modify the execution worker, ManagedOptimisticOracleV2, or existing oracle interfaces.
  • Added contract/operator documentation, focused unit and real-Permit2 tests, and pinned Polygon fork coverage using canonical Permit2.

Why

  • Atomic batching forces a worker to retry successful siblings whenever any proposal in the bundle reverts.
  • Native partial-success execution lets independent proposals settle independently while providing deterministic failure correlation by batch index and call hash.
  • Fixed child gas and up-front failure-accounting reserves prevent a gas-exhausting child from consuming the gas required to classify failures and continue later calls.

Impact

  • Delegated proposers can opt into tryMulticall; existing direct propose and atomic multicall integrations remain compatible.
  • Successful children remain authoritative through the existing ProposalExecuted and Managed OO ProposePrice events.
  • Failed children can be classified independently from the returned result and ProposalCallFailed event.
  • This is a stacked PR targeting chrismaree/signed-proposer and depends on the SignedProposer introduction in PR managed-oracle: add audited SignedProposer #69.

High risk Sections to review with detail

  • Self-delegatecall and caller preservation: each bounded child is copied from calldata to memory before delegatecall; review that the outer relayer remains msg.sender, only the propose selector is accepted, and the existing per-proposal nonReentrant modifier still enters and exits independently.
  • Gas isolation and failure continuation: review the 1,500,000 child cap, 3,400,000 per-child outer reserve, 8-call maximum, 96 KiB aggregate calldata maximum, and the up-front gas check against Polygon's transaction constraints.
  • Revert-data handling: automatic returndata copying is disabled. On failure, the complete returndata is copied once into reusable scratch memory to derive the first four-byte selector and exact keccak256(revertData); no unbounded bytes are returned or logged.
  • Failure evidence: verify index, keccak256(calls[index]), selector fallback to bytes4(0), event order, and continuation after emission.
  • Compatibility boundary: verify no ManagedOptimisticOracleV2, existing interface, or worker behavior changes and that inherited OpenZeppelin multicall remains atomic.

Validation

  • forge build
  • forge test --match-contract 'SignedProposer(Test|Permit2Test)' -vv — 54 passed
  • forge test --no-match-contract '.*Fork.*' -vv — 127 passed
  • Exact ABI inspection confirms tryMulticall, ProposalCallFailed, bounds, and custom errors.
  • Adversarial coverage includes mixed/all outcomes, late collision, selector/access/reentrancy checks, atomic compatibility, Permit2 nonce/token rollback, different proposers/nonces, exact events, a gas-exhausting child, and exact hashing of 512 KiB revert data.
  • The pinned Polygon fork test compiles and targets block 81683818 with canonical Permit2; it was not executed locally because NODE_URL_137 is unavailable in this shell and is expected to run in CI.
  • Confirmed no diff to ManagedOptimisticOracleV2 or existing oracle interfaces.

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