Skip to content

feat: CREATE3 deploy of EnsoSwapModule on dev (same address OP + mainnet)#176

Open
jtfirek wants to merge 2 commits into
feat/eth-asset-supportfrom
jacob/deploy-enso-create3-dev
Open

feat: CREATE3 deploy of EnsoSwapModule on dev (same address OP + mainnet)#176
jtfirek wants to merge 2 commits into
feat/eth-asset-supportfrom
jacob/deploy-enso-create3-dev

Conversation

@jtfirek

@jtfirek jtfirek commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Why

Enso is wired up in the BE (SwapRouterService tries enso first), but the router silently falls back to OpenOcean/Across because ensoSwapModule is undefined in the cash-be chain-registry. That single field is resolved on mainnet.id and is assumed to be one CREATE3 address shared by OP + mainnet (same as AcrossSwapModule).

The existing standalone DeployEnsoModule.s.sol deployed via plain new UUPSProxy(...) (nonce-based CREATE), so the two proxies diverged:

  • OP (10): 0x9EF2C6a01EbD49EfAdA26B5a0a19f5C4FB7FC8A1
  • Mainnet (1): 0xeaBf20f60594bCE8edde7bBc767528B2ef30DEc6

Both are already whitelisted as default modules on-chain, but the divergent addresses can't be represented by the BE's single field — so Enso stayed off.


Note

Medium Risk
On-chain default-module whitelist changes and swap routing depend on running this migration correctly; mistakes could leave duplicate Enso modules or misconfigured holds on OP.

Overview
Adds DeployEnsoModuleCreate3.s.sol, which deploys EnsoSwapModule via EtherFiDeployer CREATE3 so the proxy is 0x913B… on both Optimism and mainnet—matching the backend’s single ensoSwapModule field (same pattern as Across).

The script is idempotent: CREATE3 deploy only if the slot is empty, then whitelist the module, wire CashModule withdrawal holds on OP, grant ENSO_SWAP_MODULE_ADMIN_ROLE, and unwhitelist the old nonce-based proxies (0x9EF2… / 0xeaBf…). It reads OP from deployments.json and mainnet TradingSafe from trading-account.json when TRADING_ACCOUNT=true, and writes deployments/dev/{1,10}/enso-module.json for integration.

Reviewed by Cursor Bugbot for commit f8d6c6f. Bugbot is set up for automated code reviews on this repo. Configure here.

…mainnet)

The earlier DeployEnsoModule.s.sol used plain `new UUPSProxy(...)` (nonce-based
CREATE), so the proxies diverged across chains (OP 0x9EF2…, mainnet 0xeaBf…) and
could never be wired into the BE's single `ensoSwapModule` field (resolved on
mainnet.id, like AcrossSwapModule). This deploys impl+proxy via the EtherFiDeployer
CREATE3 path so the proxy lands at the same address on every chain
(0x913B27840Ea4c409665eFe7bcA738B6e0E948b0d), then in the same broadcast whitelists
it as a default module, registers the CashModule hold path where one exists (OP),
grants the admin role, and retires the stale non-CREATE3 module. Verified via
dry-run on both OP (chain 10) and mainnet (chain 1).

Co-authored-by: Cursor <cursoragent@cursor.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Comment thread scripts/DeployEnsoModuleCreate3.s.sol
Address the "occupied slot blocks stale retire" review: instead of reverting when
the deterministic proxy already exists, reuse it and still run the (idempotent)
whitelist / hold-registration / role-grant / stale-retire steps, so a re-run always
finishes the migration. grantRole is now guarded by hasRole.

Deployed on dev (OP 10 + mainnet 1) at 0x913B27840Ea4c409665eFe7bcA738B6e0E948b0d
(impl 0x704eCbAcEeEC66E3F83F5d2BC053EeA7C7eE4a37), both verified; stale non-CREATE3
modules (OP 0x9EF2…, mainnet 0xeaBf…) retired.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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 1 potential issue.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit f8d6c6f. Configure here.

require(stale == address(0) || !dataProvider.isDefaultModule(stale), "stale module still whitelisted");
require(enso.getEnsoRouter() == ENSO_ROUTER, "enso router mismatch");

_persist(address(enso), impl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Uninitialized impl on idempotent persist

Medium Severity

When the CREATE3 proxy already exists, the script skips deployment but still calls _persist with impl never assigned, so it stays address(0). That overwrites enso-module.json with a zero EnsoSwapModuleImpl even though the on-chain implementation is unchanged—likely on the documented idempotent re-run path.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f8d6c6f. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant