Skip to content

feat: migration to repair ERC-4337 config on Safes - #375

Open
aurel-fr wants to merge 8 commits into
mainfrom
aurel/repair-module
Open

feat: migration to repair ERC-4337 config on Safes#375
aurel-fr wants to merge 8 commits into
mainfrom
aurel/repair-module

Conversation

@aurel-fr

Copy link
Copy Markdown
Collaborator

Adds a migration that enables the 4337 module and sets it as fallback handler via a relayed execTransaction.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a migration path to “repair” legacy Gnosis Safes that were deployed without the ERC-4337 module configuration, by detecting missing config (module enablement + fallback handler) and relaying a signed execTransaction through the backend.

Changes:

  • Add Safe4337ModuleProcessor migration that checks on-chain Safe state and relays a signed repair execTransaction.
  • Add Safe-module helper utilities (calldata encoding, fallback handler slot constant, MultiSend bundle building).
  • Extend the RPC client + test HTTP client to support eth_getStorageAt and wa_relaySafeTransaction, plus add an end-to-end integration test.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
bedrock/tests/test_safe_4337_module_processor.rs New E2E test validating detection + relayed repair + post-state checks.
bedrock/tests/common.rs Refactors Safe deployment helper; adds a “without 4337 module” deployment path for tests.
bedrock/src/transactions/rpc.rs Adds EthGetStorageAt + RelaySafeTransaction RPC method support and client helpers.
bedrock/src/transactions/contracts/safe_module.rs New helpers for checking/installing the 4337 module and reading fallback handler slot.
bedrock/src/transactions/contracts/mod.rs Exposes the new safe_module helpers module.
bedrock/src/test_utils.rs Extends AnvilBackedHttpClient to simulate eth_getStorageAt + wa_relaySafeTransaction.
bedrock/src/migration/processors/safe_4337_module_processor.rs New migration processor implementing the Safe 4337 repair flow.
bedrock/src/migration/processors/mod.rs Registers/exports the new migration processor module.
bedrock/src/migration/mod.rs Re-exports Safe4337ModuleProcessor.

Comment thread bedrock/src/migration/processors/safe_4337_module_processor.rs
Comment thread bedrock/src/transactions/contracts/safe_module.rs Outdated
Comment thread bedrock/src/transactions/contracts/safe_module.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 346cd1b713

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bedrock/src/migration/processors/safe_4337_module_processor.rs
Comment thread bedrock/src/migration/processors/safe_4337_module_processor.rs Fixed
@aurel-fr aurel-fr changed the title Add migration to repair ERC-4337 config on Safes feat: migration to repair ERC-4337 config on Safes Jun 24, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3f5484c. Configure here.

Comment thread bedrock/src/migration/processors/safe_4337_module_processor.rs Outdated
processors
.push(Arc::new(Permit2ApprovalProcessor::new(account.clone())));
processors
.push(Safe4337ModuleProcessor::new(account).as_migration_processor());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permit2 runs parallel to repair

Medium Severity

Registering Safe4337ModuleProcessor alongside Permit2ApprovalProcessor while run_migrations_async still runs all processors in parallel means legacy Safes attempt Permit2 user operations before the 4337 repair can finish in the same run, so Permit2 fails even when the repair would succeed moments later.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3f5484c. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration processor has been built this way. It will self-heal on next app open and we can consider making the migration sequential in a future PR.

@aurel-fr
aurel-fr requested a review from Copilot June 24, 2026 17:25
@aurel-fr

Copy link
Copy Markdown
Collaborator Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 1c2d96bed6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


impl Safe4337ModuleProcessor {
/// Reads the Safe's ERC-4337 configuration on-chain and returns the repairs
/// needed (module enablement and/or fallback handler).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me make sure the backend checks for this - i think it was assuming both steps

karankurbur
karankurbur previously approved these changes Jun 24, 2026
}

async fn is_applicable(&self) -> Result<bool, MigrationError> {
// Always attempt — the on-chain check lives in `execute`, which is the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the check logic should be in here not execute.

execute is only called if this function returns true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on purpose. Let's assume a user needs repair. On first try the execute will send the repair and forward to tx-sitter. The transaction may take time to mine or it could fail even. So we don't mark the processor as executed successfully. On next app open the execute will trigger again, and if the previous tx mined it will exit early and mark as successful. The reason we do this dance is because only execute can return a ProcessorResult, is_applicable just return a boolean.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine - the is_applicable should always be checking the chain state as the source of truth instead of the txId/txHash returned

the migrations only apply once on cold start so we dont really need to worry about them running multiple times

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following. The migration processor does check chain state let repairs = self.fetch_repairs().await?;. It is the source of truth.

// configured (e.g. a repair relayed on a previous run has since mined),
// report success; otherwise relay the repair and stay retryable so the
// next run confirms it.
let repairs = self.fetch_repairs().await?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Comment thread bedrock/src/migration/processors/safe_4337_module_processor.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants