Skip to content

Commit

Permalink
refactor: make create and create2 standard execution functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Zer0dot committed May 23, 2024
1 parent 920aad0 commit ba9f228
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 19 deletions.
19 changes: 14 additions & 5 deletions src/common/BaseLightAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,27 @@ abstract contract BaseLightAccount is BaseAccount, TokenCallbackHandler, UUPSUpg
/// @notice Creates a contract, this can only be called by this account.
/// @param initCode The initCode to deploy. NOTE: This could be replaced with transient storage in the near future,
/// depending on gas savings, if any.
function create(bytes calldata initCode) external payable virtual {
function create(bytes calldata initCode, uint256 value) external payable virtual onlyAuthorized {
assembly ("memory-safe") {
// Check that the caller is this account, this compiles to the same as inverting the condition
if iszero(eq(caller(), address())) {
mstore(0, 0x913e98f1) // OnlyCallableBySelf()
// Copy the initCode to memory, then deploy the contract
let len := initCode.length
calldatacopy(0, initCode.offset, len)
let succ := create(value, 0, len)

// If the creation fails, revert
if iszero(succ) {
mstore(0, 0x7e16b8cd) // CreateFailed()
revert(28, 4)
}
}
}

function create2(bytes calldata initCode, bytes32 salt, uint256 value) external payable virtual onlyAuthorized {
assembly ("memory-safe") {
// Copy the initCode to memory, then deploy the contract
let len := initCode.length
calldatacopy(0, initCode.offset, len)
let succ := create(callvalue(), 0, len)
let succ := create2(value, 0, len, salt)

// If the creation fails, revert
if iszero(succ) {
Expand Down
44 changes: 30 additions & 14 deletions test/LightAccount.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -477,35 +477,51 @@ contract LightAccountTest is Test {
assertEq(initialized, 1);
}

function testRevertCreateContract_IncorrectCaller() public {
vm.expectRevert(BaseLightAccount.OnlyCallableBySelf.selector);
account.create(hex"1234");
function testRevertCreate_IncorrectCaller() public {
vm.expectRevert(abi.encodeWithSelector(BaseLightAccount.NotAuthorized.selector, address(this)));
account.create(hex"1234", 0);
}

function testRevertCreateContract_CreateFailed() public {
function testRevertCreate_CreateFailed() public {
vm.prank(eoaAddress);
vm.expectRevert(BaseLightAccount.CreateFailed.selector);
account.execute(
address(account),
0,
abi.encodeCall(
account.create,
(hex"01") // Attempt to deploy a contract with a single "ADD" opcode as the whole initcode, which will revert.
(hex"01", 0) // Attempt to deploy a contract with a single "ADD" opcode as the whole initcode, which will revert.
)
);
}

function testCreateContract() public {
function testRevertCreate2_IncorrectCaller() public {
vm.expectRevert(abi.encodeWithSelector(BaseLightAccount.NotAuthorized.selector, address(this)));
account.create2(hex"1234", bytes32(0), 0);
}

function testRevertCreate2_CreateFailed() public {
vm.prank(eoaAddress);
vm.expectRevert(BaseLightAccount.CreateFailed.selector);
account.create2(hex"01", bytes32(0), 0);
}

function testCreate() public {
vm.prank(eoaAddress);
address expected = vm.computeCreateAddress(address(account), vm.getNonce(address(account)));
account.execute(
address(account),
0,
abi.encodeCall(
account.create, (abi.encodePacked(type(LightAccount).creationCode, abi.encode(address(0x4546b))))
)
);
assertEq(address(LightAccount(payable(expected)).entryPoint()), address(0x4546b));
account.create(abi.encodePacked(type(LightAccount).creationCode, abi.encode(address(entryPoint))), 0);
assertEq(address(LightAccount(payable(expected)).entryPoint()), address(entryPoint));
}

function testCreate2() public {
vm.prank(eoaAddress);
bytes memory initCode = abi.encodePacked(type(LightAccount).creationCode, abi.encode(address(entryPoint)));
bytes32 initCodeHash = keccak256(initCode);
bytes32 salt = bytes32(hex"04546b");
address expected = vm.computeCreate2Address(salt, initCodeHash, address(account));

account.create2(abi.encodePacked(type(LightAccount).creationCode, abi.encode(address(entryPoint))), salt, 0);
assertEq(address(LightAccount(payable(expected)).entryPoint()), address(entryPoint));
}

function _useContractOwner() internal {
Expand Down

0 comments on commit ba9f228

Please sign in to comment.