Skip to content

Commit

Permalink
feat: 4337 v0.7 updates
Browse files Browse the repository at this point in the history
  • Loading branch information
jaypaik committed Mar 10, 2024
1 parent 3898ebc commit 4b1bb9d
Show file tree
Hide file tree
Showing 13 changed files with 49 additions and 36 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: nightly-de33b6af53005037b463318d2628b5cfcaf39916
- run: forge install

- run: forge fmt --check
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: nightly-de33b6af53005037b463318d2628b5cfcaf39916

- name: Install forge dependencies
run: forge install
Expand Down
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)))
)
),
0x23fb754854a6aa03057b1bae5d971963d92e534dc714fa59fff6c08a3617ba3e
0x3bc154d32c096215e957ca99af52e83275464261e8cbe90d8da1df052c89947a
);
}

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

0 comments on commit 4b1bb9d

Please sign in to comment.