How Non-Unique UserOp Hashes Broke ERC-4337 Infrastructure

A debugging experiment with repeated UserOperations exposed assumptions about userOpHash uniqueness.

While porting ERC-4337 to Foundry, I encountered a strange issue: repeating the same userOp increased its gas usage by two or three gas on every iteration. Solidity did not free the memory and expanded the memory slot on each iteration.

The Foundry port is available in the foundry-4337 repository.

Debugging the gas increase

I initially thought this was a Foundry bug, so my friend @windowhan from @kalos_security and I debugged every JUMP and its gas usage. We found that the gas cost increased on some MSTORE operations.

MSTORE gas increase

Although I found the main cause, we still needed to test it on a testnet and check whether it behaved the same way: view the Goerli transaction.

The account was a mock account, so any userOp could proceed. To confirm that the behavior came from memory bloat rather than something else, we repeated the operation. That produced five UserOperations with an identical userOpHash.

Infrastructure assumptions

The result made things behave strangely because most infrastructure depended on userOpHash being unique.

Blocknative’s ERC-4337 dashboard showed only the first UserOperation. JiffyScan also showed only one UserOperation, while Stackup returned an “invalid hash” error, although I may have been doing something wrong.

Infrastructure response

I do not think those teams did anything wrong. This was an edge case that appeared during testing, but it showed that the ecosystem needed to discuss the assumption. Disallowing nonce reuse might be one solution.