Conversation
🦋 Changeset detectedLatest commit: dad0474 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughIntroduces preparatory deployment flow and persistent cached state to the Redeployer script, replaces run() with serialProxies(), adds versioned deployExaFactory(string) and deployExaFactories(), adds NotPrepared() guard, updates tests and gas snapshots, and adds a new changeset file. Changes
Sequence DiagramsequenceDiagram
participant Test
participant Redeployer
participant Registry
participant CREATE3
participant ProposalManager
participant ExaPlugin
participant ExaFactory
Test->>Redeployer: call prepare()
Redeployer->>Registry: lookup protocol components
alt address found
Registry-->>Redeployer: return existing address
else missing
Redeployer->>CREATE3: compute salt & CREATE3-deploy stub (rgba(100,150,240,0.5))
CREATE3-->>ProposalManager: deploy/return stub address
CREATE3-->>ExaPlugin: deploy/return stub address
end
Redeployer->>CREATE3: ensure ExaFactory implementation(s) per version (rgba(120,200,140,0.5))
Test->>Redeployer: call serialProxies(targetNonce) or deployExaFactory(version)/deployExaFactory(proxy)
Redeployer->>ExaFactory: perform deployment/upgrade (requires prepared state)
ExaFactory-->>Redeployer: return result
Redeployer-->>Test: return status/result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request refactors the Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #865 +/- ##
==========================================
+ Coverage 71.59% 72.41% +0.81%
==========================================
Files 227 227
Lines 8217 8472 +255
Branches 2626 2740 +114
==========================================
+ Hits 5883 6135 +252
- Misses 2106 2115 +9
+ Partials 228 222 -6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
contracts/script/Redeployer.s.sol (1)
68-86:⚠️ Potential issue | 🟠 MajorGuard and backfill all plugin dependencies, not just
auditor.Line 68 only backfills when
auditoris zero, and Line 180 only validatesauditor. Ifauditoris set butmarketUSDC/marketWETHare zero, plugin deployment can fail at constructor-time with invalid markets.🔧 Suggested fix
- if (address(auditor) == address(0)) { + if (address(auditor) == address(0)) { auditor = IAuditor( CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAuditor")), vm.getCode("Redeployer.s.sol:StubAuditor")) ); - address stubAsset = - CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAsset")), vm.getCode("Redeployer.s.sol:StubAsset")); + } + + if (address(marketUSDC) == address(0) || address(marketWETH) == address(0)) { + address stubAsset = CREATE3_FACTORY.getDeployed(admin, keccak256(abi.encode("StubAsset"))); + if (stubAsset.code.length == 0) { + stubAsset = + CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAsset")), vm.getCode("Redeployer.s.sol:StubAsset")); + } + + if (address(marketUSDC) == address(0)) { + address stubUSDC = CREATE3_FACTORY.getDeployed(admin, keccak256(abi.encode("StubMarketUSDC"))); + marketUSDC = IMarket( + stubUSDC.code.length == 0 + ? CREATE3_FACTORY.deploy( + keccak256(abi.encode("StubMarketUSDC")), + abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) + ) + : stubUSDC + ); + } + + if (address(marketWETH) == address(0)) { + address stubWETH = CREATE3_FACTORY.getDeployed(admin, keccak256(abi.encode("StubMarketWETH"))); + marketWETH = IMarket( + stubWETH.code.length == 0 + ? CREATE3_FACTORY.deploy( + keccak256(abi.encode("StubMarketWETH")), + abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) + ) + : stubWETH + ); + } - marketUSDC = IMarket( - CREATE3_FACTORY.deploy( - keccak256(abi.encode("StubMarketUSDC")), - abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) - ) - ); - marketWETH = IMarket( - CREATE3_FACTORY.deploy( - keccak256(abi.encode("StubMarketWETH")), - abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) - ) - ); } @@ - if (address(auditor) == address(0)) revert NotPrepared(); + if (address(auditor) == address(0) || address(marketUSDC) == address(0) || address(marketWETH) == address(0)) { + revert NotPrepared(); + }Also applies to: 179-180
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6b9ddd18-4e44-47bb-b692-023871716822
📒 Files selected for processing (4)
.changeset/bumpy-foxes-refuse.mdcontracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
681ea16 to
478caf9
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
contracts/script/Redeployer.s.sol (1)
68-86:⚠️ Potential issue | 🟠 MajorHarden readiness checks for partially resolved dependencies.
prepare()and_deployPlugins()gate onauditoronly. Ifauditoris present butmarketUSDC/marketWETHare not, deployment can fail later inExaPluginconstruction instead of reverting withNotPrepared().🔧 Suggested fix
- if (address(auditor).code.length == 0) { + if (address(auditor).code.length == 0) { auditor = IAuditor( CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAuditor")), vm.getCode("Redeployer.s.sol:StubAuditor")) ); + } + if (address(marketUSDC).code.length == 0 || address(marketWETH).code.length == 0) { address stubAsset = CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAsset")), vm.getCode("Redeployer.s.sol:StubAsset")); - marketUSDC = IMarket( - CREATE3_FACTORY.deploy( - keccak256(abi.encode("StubMarketUSDC")), - abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) - ) - ); - marketWETH = IMarket( - CREATE3_FACTORY.deploy( - keccak256(abi.encode("StubMarketWETH")), - abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) - ) - ); + if (address(marketUSDC).code.length == 0) { + marketUSDC = IMarket( + CREATE3_FACTORY.deploy( + keccak256(abi.encode("StubMarketUSDC")), + abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) + ) + ); + } + if (address(marketWETH).code.length == 0) { + marketWETH = IMarket( + CREATE3_FACTORY.deploy( + keccak256(abi.encode("StubMarketWETH")), + abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) + ) + ); + } } @@ - if (address(auditor).code.length == 0) revert NotPrepared(); + if ( + address(auditor).code.length == 0 + || address(marketUSDC).code.length == 0 + || address(marketWETH).code.length == 0 + ) revert NotPrepared();Also applies to: 179-193
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 27201171-afe2-4d37-9f59-68bbbe95d8e4
📒 Files selected for processing (4)
.changeset/bumpy-foxes-refuse.mdcontracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
There was a problem hiding this comment.
♻️ Duplicate comments (1)
contracts/script/Redeployer.s.sol (1)
179-193:⚠️ Potential issue | 🟠 MajorExpand readiness guard to cover both markets.
_deployPlugins()currently guards onlyauditor, but it immediately consumesmarketUSDCandmarketWETHas constructor inputs. Missing market code can surface as an opaque low-level revert instead ofNotPrepared.🔧 Proposed fix
function _deployPlugins(address admin) internal returns (IPlugin, IPlugin) { - if (address(auditor).code.length == 0) revert NotPrepared(); + if ( + address(auditor).code.length == 0 || address(marketUSDC).code.length == 0 || address(marketWETH).code.length == 0 + ) revert NotPrepared();
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7b34488d-6631-4754-8b0f-08ec0d9f6758
📒 Files selected for processing (4)
.changeset/bumpy-foxes-refuse.mdcontracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
contracts/script/Redeployer.s.sol (1)
90-103:⚠️ Potential issue | 🟡 Minor
run()NatSpec says exclusive nonce, but implementation is inclusive.The parameter docs and loop behavior diverge (
<= targetNonce). Please make these consistent to prevent incorrect caller assumptions.📝 Minimal fix (doc alignment)
- /// `@param` targetNonce The nonce to stop at (exclusive) + /// `@param` targetNonce The nonce to stop at (inclusive)
♻️ Duplicate comments (1)
contracts/script/Redeployer.s.sol (1)
68-86:⚠️ Potential issue | 🟠 Major
NotPreparedcan be skipped while markets are still unresolved.
prepare()backfills stubs only whenauditoris missing, and_deployPlugins()only validatesauditor. Ifauditorresolves butmarketUSDC/marketWETHdo not, plugin deployment can fail with a low-level revert instead ofNotPrepared, andprepare()won’t repair that state.🔧 Suggested fix
- if (address(auditor).code.length == 0) { + if (address(auditor).code.length == 0) { auditor = IAuditor( CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAuditor")), vm.getCode("Redeployer.s.sol:StubAuditor")) ); - address stubAsset = - CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAsset")), vm.getCode("Redeployer.s.sol:StubAsset")); + } + + if (address(marketUSDC).code.length == 0 || address(marketWETH).code.length == 0) { + address stubAsset = CREATE3_FACTORY.getDeployed(admin, keccak256(abi.encode("StubAsset"))); + if (stubAsset.code.length == 0) { + stubAsset = CREATE3_FACTORY.deploy(keccak256(abi.encode("StubAsset")), vm.getCode("Redeployer.s.sol:StubAsset")); + } + if (address(marketUSDC).code.length == 0) { marketUSDC = IMarket( CREATE3_FACTORY.deploy( keccak256(abi.encode("StubMarketUSDC")), abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) ) ); + } + if (address(marketWETH).code.length == 0) { marketWETH = IMarket( CREATE3_FACTORY.deploy( keccak256(abi.encode("StubMarketWETH")), abi.encodePacked(vm.getCode("Redeployer.s.sol:StubMarket"), abi.encode(stubAsset)) ) ); + } } @@ - if (address(auditor).code.length == 0) revert NotPrepared(); + if (address(auditor).code.length == 0 || address(marketUSDC).code.length == 0 || address(marketWETH).code.length == 0) { + revert NotPrepared(); + }Also applies to: 179-193
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ad9fb905-5aa6-418a-9507-a42a5b07c847
📒 Files selected for processing (3)
contracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
76965b3 to
7789af5
Compare
9345b59 to
13997b4
Compare
78d7b91 to
449ada9
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
contracts/script/Redeployer.s.sol (1)
205-224: 🧹 Nitpick | 🔵 TrivialConsider adding
ownerPluginto theNotPreparedcheck.Line 210 only verifies
exaPlugin.code.length, but line 219 also usesownerPluginin the factory constructor. While the intended flow (prepare()deploysownerPluginbeforeexaPlugin) should guarantee both are available, an explicit check would make the invariant clearer and prevent misuse.🔧 Suggested improvement
function deployExaFactory(string calldata version) external returns (ExaAccountFactory f) { bytes32 salt = keccak256(abi.encode("Exa Plugin", version)); f = ExaAccountFactory(payable(CREATE3_FACTORY.getDeployed(acct("admin"), salt))); if (address(f).code.length != 0) return f; - if (address(exaPlugin).code.length == 0) revert NotPrepared(); + if (address(ownerPlugin).code.length == 0 || address(exaPlugin).code.length == 0) revert NotPrepared();
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ac128abc-2a58-4311-946b-ef16e079f4d3
📒 Files selected for processing (4)
.changeset/bumpy-foxes-refuse.mdcontracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dad0474b7c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
♻️ Duplicate comments (1)
contracts/script/Redeployer.s.sol (1)
148-150: 🧹 Nitpick | 🔵 TrivialConsider using
ProposalManager.PROPOSER_ROLEconstant.The inline
keccak256("PROPOSER_ROLE")works but is less maintainable.ProposalManageralready exposes this as a public constant.♻️ Suggested improvement
- if (!ProposalManager(proposalManagerAddr).hasRole(keccak256("PROPOSER_ROLE"), address(exaPlugin))) { - ProposalManager(proposalManagerAddr).grantRole(keccak256("PROPOSER_ROLE"), address(exaPlugin)); + ProposalManager pm = ProposalManager(proposalManagerAddr); + if (!pm.hasRole(pm.PROPOSER_ROLE(), address(exaPlugin))) { + pm.grantRole(pm.PROPOSER_ROLE(), address(exaPlugin)); }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: e21e6346-9d52-44dc-b3b4-6ec268b11725
📒 Files selected for processing (4)
.changeset/bumpy-foxes-refuse.mdcontracts/.gas-snapshotcontracts/script/Redeployer.s.solcontracts/test/Redeployer.t.sol
Summary by CodeRabbit
Refactor
Tests
Chores