Skip to content
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: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ solc_version = '0.8.19'
bytecode_hash = "none"
cbor_metadata = false
optimize = true
via-ir = false
via-ir = true
runs = 1000000

gas_reports=["Kernel","KernelFactory"]
gas_reports=["Kernel","KernelLiteECDSA","KernelFactory"]

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
40 changes: 40 additions & 0 deletions gas/ecdsa/report-lite.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
No files changed, compilation skipped

Running 8 tests for test/foundry/KernelLite.t.sol:KernelTest
[PASS] test_disable_mode() (gas: 171425)
[PASS] test_external_call_default() (gas: 22953)
[PASS] test_external_call_execution() (gas: 439687)
[PASS] test_initialize_twice() (gas: 20968)
[PASS] test_set_default_validator() (gas: 369789)
[PASS] test_set_execution() (gas: 400852)
[PASS] test_validate_signature() (gas: 139666)
[PASS] test_validate_userOp() (gas: 1733019)
Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.73ms
| src/factory/KernelFactory.sol:KernelFactory contract | | | | | |
|------------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 594023 | 3050 | | | | |
| Function Name | min | avg | median | max | # calls |
| createAccount | 106913 | 107413 | 106913 | 111413 | 9 |
| deployDeterministicAndCall | 105350 | 105627 | 105350 | 107850 | 9 |
| setImplementation | 22862 | 22862 | 22862 | 22862 | 8 |


| src/lite/KernelLiteECDSA.sol:KernelLiteECDSA contract | | | | | |
|-------------------------------------------------------|-----------------|-------|--------|-------|---------|
| Deployment Cost | Deployment Size | | | | |
| 1598398 | 8392 | | | | |
| Function Name | min | avg | median | max | # calls |
| disableMode | 22865 | 22865 | 22865 | 22865 | 1 |
| getDefaultValidator | 341 | 341 | 341 | 341 | 1 |
| getDisabledMode | 577 | 577 | 577 | 577 | 1 |
| getExecution | 1249 | 1249 | 1249 | 1249 | 2 |
| initialize | 3117 | 21073 | 23069 | 23069 | 10 |
| isValidSignature | 8587 | 8587 | 8587 | 8587 | 1 |
| setDefaultValidator | 26774 | 26774 | 26774 | 26774 | 1 |
| setExecution | 49853 | 49853 | 49853 | 49853 | 2 |
| validateUserOp | 36049 | 36049 | 36049 | 36049 | 4 |



Ran 1 test suites: 8 tests passed, 0 failed, 0 skipped (8 total tests)
33 changes: 22 additions & 11 deletions gas/ecdsa/report.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
No files changed, compilation skipped

Running 7 tests for test/foundry/Kernel.t.sol:KernelTest
[PASS] test_disable_mode() (gas: 162879)
[PASS] test_external_call_default() (gas: 28845)
[PASS] test_external_call_execution() (gas: 453354)
[PASS] test_initialize_twice() (gas: 20840)
Running 8 tests for test/foundry/Kernel.t.sol:KernelTest
[PASS] test_disable_mode() (gas: 162901)
[PASS] test_external_call_default() (gas: 28867)
[PASS] test_external_call_execution() (gas: 453376)
[PASS] test_initialize_twice() (gas: 20885)
[PASS] test_set_default_validator() (gas: 361374)
[PASS] test_set_execution() (gas: 411689)
[PASS] test_validate_signature() (gas: 165811)
Test result: ok. 7 passed; 0 failed; 0 skipped; finished in 2.67ms
[PASS] test_set_execution() (gas: 411711)
[PASS] test_validate_signature() (gas: 164810)
[PASS] test_validate_userOp() (gas: 1729466)
Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.77ms
| src/Kernel.sol:Kernel contract | | | | | |
|--------------------------------|-----------------|-------|--------|-------|---------|
| Deployment Cost | Deployment Size | | | | |
| 1590591 | 8353 | | | | |
| 1586591 | 8333 | | | | |
| Function Name | min | avg | median | max | # calls |
| disableMode | 3765 | 3765 | 3765 | 3765 | 1 |
| getDefaultValidator | 341 | 341 | 341 | 341 | 1 |
| getDisabledMode | 577 | 577 | 577 | 577 | 1 |
| getExecution | 1249 | 1249 | 1249 | 1249 | 2 |
| initialize | 3083 | 44928 | 49847 | 52347 | 9 |
| initialize | 3046 | 43982 | 48253 | 50753 | 10 |
| isValidSignature | 6047 | 6047 | 6047 | 6047 | 1 |
| setDefaultValidator | 7870 | 7870 | 7870 | 7870 | 1 |
| setExecution | 49877 | 49877 | 49877 | 49877 | 2 |
| validateUserOp | 46040 | 46234 | 46256 | 46386 | 4 |


