fix: Tenderly simulation initCode split, 7702 sentinel forms, and bigint precision - #223
Conversation
…cision - v0.6 initCode was split at 22 chars instead of 42, truncating the factory address to 10 bytes and leaking its second half into an unprefixed factoryData — every v0.6 deployment simulation was garbage. - the EIP-7702 factory sentinel check only matched the short '0x7702' form; the 20-byte right-padded form accepted by EntryPoint v0.8 fell through, skipping the delegation code override (or triggering a bogus deployment simulation in the callData path). - callTenderlySimulateBundle typed value/gasPrice as number, silently rounding wei amounts above 2^53; bigint is now accepted and serialized as a decimal string. - stateOverrides passed by the caller were rewritten in place (stateDiff renamed to storage); the conversion now works on a copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughTenderly simulation helpers now recognize both EIP-7702 sentinel formats, parse full factory addresses from ChangesTenderly simulation updates
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant UserOperation
participant TenderlyHelper
participant StateOverrides
participant Tenderly
UserOperation->>TenderlyHelper: provide factory and factoryData
TenderlyHelper->>TenderlyHelper: normalize sentinel and build initCode
TenderlyHelper->>StateOverrides: install delegation code
TenderlyHelper->>Tenderly: submit simulation request
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
Sednaoui
left a comment
There was a problem hiding this comment.
Requesting changes based on live Tenderly verification.
What is working:
- The padded EIP-7702 marker in the full
handleOpspath is valid. Simulation07bb5508-667b-4deb-8580-c4af19bfd61ecompleted withstatus=true, included the sender code override, and executed the expected 1-wei internal transfer. - The v0.6 split, bigint serialization, and non-mutating state-override changes also behaved correctly in isolated request probes.
Two EIP-7702 cases still need correction:
- The short marker with non-empty
factoryDatais packed as0x7702<factoryData>rather than a 20-byte right-padded marker followed by the data. - The direct call-data path removes the sentinel but does not install the delegation override and discards initialization data. In simulation
001431d4-9e83-409d-b667-49cafe163d16, Tenderly returnedstatus=truebut no internal transfer executed. The same call with the missing delegation override added (c727864a-f42e-4e0e-8228-371482f24fa2) executed successfully.
Please add regression coverage for short/padded markers, fresh delegation, and non-empty factoryData.
| if ( | ||
| !isV6UserOperation && | ||
| (userOperation as UserOperationV7 | UserOperationV8 | UserOperationV9).factory === "0x7702" | ||
| isEip7702FactorySentinel( |
There was a problem hiding this comment.
The expanded padded-marker detection is valid, but the short-marker case is still malformed when factoryData is non-empty. The initCode construction above concatenates the data immediately after 0x7702, producing e.g. 0x77021234; EntryPoint requires 0x7702 right-padded to 20 bytes before the initialization data. A live Tenderly run decoded exactly 0x77021234 and reverted through the ordinary deployment path with AA10 sender already constructed. Please normalize the short marker during initCode construction and add a regression test for non-empty factoryData.
| // factoryData:null. This doesn't represent an actual factory | ||
| // deployment, so normalize to null. | ||
| if (factory === "0x7702") { | ||
| if (isEip7702FactorySentinel(factory)) { |
There was a problem hiding this comment.
This avoids treating the padded marker as a factory, but the direct simulation is still semantically incomplete: it neither installs the sender's EIP-7702 delegation-code override nor preserves non-empty factoryData as the sender initialization call. In live Tenderly simulation 001431d4-9e83-409d-b667-49cafe163d16, this path returned status=true while executing no internal transfer; adding the missing code override made the same call execute successfully (c727864a-f42e-4e0e-8228-371482f24fa2). Please mirror the full simulation's delegation override here and, when factoryData is non-empty, enqueue the SenderCreator-to-sender initialization before the call-data transaction.
The handleOps encoding concatenated the short 0x7702 factory sentinel directly with factoryData, producing a malformed initCode head; normalize it to the 20-byte right-padded marker EntryPoint requires (also in the executeUserOp rewrite path). The direct call-data simulation dropped the sentinel entirely: it now installs the sender's 0xef0100 delegation-code override from eip7702Auth and routes non-empty factoryData as the SenderCreator-to-sender initialization call. Adds regression tests for short/padded markers, fresh delegation, and non-empty factoryData. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes in
utilsTenderlythat made simulations wrong or lossy.initCodewas split at 22 chars instead of 42, truncating the factory address to 10 bytes and leaking its second halfinto an unprefixed
factoryData.0x7702but not the 20-byte right-padded form accepted by EntryPoint v0.8, which fell through — skipping the delegation code override, or triggering a bogus deployment simulation in the callData path.callTenderlySimulateBundletypedvalue/gasPriceasnumber, silently rounding large wei amounts.bigintis now accepted and serialized as a decimal string.stateOverridesmutated in place: thestateDiff→storagerename rewrote the caller's object; the conversion now works on a copy.Summary by CodeRabbit