OP Security Proxy: A local RPC middleware to prevent paying for failed L2 executions

I am putting together OP Security Proxy, which is a fast JSON-RPC middleware layer I wrote in Rust. You can check out the code at GitHub - Ishant5436/op-sec-proxy · GitHub . It essentially sits between a standard wallet or client and the public Optimism RPC nodes.

The core mechanic is that whenever a transaction goes out via eth_sendRawTransaction, the proxy catches it. It then uses the revm engine to fork the network state locally and run a quick simulation. If it detects that the transaction is going to revert, halt, or burn the whole gas limit without touching the state, the proxy just drops it before it ever hits the public mempool.

I built this because when you use Ethereum-equivalent chains, you still end up paying the L2 execution fee up to the point of failure if a transaction reverts on-chain. We see this all the time with MEV bots, slippage issues, or unexpected state changes. This proxy serves as a public good that stops regular users from paying for failed executions, saving them money and keeping junk traffic off the sequencer.

I ran some tests against the mainnet.optimism.io endpoint to see the performance impact. For standard read requests like eth_call, there is basically no overhead. Because I am using tokio and hyper for connection pooling, the jitter was actually slightly better than hitting the upstream directly. The upstream took around 516ms, while the proxy handled it in about 444ms.

When doing the actual transaction simulation, it takes about 2.9 seconds. That overhead comes from having to fetch nonces, balances, and raw bytecodes over the network on the fly so we can reconstruct the state from scratch.

For the stack, it is mostly Rust. I rely on tokio for the async side of things and hyper to handle the HTTP server. I also pull in alloy to handle the Ethereum primitives and RPC parsing, while revm runs the local EVM simulations. I also wrote a bunch of strict TDD tests to make sure it doesn’t panic if an upstream node times out.

Looking ahead, I am hoping to implement LRU caching for the state trie nodes so we can drop the simulation latency well below 100 milliseconds. I also plan to bake in some local heuristics to catch sandwich attacks before they happen, and eventually make sure the whole thing runs smoothly across Base and other Superchain networks.

This sounds useful, especially for users who are confused when a transaction fails but they still lose money to fees.

From a support perspective, how would this appear to an ordinary wallet user? Would they receive a clear explanation that the transaction was stopped and why?

Making that message easy to understand could be just as important as preventing the failed transaction itself.

1 Like

Right now, when a transaction reverts in local revm simulation, the proxy intercepts the send call and returns a standard JSON-RPC error with code minus 32000 instead of a transaction hash. In the error payload, it includes both the raw hex revert data and a human readable decoded string when a standard Error(string) or Panic(uint256) signature is present. For a wallet like GemWallet or MetaMask connected through the proxy, the wallet catches that RPC error before signing or broadcasting. Instead of the user seeing a confusing onchain failed receipt twenty seconds later with lost gasfees, the wallet immediately renders the exact reason, such as slippage exceeded or insufficient allowance, right at the confirmation step. I am also adding an extra metadata field in the error response that calculates the estimated L2 gas fee the user just saved by having the execution halted locally. That way, the wallet UI can explicitly show users that their transaction was safely intercepted and no gas was spent.

1 Like

Just wanted to close the loop here. The question about how this surfaces to an ordinary wallet user directly shaped how I scoped the SDK work: the formal builder grant proposal is now up at [Builder Grant Proposal] OP Security Proxy: Local Pre-Execution & Revert Interception for the Superchain, and milestone two is specifically the TypeScript provider wrapper with standardized error decoding so a wallet like GemWallet can render the exact revert reason and the gas saved at the confirmation step, instead of a generic failed transaction. Appreciate the input, it’s part of why that milestone looks the way it does.

1 Like