Skip to content

Commit

Permalink
refactor: split account deployment into its own script (#62)
Browse files Browse the repository at this point in the history
## Summary
Etherscan can't handle IR pipeline optimization (had no issues on
sourcify and okx so far) if the factory includes account creation.

Deployment & verify commands
```
forge script script/003_DeploySingleOwnerMSCA.s.sol --rpc-url $RPC_URL --broadcast --verify -vvvv --slow 

forge script script/003.1_DeploySingleOwnerMSCAFactory.s.sol --rpc-url $RPC_URL --broadcast --verify -vvvv --slow 
```

For standard json input used in manual verification 
```
forge verify-contract -c 11155111  --optimizer-runs 200 --constructor-args $(cast abi-encode "constructor(address,address)" 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 0xc93D6559Fe4dB59742751A857d11a04861a50CCC) --via-ir 0x9693313996cA03a194A529ef82AB3E3a9955C66d SingleOwnerMSCA --show-standard-json-input > ~/Downloads/account.json


forge verify-contract -c 11155111  --optimizer-runs 200 --constructor-args $(cast abi-encode "constructor(address)" 0x9693313996cA03a194A529ef82AB3E3a9955C66d) --via-ir 0xf4f25B6058bB5F4Bb63F51Ed8D351B66e1Fc0776 SingleOwnerMSCAFactory --show-standard-json-input > ~/Downloads/factory.json
```

## Detail
### Changeset
* Added a dedicated script to deploy account first
* Updated the factory script to use a deployed account
* Update the constructor of factory

