From 937b338a867644eac3d0f17f712662c74b487c1b Mon Sep 17 00:00:00 2001 From: Wilson Cusack Date: Sun, 10 Mar 2024 19:31:23 -0400 Subject: [PATCH 1/3] exploring gas of using oz --- .gas-snapshot | 52 +++++++++---------- .gitmodules | 3 ++ lib/openzeppelin-contracts | 1 + src/CoinbaseSmartWallet.sol | 11 ++-- src/CoinbaseSmartWalletFactory.sol | 20 ++++--- .../ExecuteWithoutChainIdValidation.t.sol | 2 +- .../IsValidSignature.t.sol | 2 + 7 files changed, 50 insertions(+), 41 deletions(-) create mode 160000 lib/openzeppelin-contracts diff --git a/.gas-snapshot b/.gas-snapshot index 9ae8948..83e6fd9 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,14 +10,14 @@ AddOwnerPublicKeyTest:testRevertsIfAlreadyOwner() (gas: 116301) AddOwnerPublicKeyTest:testRevertsIfCalledByNonOwner() (gas: 11744) AddOwnerPublicKeyTest:testSetsIsOwner() (gas: 113775) AddOwnerPublicKeyTest:testSetsOwnerAtIndex() (gas: 128543) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 308664) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 291435) -CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 267742) -CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 287406) -CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 269093) -CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 277981) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 283108) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 265831) +CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 249076) +CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 261498) +CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 250379) +CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 259033) CoinbaseSmartWalletFactoryTest:test_revertsIfNoOwners() (gas: 29214) -ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 15406) +ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 13194) MultiOwnableInitializeTest:testRevertsIfLength32ButLargerThanAddress() (gas: 78927) MultiOwnableInitializeTest:testRevertsIfLength32NotAddress() (gas: 78908) MultiOwnableInitializeTest:testRevertsIfLengthNot32Or64() (gas: 101211) @@ -28,25 +28,25 @@ RemoveOwnerAtIndexTest:testRevertsIfCalledByNonOwner() (gas: 11332) RemoveOwnerAtIndexTest:testRevertsIfNoOwnerAtIndex() (gas: 16648) TestCanSkipChainIdValidation:test_approvedSelectorsReturnTrue() (gas: 15845) TestCanSkipChainIdValidation:test_otherSelectorsReturnFalse() (gas: 12469) -TestExecuteWithoutChainIdValidation:testExecute() (gas: 424705) -TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729086) -TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3409748, ~: 3278930) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49006) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49241) -TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 287917) -TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220047) -TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8620) +TestExecuteWithoutChainIdValidation:testExecute() (gas: 424839) +TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729083) +TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3578478, ~: 3434647) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49775) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 50010) +TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 288312) +TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220443) +TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8598) TestExecuteWithoutChainIdValidation:test_revertsIfWrongNonceKey() (gas: 62275) TestExecuteWithoutChainIdValidation:test_revertsWithReservedNonce() (gas: 82302) TestInitialize:testInitialize() (gas: 21122) -TestInitialize:test_cannotInitImplementation() (gas: 2708253) -TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 39497) -TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24068) -TestIsValidSignature:testSmartWalletSigner() (gas: 2981137) -TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 24950) -TestIsValidSignature:testValidateSignatureWithEOASignerFailsWithWrongSigner() (gas: 23880) -TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421284) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34986) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428750) -TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 23839) -TestValidateUserOp:testValidateUserOp() (gas: 447113) \ No newline at end of file +TestInitialize:test_cannotInitImplementation() (gas: 2860579) +TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 42452) +TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24046) +TestIsValidSignature:testSmartWalletSigner() (gas: 3139037) +TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 25347) +TestIsValidSignature:testValidateSignatureWithEOASignerFailsWithWrongSigner() (gas: 25481) +TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421262) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34964) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428728) +TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 38915) +TestValidateUserOp:testValidateUserOp() (gas: 449222) \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 147bd38..7d14d19 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "lib/webauthn-sol"] path = lib/webauthn-sol url = https://github.com/base-org/webauthn-sol +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/openzeppelin/openzeppelin-contracts diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 0000000..dbb6104 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/src/CoinbaseSmartWallet.sol b/src/CoinbaseSmartWallet.sol index 4556be1..018f8df 100644 --- a/src/CoinbaseSmartWallet.sol +++ b/src/CoinbaseSmartWallet.sol @@ -2,8 +2,9 @@ pragma solidity 0.8.23; import {Receiver} from "solady/accounts/Receiver.sol"; -import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; -import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol"; +import {UUPSUpgradeable} from "openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol"; +import {ERC1967Utils} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import {SignatureChecker} from "openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol"; import {UserOperation, UserOperationLib} from "account-abstraction/interfaces/UserOperation.sol"; import {WebAuthn} from "webauthn-sol/WebAuthn.sol"; @@ -209,6 +210,10 @@ contract CoinbaseSmartWallet is MultiOwnable, UUPSUpgradeable, Receiver, ERC1271 } } + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } + /// @notice Returns the address of the EntryPoint v0.6. /// /// @return The address of the EntryPoint v0.6 @@ -302,7 +307,7 @@ contract CoinbaseSmartWallet is MultiOwnable, UUPSUpgradeable, Receiver, ERC1271 owner := mload(add(ownerBytes, 32)) } - return SignatureCheckerLib.isValidSignatureNow(owner, message, sigWrapper.signatureData); + return SignatureChecker.isValidSignatureNow(owner, message, sigWrapper.signatureData); } if (ownerBytes.length == 64) { diff --git a/src/CoinbaseSmartWalletFactory.sol b/src/CoinbaseSmartWalletFactory.sol index 2251cba..2c8dae6 100644 --- a/src/CoinbaseSmartWalletFactory.sol +++ b/src/CoinbaseSmartWalletFactory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {LibClone} from "solady/utils/LibClone.sol"; +import {Clones} from "openzeppelin-contracts/contracts/proxy/Clones.sol"; import {CoinbaseSmartWallet} from "./CoinbaseSmartWallet.sol"; /// @title Coinbase Smart Wallet Factory @@ -31,24 +31,22 @@ contract CoinbaseSmartWalletFactory { revert OwnerRequired(); } - (bool alreadyDeployed, address accountAddress) = - LibClone.createDeterministicERC1967(msg.value, implementation, _getSalt(owners, nonce)); + bytes32 salt = _getSalt(owners, nonce); + address accountAddress = Clones.predictDeterministicAddress(implementation, salt, address(this)); account = CoinbaseSmartWallet(payable(accountAddress)); - if (alreadyDeployed == false) { - account.initialize(owners); + if (address(account).code.length > 0) { + return account; } + + Clones.cloneDeterministic(implementation, salt); + account.initialize{value: msg.value}(owners); } /// @dev Returns the deterministic address of the account created via `createAccount`. function getAddress(bytes[] calldata owners, uint256 nonce) external view returns (address predicted) { - predicted = LibClone.predictDeterministicAddress(initCodeHash(), _getSalt(owners, nonce), address(this)); - } - - /// @dev Returns the initialization code hash of the ERC4337 account (a minimal ERC1967 proxy). - function initCodeHash() public view virtual returns (bytes32 result) { - result = LibClone.initCodeHashERC1967(implementation); + predicted = Clones.predictDeterministicAddress(implementation, _getSalt(owners, nonce), address(this)); } /// @dev Returns the salt that will be used for deterministic address diff --git a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol index 3c2084d..9c1e2c3 100644 --- a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol +++ b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol @@ -42,7 +42,7 @@ contract TestExecuteWithoutChainIdValidation is SmartWalletTestBase { UserOperation memory userOp = _getUserOpWithSignature(); vm.expectEmit(true, true, true, true); emit IEntryPoint.UserOperationEvent( - entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48027 + entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48423 ); _sendUserOperation(userOp); } diff --git a/test/CoinbaseSmartWallet/IsValidSignature.t.sol b/test/CoinbaseSmartWallet/IsValidSignature.t.sol index 156934c..f9a80d4 100644 --- a/test/CoinbaseSmartWallet/IsValidSignature.t.sol +++ b/test/CoinbaseSmartWallet/IsValidSignature.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol"; + import "./SmartWalletTestBase.sol"; import "webauthn-sol/../test/Utils.sol"; From 154a4772428134808cbc1ced8ab499fe0f600499 Mon Sep 17 00:00:00 2001 From: Wilson Cusack Date: Sun, 10 Mar 2024 22:10:03 -0400 Subject: [PATCH 2/3] use solady uups --- .gas-snapshot | 50 +++++++++---------- src/CoinbaseSmartWallet.sol | 7 +-- .../ExecuteWithoutChainIdValidation.t.sol | 2 +- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 83e6fd9..dcef5c2 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,14 +10,14 @@ AddOwnerPublicKeyTest:testRevertsIfAlreadyOwner() (gas: 116301) AddOwnerPublicKeyTest:testRevertsIfCalledByNonOwner() (gas: 11744) AddOwnerPublicKeyTest:testSetsIsOwner() (gas: 113775) AddOwnerPublicKeyTest:testSetsOwnerAtIndex() (gas: 128543) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 283108) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 265831) -CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 249076) -CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 261498) -CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 250379) -CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 259033) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 283130) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 265853) +CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 249098) +CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 261520) +CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 250401) +CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 259099) CoinbaseSmartWalletFactoryTest:test_revertsIfNoOwners() (gas: 29214) -ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 13194) +ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 13216) MultiOwnableInitializeTest:testRevertsIfLength32ButLargerThanAddress() (gas: 78927) MultiOwnableInitializeTest:testRevertsIfLength32NotAddress() (gas: 78908) MultiOwnableInitializeTest:testRevertsIfLengthNot32Or64() (gas: 101211) @@ -28,25 +28,25 @@ RemoveOwnerAtIndexTest:testRevertsIfCalledByNonOwner() (gas: 11332) RemoveOwnerAtIndexTest:testRevertsIfNoOwnerAtIndex() (gas: 16648) TestCanSkipChainIdValidation:test_approvedSelectorsReturnTrue() (gas: 15845) TestCanSkipChainIdValidation:test_otherSelectorsReturnFalse() (gas: 12469) -TestExecuteWithoutChainIdValidation:testExecute() (gas: 424839) -TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729083) -TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3578478, ~: 3434647) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49775) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 50010) -TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 288312) -TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220443) -TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8598) +TestExecuteWithoutChainIdValidation:testExecute() (gas: 424705) +TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729086) +TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3487945, ~: 3356582) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49393) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49628) +TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 288335) +TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220465) +TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8620) TestExecuteWithoutChainIdValidation:test_revertsIfWrongNonceKey() (gas: 62275) TestExecuteWithoutChainIdValidation:test_revertsWithReservedNonce() (gas: 82302) TestInitialize:testInitialize() (gas: 21122) -TestInitialize:test_cannotInitImplementation() (gas: 2860579) -TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 42452) -TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24046) -TestIsValidSignature:testSmartWalletSigner() (gas: 3139037) -TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 25347) +TestInitialize:test_cannotInitImplementation() (gas: 2785838) +TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 42474) +TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24068) +TestIsValidSignature:testSmartWalletSigner() (gas: 3061110) +TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 25369) TestIsValidSignature:testValidateSignatureWithEOASignerFailsWithWrongSigner() (gas: 25481) -TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421262) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34964) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428728) -TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 38915) -TestValidateUserOp:testValidateUserOp() (gas: 449222) \ No newline at end of file +TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421284) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34986) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428750) +TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 40944) +TestValidateUserOp:testValidateUserOp() (gas: 449132) \ No newline at end of file diff --git a/src/CoinbaseSmartWallet.sol b/src/CoinbaseSmartWallet.sol index 018f8df..0fa9099 100644 --- a/src/CoinbaseSmartWallet.sol +++ b/src/CoinbaseSmartWallet.sol @@ -2,8 +2,7 @@ pragma solidity 0.8.23; import {Receiver} from "solady/accounts/Receiver.sol"; -import {UUPSUpgradeable} from "openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol"; -import {ERC1967Utils} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; import {SignatureChecker} from "openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol"; import {UserOperation, UserOperationLib} from "account-abstraction/interfaces/UserOperation.sol"; import {WebAuthn} from "webauthn-sol/WebAuthn.sol"; @@ -210,10 +209,6 @@ contract CoinbaseSmartWallet is MultiOwnable, UUPSUpgradeable, Receiver, ERC1271 } } - function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { - ERC1967Utils.upgradeToAndCall(newImplementation, data); - } - /// @notice Returns the address of the EntryPoint v0.6. /// /// @return The address of the EntryPoint v0.6 diff --git a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol index 9c1e2c3..1ae3a6d 100644 --- a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol +++ b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol @@ -42,7 +42,7 @@ contract TestExecuteWithoutChainIdValidation is SmartWalletTestBase { UserOperation memory userOp = _getUserOpWithSignature(); vm.expectEmit(true, true, true, true); emit IEntryPoint.UserOperationEvent( - entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48423 + entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48445 ); _sendUserOperation(userOp); } From 016619b36fcd549853fded5f87b7640483502b1e Mon Sep 17 00:00:00 2001 From: Wilson Cusack Date: Mon, 11 Mar 2024 09:42:36 -0400 Subject: [PATCH 3/3] fix proxy --- .gas-snapshot | 50 +++++++++---------- src/CoinbaseSmartWallet.sol | 2 +- src/CoinbaseSmartWalletFactory.sol | 14 ++++-- .../ExecuteWithoutChainIdValidation.t.sol | 2 +- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index dcef5c2..bc29664 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,14 +10,14 @@ AddOwnerPublicKeyTest:testRevertsIfAlreadyOwner() (gas: 116301) AddOwnerPublicKeyTest:testRevertsIfCalledByNonOwner() (gas: 11744) AddOwnerPublicKeyTest:testSetsIsOwner() (gas: 113775) AddOwnerPublicKeyTest:testSetsOwnerAtIndex() (gas: 128543) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 283130) -CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 265853) -CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 249098) -CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 261520) -CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 250401) -CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 259099) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForDeployedAccount() (gas: 337995) +CoinbaseSmartWallet1271InputGeneratorTest:testGetReplaySafeHashForUndeployedAccount() (gas: 324408) +CoinbaseSmartWalletFactoryTest:testDeployDeterministicPassValues() (gas: 303902) +CoinbaseSmartWalletFactoryTest:test_CreateAccount_ReturnsPredeterminedAddress_WhenAccountAlreadyExists() (gas: 324950) +CoinbaseSmartWalletFactoryTest:test_createAccountDeploysToPredeterminedAddress() (gas: 308896) +CoinbaseSmartWalletFactoryTest:test_createAccountSetsOwnersCorrectly() (gas: 317992) CoinbaseSmartWalletFactoryTest:test_revertsIfNoOwners() (gas: 29214) -ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 13216) +ERC1271Test:test_returnsExpectedDomainHashWhenProxy() (gas: 15636) MultiOwnableInitializeTest:testRevertsIfLength32ButLargerThanAddress() (gas: 78927) MultiOwnableInitializeTest:testRevertsIfLength32NotAddress() (gas: 78908) MultiOwnableInitializeTest:testRevertsIfLengthNot32Or64() (gas: 101211) @@ -28,25 +28,25 @@ RemoveOwnerAtIndexTest:testRevertsIfCalledByNonOwner() (gas: 11332) RemoveOwnerAtIndexTest:testRevertsIfNoOwnerAtIndex() (gas: 16648) TestCanSkipChainIdValidation:test_approvedSelectorsReturnTrue() (gas: 15845) TestCanSkipChainIdValidation:test_otherSelectorsReturnFalse() (gas: 12469) -TestExecuteWithoutChainIdValidation:testExecute() (gas: 424705) -TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729086) -TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3487945, ~: 3356582) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49393) -TestExecuteWithoutChainIdValidation:test__codesize() (gas: 49628) -TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 288335) -TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220465) -TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8620) +TestExecuteWithoutChainIdValidation:testExecute() (gas: 424839) +TestExecuteWithoutChainIdValidation:testExecuteBatch() (gas: 729083) +TestExecuteWithoutChainIdValidation:testExecuteBatch(uint256) (runs: 256, μ: 3663189, ~: 3665261) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 50164) +TestExecuteWithoutChainIdValidation:test__codesize() (gas: 50399) +TestExecuteWithoutChainIdValidation:test_canChangeOwnerWithoutChainId() (gas: 288312) +TestExecuteWithoutChainIdValidation:test_cannotCallExec() (gas: 220443) +TestExecuteWithoutChainIdValidation:test_revertsIfCallerNotEntryPoint() (gas: 8598) TestExecuteWithoutChainIdValidation:test_revertsIfWrongNonceKey() (gas: 62275) TestExecuteWithoutChainIdValidation:test_revertsWithReservedNonce() (gas: 82302) TestInitialize:testInitialize() (gas: 21122) -TestInitialize:test_cannotInitImplementation() (gas: 2785838) -TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 42474) -TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24068) -TestIsValidSignature:testSmartWalletSigner() (gas: 3061110) -TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 25369) +TestInitialize:test_cannotInitImplementation() (gas: 2935795) +TestIsValidSignature:testReturnsInvalidIfPasskeySigButWrongOwnerLength() (gas: 42452) +TestIsValidSignature:testRevertsIfEthereumSignatureButWrongOwnerLength() (gas: 24046) +TestIsValidSignature:testSmartWalletSigner() (gas: 3214255) +TestIsValidSignature:testValidateSignatureWithEOASigner() (gas: 25347) TestIsValidSignature:testValidateSignatureWithEOASignerFailsWithWrongSigner() (gas: 25481) -TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421284) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34986) -TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428750) -TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 40944) -TestValidateUserOp:testValidateUserOp() (gas: 449132) \ No newline at end of file +TestIsValidSignature:testValidateSignatureWithPasskeySigner() (gas: 421262) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsBadOwnerIndex() (gas: 34964) +TestIsValidSignature:testValidateSignatureWithPasskeySignerFailsWithWrongBadSignature() (gas: 428728) +TestUpgradeToAndCall:testUpgradeToAndCall() (gas: 25793) +TestValidateUserOp:testValidateUserOp() (gas: 449222) \ No newline at end of file diff --git a/src/CoinbaseSmartWallet.sol b/src/CoinbaseSmartWallet.sol index 0fa9099..545a488 100644 --- a/src/CoinbaseSmartWallet.sol +++ b/src/CoinbaseSmartWallet.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import {Receiver} from "solady/accounts/Receiver.sol"; -import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; +import {UUPSUpgradeable} from "openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol"; import {SignatureChecker} from "openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol"; import {UserOperation, UserOperationLib} from "account-abstraction/interfaces/UserOperation.sol"; import {WebAuthn} from "webauthn-sol/WebAuthn.sol"; diff --git a/src/CoinbaseSmartWalletFactory.sol b/src/CoinbaseSmartWalletFactory.sol index 2c8dae6..7cd6494 100644 --- a/src/CoinbaseSmartWalletFactory.sol +++ b/src/CoinbaseSmartWalletFactory.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {Clones} from "openzeppelin-contracts/contracts/proxy/Clones.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; import {CoinbaseSmartWallet} from "./CoinbaseSmartWallet.sol"; /// @title Coinbase Smart Wallet Factory @@ -32,7 +33,7 @@ contract CoinbaseSmartWalletFactory { } bytes32 salt = _getSalt(owners, nonce); - address accountAddress = Clones.predictDeterministicAddress(implementation, salt, address(this)); + address accountAddress = getAddress(owners, nonce); account = CoinbaseSmartWallet(payable(accountAddress)); @@ -40,13 +41,16 @@ contract CoinbaseSmartWalletFactory { return account; } - Clones.cloneDeterministic(implementation, salt); + new ERC1967Proxy{salt: salt}(implementation, ""); account.initialize{value: msg.value}(owners); } /// @dev Returns the deterministic address of the account created via `createAccount`. - function getAddress(bytes[] calldata owners, uint256 nonce) external view returns (address predicted) { - predicted = Clones.predictDeterministicAddress(implementation, _getSalt(owners, nonce), address(this)); + function getAddress(bytes[] calldata owners, uint256 nonce) public view returns (address predicted) { + predicted = Create2.computeAddress( + _getSalt(owners, nonce), + keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(implementation, ""))) + ); } /// @dev Returns the salt that will be used for deterministic address diff --git a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol index 1ae3a6d..9c1e2c3 100644 --- a/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol +++ b/test/CoinbaseSmartWallet/ExecuteWithoutChainIdValidation.t.sol @@ -42,7 +42,7 @@ contract TestExecuteWithoutChainIdValidation is SmartWalletTestBase { UserOperation memory userOp = _getUserOpWithSignature(); vm.expectEmit(true, true, true, true); emit IEntryPoint.UserOperationEvent( - entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48445 + entryPoint.getUserOpHash(userOp), userOp.sender, address(0), userOp.nonce, false, 0, 48423 ); _sendUserOperation(userOp); }