Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(v2): 4337 v0.7 updates #31

Merged
merged 1 commit into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.3.0
branch = v1
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
branch = release-v5.0
[submodule "lib/account-abstraction"]
path = lib/account-abstraction
url = https://github.com/eth-infinitism/account-abstraction
branch = releases/v0.7
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"solidity.packageDefaultDependenciesContractsDirectory": "src",
"solidity.packageDefaultDependenciesDirectory": "lib",
"solidity.compileUsingRemoteVersion": "v0.8.21",
"solidity.compileUsingRemoteVersion": "v0.8.23",
"editor.formatOnSave": true,
"[solidity]": {
"editor.defaultFormatter": "JuanBlanco.solidity"
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[profile.default]
solc = '0.8.21'
solc = '0.8.23'
evm_version = 'paris'
via_ir = true
src = 'src'
Expand Down
2 changes: 1 addition & 1 deletion lib/account-abstraction
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
2 changes: 1 addition & 1 deletion src/CustomSlotInitializable.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

/**
* @dev Identical to OpenZeppelin's `Initializable`, except that its state variables are kept at a custom storage slot
Expand Down
11 changes: 7 additions & 4 deletions src/LightAccount.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
Expand All @@ -8,11 +8,13 @@ pragma solidity ^0.8.21;
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

import {BaseAccount} from "account-abstraction/core/BaseAccount.sol";
import {SIG_VALIDATION_FAILED} from "account-abstraction/core/Helpers.sol";
import {IEntryPoint} from "account-abstraction/interfaces/IEntryPoint.sol";
import {UserOperation} from "account-abstraction/interfaces/UserOperation.sol";
import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
import {TokenCallbackHandler} from "account-abstraction/samples/callback/TokenCallbackHandler.sol";

import {CustomSlotInitializable} from "./CustomSlotInitializable.sol";
Expand Down Expand Up @@ -49,6 +51,7 @@ import {CustomSlotInitializable} from "./CustomSlotInitializable.sol";
*/
contract LightAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, CustomSlotInitializable, IERC1271 {
using ECDSA for bytes32;
using MessageHashUtils for bytes32;

// keccak256(abi.encode(uint256(keccak256("light_account_v1.storage")) - 1)) & ~bytes32(uint256(0xff));
bytes32 internal constant _STORAGE_POSITION = 0x691ec1a18226d004c07c9f8e5c4a6ff15a7b38db267cf7e3c945aef8be512200;
Expand Down Expand Up @@ -311,7 +314,7 @@ contract LightAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, Cus
* which the digest is wrapped with an "Ethereum Signed Message" envelope
* for the EOA-owner case but not in the ERC-1271 contract-owner case.
*/
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
function _validateSignature(PackedUserOperation calldata userOp, bytes32 userOpHash)
internal
virtual
override
Expand All @@ -320,7 +323,7 @@ contract LightAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, Cus
address _owner = owner();
bytes32 signedHash = userOpHash.toEthSignedMessageHash();
bytes memory signature = userOp.signature;
(address recovered, ECDSA.RecoverError error) = signedHash.tryRecover(signature);
(address recovered, ECDSA.RecoverError error,) = signedHash.tryRecover(signature);
if (
(error == ECDSA.RecoverError.NoError && recovered == _owner)
|| SignatureChecker.isValidERC1271SignatureNow(_owner, userOpHash, signature)
Expand Down
2 changes: 1 addition & 1 deletion src/LightAccountFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
Expand Down
2 changes: 1 addition & 1 deletion test/CustomSlotInitializable.t.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

import "forge-std/Test.sol";

Expand Down
48 changes: 28 additions & 20 deletions test/LightAccount.t.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

import "forge-std/Test.sol";

import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

import {EntryPoint} from "account-abstraction/core/EntryPoint.sol";
import {IEntryPoint} from "account-abstraction/interfaces/IEntryPoint.sol";
import {UserOperation} from "account-abstraction/interfaces/UserOperation.sol";
import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
import {SimpleAccount} from "account-abstraction/samples/SimpleAccount.sol";

import {LightAccount} from "../src/LightAccount.sol";
Expand All @@ -17,6 +18,7 @@ import {LightAccountFactory} from "../src/LightAccountFactory.sol";
contract LightAccountTest is Test {
using stdStorage for StdStorage;
using ECDSA for bytes32;
using MessageHashUtils for bytes32;

uint256 public constant EOA_PRIVATE_KEY = 1;
address payable public constant BENEFICIARY = payable(address(0xbe9ef1c1a2ee));
Expand Down Expand Up @@ -55,27 +57,27 @@ contract LightAccountTest is Test {
}

function testExecuteCanBeCalledByEntryPointWithExternalOwner() public {
UserOperation memory op =
PackedUserOperation memory op =
_getSignedOp(address(lightSwitch), abi.encodeCall(LightSwitch.turnOn, ()), EOA_PRIVATE_KEY);
UserOperation[] memory ops = new UserOperation[](1);
PackedUserOperation[] memory ops = new PackedUserOperation[](1);
ops[0] = op;
entryPoint.handleOps(ops, BENEFICIARY);
assertTrue(lightSwitch.on());
}

function testExecutedCanBeCalledByEntryPointWithContractOwner() public {
_useContractOwner();
UserOperation memory op = _getUnsignedOp(address(lightSwitch), abi.encodeCall(LightSwitch.turnOn, ()));
PackedUserOperation memory op = _getUnsignedOp(address(lightSwitch), abi.encodeCall(LightSwitch.turnOn, ()));
op.signature = contractOwner.sign(entryPoint.getUserOpHash(op));
UserOperation[] memory ops = new UserOperation[](1);
PackedUserOperation[] memory ops = new PackedUserOperation[](1);
ops[0] = op;
entryPoint.handleOps(ops, BENEFICIARY);
assertTrue(lightSwitch.on());
}

function testRejectsUserOpsWithInvalidSignature() public {
UserOperation memory op = _getSignedOp(address(lightSwitch), abi.encodeCall(LightSwitch.turnOn, ()), 1234);
UserOperation[] memory ops = new UserOperation[](1);
PackedUserOperation memory op = _getSignedOp(address(lightSwitch), abi.encodeCall(LightSwitch.turnOn, ()), 1234);
PackedUserOperation[] memory ops = new PackedUserOperation[](1);
ops[0] = op;
vm.expectRevert(abi.encodeWithSelector(IEntryPoint.FailedOp.selector, 0, "AA24 signature error"));
entryPoint.handleOps(ops, BENEFICIARY);
Expand Down Expand Up @@ -184,9 +186,9 @@ contract LightAccountTest is Test {

function testEntryPointCanTransferOwnership() public {
address newOwner = address(0x100);
UserOperation memory op =
PackedUserOperation memory op =
_getSignedOp(address(account), abi.encodeCall(LightAccount.transferOwnership, (newOwner)), EOA_PRIVATE_KEY);
UserOperation[] memory ops = new UserOperation[](1);
PackedUserOperation[] memory ops = new PackedUserOperation[](1);
ops[0] = op;
vm.expectEmit(true, true, false, false);
emit OwnershipTransferred(eoaAddress, newOwner);
Expand Down Expand Up @@ -282,10 +284,10 @@ contract LightAccountTest is Test {
keccak256(
abi.encodePacked(
type(LightAccountFactory).creationCode,
bytes32(uint256(uint160(0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789)))
bytes32(uint256(uint160(0x0000000071727De22E5E9d8BAf0edAc6f37da032)))
Copy link
Contributor

Choose a reason for hiding this comment

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

We can replace this line with just abi.encode(<EntryPoint address>) to avoid dealing with the type conversions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ack, will fix up the stack.

)
),
0x23fb754854a6aa03057b1bae5d971963d92e534dc714fa59fff6c08a3617ba3e
0xbb16617edd0a177192b9a37ddb37f7783ae99a0cd21d53607df759ded54e024c
);
}

Expand All @@ -294,17 +296,23 @@ contract LightAccountTest is Test {
account.transferOwnership(address(contractOwner));
}

function _getUnsignedOp(address target, bytes memory innerCallData) internal view returns (UserOperation memory) {
return UserOperation({
function _getUnsignedOp(address target, bytes memory innerCallData)
internal
view
returns (PackedUserOperation memory)
{
uint128 verificationGasLimit = 1 << 24;
uint128 callGasLimit = 1 << 24;
uint128 maxPriorityFeePerGas = 1 << 8;
uint128 maxFeePerGas = 1 << 8;
return PackedUserOperation({
sender: address(account),
nonce: 0,
initCode: "",
callData: abi.encodeCall(LightAccount.execute, (target, 0, innerCallData)),
callGasLimit: 1 << 24,
verificationGasLimit: 1 << 24,
accountGasLimits: bytes32(uint256(verificationGasLimit) << 128 | callGasLimit),
preVerificationGas: 1 << 24,
maxFeePerGas: 1 << 8,
maxPriorityFeePerGas: 1 << 8,
gasFees: bytes32(uint256(maxPriorityFeePerGas) << 128 | maxFeePerGas),
paymasterAndData: "",
signature: ""
});
Expand All @@ -313,9 +321,9 @@ contract LightAccountTest is Test {
function _getSignedOp(address target, bytes memory innerCallData, uint256 privateKey)
internal
view
returns (UserOperation memory)
returns (PackedUserOperation memory)
{
UserOperation memory op = _getUnsignedOp(target, innerCallData);
PackedUserOperation memory op = _getUnsignedOp(target, innerCallData);
op.signature = _sign(privateKey, entryPoint.getUserOpHash(op).toEthSignedMessageHash());
return op;
}
Expand Down
2 changes: 1 addition & 1 deletion test/LightAccountFactory.t.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;
pragma solidity ^0.8.23;

import "forge-std/Test.sol";

Expand Down
Loading