Repository navigation
[evm]: migrate SimplexPaymaster to EntryPoint v0.9 #1365
Description
Background
SimplexPaymaster only answers to EntryPoint v0.8. It inherits OpenZeppelin's PaymasterCore, whose entryPoint() returns ERC4337Utils.ENTRYPOINT_V08, and validatePaymasterUserOp and postOp reject every other caller.
EntryPoint v0.9 (0x433709009B8330FDa32311DF1C2AFA402eD8D009) calls paymasters through the same interface. IPaymaster and PackedUserOperation are unchanged from v0.8, and the v0.9 release notes say existing paymasters need no changes.
The paymaster has to move before #816 can ship: #816 needs getCurrentUserOpHash(), which only v0.9 has.
Proposed change
- Override
entryPoint()to return the v0.9 address. OpenZeppelin contracts 5.4.0 has no v0.9 constant, so define it locally. - Bump
VERSIONand add the migration for the upgrade. - Keep the exact-length checks on
paymasterData(150 and 182 bytes). They already reject operations carrying v0.9's newpaymasterSignaturesuffix, which this paymaster does not use. Add a test for it.
What does not carry over
The deposit and the stake are held per EntryPoint. After the upgrade the proxy has neither on v0.9, and its v0.8 deposit and stake are still in the old EntryPoint.
- Fund v0.9. Deposit and stake on v0.9 on every chain before any v0.9 operation is sent.
- Recover v0.8.
WithdrawAssets,UnlockStakeandWithdrawStakeall go throughentryPoint(), which points at v0.9 after the upgrade.unlockStakemarks the paymaster unstaked at once, and the withdrawal then waits outunstakeDelaySec.
Decisions needed
- How the v0.8 funds are recovered. Either withdraw before the upgrade and accept that the paymaster is unstaked on v0.8 for the delay, or give the new implementation a host-only path to the v0.8 EntryPoint that governance reaches through
PaymasterUpgradeinit_data, the waymigrateis reached today. The second needs no new request kind inpallet-intents-coprocessor. - Cutover or transition. Once
entryPoint()returns v0.9, every v0.8 operation naming this paymaster fails validation, so a hard cutover needs all solvers to switch at the same time. The alternative is to accept both EntryPoints as callers for a transition period. Nothing in validation orpostOpdepends on which EntryPoint called, but the stake and deposit functions would then need to say which EntryPoint they act on. - Ship with [simplex] Bundler whitelists in paymaster #1364. The bundler whitelist is also a paymaster change. One governance upgrade per chain is cheaper than two.
Verify against v0.9
- The unused-gas penalty rule is unchanged (10% of unused gas above a 40,000 threshold), so
MAX_POST_OP_GAS_LIMIT,MIN_POST_OP_GAS_LIMITand the_postOpCostcushion should still hold. The EntryPoint's internal overhead may differ, so re-run the gas-grief tests against the v0.9 contract. - v0.9 reads a validity range as block numbers only when both bounds have their top bit set. The paymaster returns
validAfter = 0, so its Permit2 deadline stays a timestamp.
Rollout
Deployed on Ethereum, BNB Chain, Arbitrum, Base and Polygon. Per chain:
- Deploy the new implementation (
DeploySimplexPaymasterImpl.s.sol) - Upgrade through governance (
upgrade_paymaster) with the migration calldata - Deposit and stake on EntryPoint v0.9
- Recover the v0.8 deposit and stake to the treasury
- Confirm the fee-recycling keeper's
swapAndDeposittops up the v0.9 deposit
Affected files
evm/src/utils/SimplexPaymaster.solevm/script/DeploySimplexPaymasterImpl.s.sol,evm/script/SimplexPaymasterPermit2Probe.s.solevm/tests/foundry/SimplexPaymasterTest.t.sol,SimplexPaymasterGasGriefTest.t.sol,SimplexPaymasterPermit2ForkTest.t.sol,SimplexPaymasterStakeLockForkTest.t.sol, all pinned toENTRYPOINT_V08- README and docs that describe the paymaster as v0.8
Acceptance
- Fork tests pass against the canonical v0.9 EntryPoint
- A sponsored operation succeeds through a v0.9 bundler in both PERMIT and PERMIT2 modes
- The v0.8 deposit and stake are back in the treasury on all five chains
Activity
seunlanlege commentedon Oct 9, 2026
closed in #1371