| src/factory/KernelFactory.sol:KernelFactory contract | | | | | |
|------------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 594023 | 3050 | | | | |
| Function Name | min | avg | median | max | # calls |
| createAccount | 132097 | 132874 | 132097 | 139097 | 9 |
| deployDeterministicAndCall | 130534 | 131089 | 130534 | 135534 | 9 |
| setImplementation | 22862 | 22862 | 22862 | 22862 | 8 |

Ran 1 test suites: 7 tests passed, 0 failed, 0 skipped (7 total tests)


Ran 1 test suites: 8 tests passed, 0 failed, 0 skipped (8 total tests)
2 changes: 2 additions & 0 deletions gas/gas_report.sh
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
forge build
forge test --gas-report --match-path test/foundry/Kernel.t.sol > gas/ecdsa/report.txt
forge test --gas-report --match-path test/foundry/KernelLite.t.sol > gas/ecdsa/report-lite.txt
7 changes: 3 additions & 4 deletions src/Kernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,21 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
/// @param value The amount of Ether to send
/// @param data The call data to be sent
/// @param operation The type of operation (call or delegatecall)
function execute(address to, uint256 value, bytes calldata data, Operation operation) external payable {
function execute(address to, uint256 value, bytes memory data, Operation operation) external payable {
if (msg.sender != address(entryPoint) && !_checkCaller()) {
revert NotAuthorizedCaller();
}
bytes memory callData = data;
if (operation == Operation.DelegateCall) {
assembly {
let success := delegatecall(gas(), to, add(callData, 0x20), mload(callData), 0, 0)
let success := delegatecall(gas(), to, add(data, 0x20), mload(data), 0, 0)
returndatacopy(0, 0, returndatasize())
switch success
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
} else {
assembly {
let success := call(gas(), to, value, add(callData, 0x20), mload(callData), 0, 0)
let success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0)
returndatacopy(0, 0, returndatasize())
switch success
case 0 { revert(0, returndatasize()) }
Expand Down
20 changes: 13 additions & 7 deletions src/abstract/KernelStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ contract KernelStorage {

// Function to initialize the wallet kernel
function initialize(IKernelValidator _defaultValidator, bytes calldata _data) external payable {
WalletKernelStorage storage ws = getKernelStorage();
if (address(ws.defaultValidator) != address(0)) {
revert AlreadyInitialized();
}
ws.defaultValidator = _defaultValidator;
emit DefaultValidatorChanged(address(0), address(_defaultValidator));
_defaultValidator.enable(_data);
_setInitialData(_defaultValidator, _data);
}

// Function to get the wallet kernel storage
Expand Down Expand Up @@ -161,4 +155,16 @@ contract KernelStorage {
getKernelStorage().disabledMode = _disableFlag;
getKernelStorage().lastDisabledTime = uint48(block.timestamp);
}

function _setInitialData(IKernelValidator _defaultValidator, bytes calldata _data) internal virtual {
address validator;
assembly {
validator := shr(80, sload(KERNEL_STORAGE_SLOT_1))
}
if (address(validator) != address(0)) {
revert AlreadyInitialized();
}
getKernelStorage().defaultValidator = _defaultValidator;
_defaultValidator.enable(_data);
}
}
25 changes: 0 additions & 25 deletions src/factory/ECDSAKernelFactory.sol

This file was deleted.

32 changes: 16 additions & 16 deletions src/factory/KernelFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,36 @@ import "./AdminLessERC1967Factory.sol";
import "openzeppelin-contracts/contracts/utils/Create2.sol";
import "src/Kernel.sol";
import "src/validator/ECDSAValidator.sol";
import "solady/auth/Ownable.sol";

contract KernelFactory {
AdminLessERC1967Factory public immutable erc1967factory;
Kernel public immutable kernelTemplate;
IEntryPoint public immutable entryPoint;
contract KernelFactory is AdminLessERC1967Factory, Ownable{

event AccountCreated(address indexed account, address indexed validator, bytes data, uint256 index);
mapping(address => bool) public isAllowedImplementation;

constructor(AdminLessERC1967Factory _erc1967factory, IEntryPoint _entryPoint) {
erc1967factory = _erc1967factory;
entryPoint = _entryPoint;
kernelTemplate = new Kernel(_entryPoint);
constructor(address _owner) {
_initializeOwner(_owner);
}

function createAccount(IKernelValidator _validator, bytes calldata _data, uint256 _index)
function setImplementation(address _implementation, bool _allow) external onlyOwner {
isAllowedImplementation[_implementation] = _allow;
}

function createAccount(address _implementation, bytes calldata _data, uint256 _index)
external
payable
returns (address proxy)
{
bytes memory initData = abi.encodeWithSelector(KernelStorage.initialize.selector, _validator, _data);
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_validator, _data, _index))) & type(uint96).max);
proxy = erc1967factory.deployDeterministicAndCall(address(kernelTemplate), salt, initData);
require(isAllowedImplementation[_implementation], "KernelFactory: implementation not allowed");
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_data, _index))) & type(uint96).max);
proxy = this.deployDeterministicAndCall(_implementation, salt, _data);
}