### Checklist
- [ ] Did you add new tests and confirm all tests pass? (`yarn test`)
- [ ] Did you update relevant docs? (docs are found in the `docs`
folder)
- [x] Do your commits follow the [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard?
- [x] Does your PR title also follow the [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard?
- [ ] If you have a breaking change, is it [correctly reflected in your
commit
message](https://www.conventionalcommits.org/en/v1.0.0/#examples)? (e.g.
`feat!: breaking change`)
- [x] Did you run lint (`yarn lint`) and fix any issues?
- [x] Did you run formatter (`yarn format:check`) and fix any issues
(`yarn format:write`)?

## Testing
* Updated the existing tests to reflect the constructor changes

## Documentation
n/a
  • Loading branch information
huaweigu authored Jan 17, 2025
1 parent af55d55 commit 9346945
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 24 deletions.
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ via_ir = true
auto_detect_solc = false
auto_detect_remappings = false
deny_warnings = true
optimizer = true
optimizer_runs = 200

[fuzz]
runs = 1024
Expand Down
3 changes: 2 additions & 1 deletion script/000_ContractAddress.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pragma solidity 0.8.24;
address constant ENTRY_POINT = 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789;

// Use address(0) if unknown or deploying a new version of a contract.
address constant PLUGIN_MANAGER_ADDRESS = 0x3169Ad878021B87C9CaA9b5CDA740ff3ca270Ce9;
address constant PLUGIN_MANAGER_ADDRESS = 0xc93D6559Fe4dB59742751A857d11a04861a50CCC;
address constant SINGLE_OWNER_MSCA_ADDRESS = address(0);
address constant SINGLE_OWNER_MSCA_FACTORY_ADDRESS = 0xa233b124D7b9CFF2D38cB62319e1A3f79144B490;
address constant UPGRADABLE_MSCA_FACTORY_ADDRESS = 0x3e6b66A72B76850c372FBDf29f53268ad636B320;
address constant SINGLE_OWNER_PLUGIN_ADDRESS = 0x7af5E9DBe3e50F023a5b99f44002697cF8e1de2e;
Expand Down
49 changes: 49 additions & 0 deletions script/003.1_DeploySingleOwnerMSCA.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2025 Circle Internet Group, Inc. All rights reserved.
* SPDX-License-Identifier: GPL-3.0-or-later
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.24;

import {SingleOwnerMSCA} from "../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol";
import {PluginManager} from "../src/msca/6900/v0.7/managers/PluginManager.sol";
import {ENTRY_POINT, PLUGIN_MANAGER_ADDRESS, SINGLE_OWNER_MSCA_ADDRESS} from "./000_ContractAddress.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {Script, console} from "forge-std/src/Script.sol";

contract DeploySingleOwnerMSCAScript is Script {
address payable internal constant EXPECTED_ACCOUNT_ADDRESS = payable(SINGLE_OWNER_MSCA_ADDRESS);

event AccountImplementationDeployed(
address indexed accountImplementation, address entryPoint, address pluginManager
);

function run() public {
address entryPoint = ENTRY_POINT;
uint256 key = vm.envUint("DEPLOYER_PRIVATE_KEY");
vm.startBroadcast(key);
SingleOwnerMSCA account;
if (EXPECTED_ACCOUNT_ADDRESS.code.length == 0) {
account = new SingleOwnerMSCA{salt: 0}(IEntryPoint(entryPoint), PluginManager(PLUGIN_MANAGER_ADDRESS));
emit AccountImplementationDeployed(address(account), entryPoint, PLUGIN_MANAGER_ADDRESS);
console.log("New single owner MSCA address: %s", address(account));
} else {
account = SingleOwnerMSCA(EXPECTED_ACCOUNT_ADDRESS);
console.log("Found existing single owner MSCA at expected address: %s", address(account));
}
vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,18 @@
pragma solidity 0.8.24;

import {SingleOwnerMSCAFactory} from "../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol";
import {ENTRY_POINT, PLUGIN_MANAGER_ADDRESS, SINGLE_OWNER_MSCA_FACTORY_ADDRESS} from "./000_ContractAddress.sol";
import {SINGLE_OWNER_MSCA_ADDRESS, SINGLE_OWNER_MSCA_FACTORY_ADDRESS} from "./000_ContractAddress.sol";
import {Script, console} from "forge-std/src/Script.sol";

contract DeploySingleOwnerMSCAFactoryScript is Script {
address internal constant PLUGIN_MANAGER = PLUGIN_MANAGER_ADDRESS;
address payable internal constant EXPECTED_FACTORY_ADDRESS = payable(SINGLE_OWNER_MSCA_FACTORY_ADDRESS);

function run() public {
address entryPoint = ENTRY_POINT;
uint256 key = vm.envUint("DEPLOYER_PRIVATE_KEY");
vm.startBroadcast(key);
SingleOwnerMSCAFactory factory;
if (EXPECTED_FACTORY_ADDRESS.code.length == 0) {
factory = new SingleOwnerMSCAFactory{salt: 0}(entryPoint, PLUGIN_MANAGER);
factory = new SingleOwnerMSCAFactory{salt: 0}(SINGLE_OWNER_MSCA_ADDRESS);
console.log("New single owner MSCA factory address: %s", address(factory));
} else {
factory = SingleOwnerMSCAFactory(EXPECTED_FACTORY_ADDRESS);
Expand Down
13 changes: 4 additions & 9 deletions src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ pragma solidity 0.8.24;

import {Create2FailedDeployment, InvalidInitializationInput} from "../../../shared/common/Errors.sol";
import {SingleOwnerMSCA} from "../../account/semi/SingleOwnerMSCA.sol";
import {PluginManager} from "../../managers/PluginManager.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

Expand All @@ -32,9 +30,8 @@ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
contract SingleOwnerMSCAFactory {
// logic implementation
SingleOwnerMSCA public immutable ACCOUNT_IMPLEMENTATION;
IEntryPoint public immutable ENTRY_POINT;

event FactoryDeployed(address indexed factory, address accountImplementation, address entryPoint);
event FactoryDeployed(address indexed factory, address accountImplementation);
event AccountCreated(address indexed proxy, address sender, bytes32 salt);

/**
Expand All @@ -45,11 +42,9 @@ contract SingleOwnerMSCAFactory {
* during the deployment. No hooks can be injected during the account deployment, so for a future installation
* of more complicated plugins, please call installPlugin via a separate tx/userOp after account deployment.
*/
constructor(address _entryPointAddr, address _pluginManagerAddr) {
ENTRY_POINT = IEntryPoint(_entryPointAddr);
PluginManager _pluginManager = PluginManager(_pluginManagerAddr);
ACCOUNT_IMPLEMENTATION = new SingleOwnerMSCA(ENTRY_POINT, _pluginManager);
emit FactoryDeployed(address(this), address(ACCOUNT_IMPLEMENTATION), _entryPointAddr);
constructor(address _singleOwnerMSCAImplAddr) {
ACCOUNT_IMPLEMENTATION = SingleOwnerMSCA(payable(_singleOwnerMSCAImplAddr));
emit FactoryDeployed(address(this), address(ACCOUNT_IMPLEMENTATION));
}

/**
Expand Down
3 changes: 2 additions & 1 deletion test/WalletMigration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ contract WalletMigrationTest is TestUtils {
testERC1155 = new TestERC1155("getrich.com");
testERC721 = new TestERC721("getrich", "$$$");
testERC20 = new TestLiquidityPool("getrich", "$$$");
singleOwnerMSCAFactory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager));
SingleOwnerMSCA singleOwnerMSCA = new SingleOwnerMSCA(entryPoint, pluginManager);
singleOwnerMSCAFactory = new SingleOwnerMSCAFactory(address(singleOwnerMSCA));
ecdsaAccountFactory = new ECDSAAccountFactory(entryPoint);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@ pragma solidity 0.8.24;

import {FunctionReference} from "../../../../../../src/msca/6900/v0.7/common/Structs.sol";

import {
PluginManager,
SingleOwnerMSCA,
SingleOwnerMSCAFactory
} from "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol";
import {SingleOwnerMSCA} from "../../../../../../src/msca/6900/v0.7/account/semi/SingleOwnerMSCA.sol";
import {SingleOwnerMSCAFactory} from "../../../../../../src/msca/6900/v0.7/factories/semi/SingleOwnerMSCAFactory.sol";
import {PluginManager} from "../../../../../../src/msca/6900/v0.7/managers/PluginManager.sol";
import {SingleOwnerPlugin} from "../../../../../../src/msca/6900/v0.7/plugins/v1_0_0/acl/SingleOwnerPlugin.sol";
import {PluginGasProfileBaseTest, UserOperation} from "../../../../PluginGasProfileBase.t.sol";

Expand Down Expand Up @@ -56,7 +54,7 @@ contract SingleOwnerMSCAWithSingleOwnerPluginTest is PluginGasProfileBaseTest {
function setUp() public override {
super.setUp();
accountAndPluginType = "SingleOwnerMSCAWithSingleOwnerPlugin";
factory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager));
factory = new SingleOwnerMSCAFactory(address(new SingleOwnerMSCA(entryPoint, pluginManager)));
singleOwnerPlugin = new SingleOwnerPlugin();
singleOwnerPluginAddr = address(singleOwnerPlugin);
}
Expand Down
2 changes: 1 addition & 1 deletion test/msca/6900/v0.7/SingleOwnerMSCA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ contract SingleOwnerMSCATest is TestUtils {
testERC1155 = new TestERC1155("getrich.com");
testERC721 = new TestERC721("getrich", "$$$");
testLiquidityPool = new TestLiquidityPool("getrich", "$$$");
factory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager));
factory = new SingleOwnerMSCAFactory(address(new SingleOwnerMSCA(entryPoint, pluginManager)));
// mock ERC1820Registry contract, could also use etch though, but I'm implementing a simplified registry
erc1820Registry = new MockERC1820Registry();
testERC777 = new TestERC777(erc1820Registry);
Expand Down
2 changes: 1 addition & 1 deletion test/msca/6900/v0.7/SingleOwnerMSCAFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ contract SingleOwnerMSCAFactoryTest is TestUtils {
address payable private beneficiary; // e.g. bundler

function setUp() public {
factory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager));
factory = new SingleOwnerMSCAFactory(address(new SingleOwnerMSCA(entryPoint, pluginManager)));
testLiquidityPool = new TestLiquidityPool("getrich", "$$$");
beneficiary = payable(address(makeAddr("bundler")));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ contract ColdStorageAddressBookPluginWithSemiMSCATest is TestUtils {

function setUp() public {
beneficiary = payable(address(makeAddr("bundler")));
factory = new SingleOwnerMSCAFactory(address(entryPoint), address(pluginManager));
factory = new SingleOwnerMSCAFactory(address(new SingleOwnerMSCA(entryPoint, pluginManager)));
addressBookPlugin = new ColdStorageAddressBookPlugin();

(ownerAddr, eoaPrivateKey) = makeAddrAndKey("ColdStorageAddressBookPluginWithSemiMSCATest");
Expand Down

0 comments on commit 9346945

Please sign in to comment.