OP Fault Proof upgrade break op-verifier and op-gateway implementation in the EVM Gateway

Chained CCIP-Reads are already supported!

Correct, but in a trustless gateway setup, a rogue gateway can provide a variety of status codes that will terminate the CCIP-Read session.

Shuffling the endpoints lets you dodge the rogue gateway via retry.

However, the callback function should be able to signal that the response was unacceptable and that further endpoints should be tried.

An additional OffchainLookup revert during the callback would be insufficient as the protocol doesn’t reveal the state of the endpoint iterator.

Instead of OffchainNext, it could just be an overload of OffchainLookup, where the endpoint array contains some signal value, like ["$next"]. This would be backwards-compatible as it would just appear like an error to unaware clients.

For open gateways that provide arbitrary storage proofs following some standard, a different solution would be the ability to identify these types of interchangeable endpoints and substitute them with client-side choices.

Edit: If a data URL was a valid CCIP endpoint (maybe it is?), then the contract could do it’s own iteration and randomization by providing pairs for each actual endpoint: [url_i, "data:text/json,{"data":...}]. If url_i fails, the data URL will succeed, and the next URL can be tried: [url_i+1, "data..."]. If url_i succeeds but is a faux response, the callback can just revert again with [url_i+1, "data:..."].

Ah, I see what you mean. Yes, some way for the contract to canonically indicate that the response was unacceptable would be ideal here.

Instead of recursive CCIP-read we can also use multiple gateways as multisig…

0 > start with reverting OffchainLookup with random list of gateways,

eg. we’ve 3 gateways.
1st gateway will read records data from DB/L2 then call another gateway for signature.

  • if 1st gateway fails, ccip-read will auto fallback to next gateway in lookup array

2nd gateway will read from their DB/L2 endpoints and reply 1st gateway with signed data.

  • if 2nd gateway fails 1st gateway can request 3rd gateway

1st gateway can pack their data + signature with 2nd gateway’s signature in {data:…} so resolver contract can check if same data is signed by 2/3 of unique gateways.

we’re testing around basic multisig gateways for .sol+ENS integration, we’ve dev works paused for now as we need proper ccip-write specs for 2-way read-write.

** still WIP, not tested codes


I created a version of this that works pretty well: resolveworks/OffchainNext.sol

It’s a contract base which has a helper function offchainLookup() that invokes revert OffchainLookup with some additional logic:

  • It “randomizes” using the current block.number and tries pairs [uri_i, data:...].
  • If the response is 200, it calls the original callback, and if that reverts with an error that satisfies _shouldTryNext() -> bool, it will try the next endpoint until all endpoints are tried, then revert OffchainEOL.
  • By default, _shouldTryNext() returns true for revert OffchainNext().

It has a blocksmith test, where I give it 5 endpoints:

  1. a random website
  2. server that signs
  3. server that throws
  4. server that returns the wrong answer
  5. server that returns the right answer

I call the example CCIP-Read function in a loop and it succeeds 100% of the time, with a randomized order.


adraffy/CCIPRewriter.sol is a resolver that modifies how name is resolved when input as [name].[basename]. This is very similar to the XOR where [name].[basename] resolves name via ENSIP-10 and then calls the non-ENSIP-10 equivalents instead (ie. an exclusively on-chain version of the name.)

For CCIPRewriter, [name].{base32(endpoint)}.[basename] resolves name via ENSIP-10 and then wraps OffchainLookup() and rewrite urls = [endpoint]. An on-chain name or a name that doesn’t revert is unaffected.

Two obvious use-cases: debugging (rewrite to localhost) and privacy (rewrite to local gateway.)


I had this behavior available in my resolver (using debugger → custom ccip rewrite) and found it very useful but this technique makes it use-able anywhere ENSIP-10 is supported.

Edit: since gas was 6 gwei, I deployed a version to mainnet at ccipr.eth