function getAccountAddress(IKernelValidator _validator, bytes calldata _data, uint256 _index)
function getAccountAddress(bytes calldata _data, uint256 _index)
public
view
returns (address)
{
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_validator, _data, _index))) & type(uint96).max);
return erc1967factory.predictDeterministicAddress(salt);
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_data, _index))) & type(uint96).max);
return predictDeterministicAddress(salt);
}
}
88 changes: 0 additions & 88 deletions src/factory/MultiECDSAKernelFactory.sol

This file was deleted.

18 changes: 10 additions & 8 deletions test/foundry/Kernel.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.0;

import "src/factory/AdminLessERC1967Factory.sol";
import "src/factory/KernelFactory.sol";
import "src/factory/ECDSAKernelFactory.sol";
import "src/Kernel.sol";
import "src/validator/ECDSAValidator.sol";
// test artifacts
Expand All @@ -18,25 +17,28 @@ using ERC4337Utils for EntryPoint;

contract KernelTest is Test {
Kernel kernel;
AdminLessERC1967Factory erc1967factory;
Kernel kernelImpl;
KernelFactory factory;
ECDSAKernelFactory ecdsaFactory;
EntryPoint entryPoint;
ECDSAValidator validator;
address owner;
uint256 ownerKey;
address payable beneficiary;
address factoryOwner;

function setUp() public {
(owner, ownerKey) = makeAddrAndKey("owner");
erc1967factory = new AdminLessERC1967Factory();
(factoryOwner, ) = makeAddrAndKey("factoryOwner");
entryPoint = new EntryPoint();
factory = new KernelFactory(erc1967factory, entryPoint);
kernelImpl = new Kernel(entryPoint);
factory = new KernelFactory(factoryOwner);
vm.startPrank(factoryOwner);
factory.setImplementation(address(kernelImpl), true);
vm.stopPrank();

validator = new ECDSAValidator();
ecdsaFactory = new ECDSAKernelFactory(factory, validator);

kernel = Kernel(payable(ecdsaFactory.createAccount(owner, 0)));
kernel = Kernel(payable(address(factory.createAccount(address(kernelImpl), abi.encodeWithSelector(KernelStorage.initialize.selector, validator, abi.encodePacked(owner)), 0))));
vm.deal(address(kernel), 1e30);
beneficiary = payable(address(makeAddr("beneficiary")));
}
Expand All @@ -53,7 +55,7 @@ contract KernelTest is Test {
}

function test_validate_signature() external {
Kernel kernel2 = Kernel(payable(address(ecdsaFactory.createAccount(owner, 1))));
Kernel kernel2 = Kernel(payable(address(factory.createAccount(address(kernelImpl), abi.encodeWithSelector(KernelStorage.initialize.selector, validator, abi.encodePacked(owner)), 1))));
bytes32 hash = keccak256(abi.encodePacked("hello world"));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerKey, hash);
assertEq(kernel2.isValidSignature(hash, abi.encodePacked(r, s, v)), Kernel.isValidSignature.selector);
Expand Down
Loading