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
26 changes: 13 additions & 13 deletions gas/ecdsa/report.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
No files changed, compilation skipped

Running 8 tests for test/foundry/Kernel.t.sol:KernelTest
[PASS] test_disable_mode() (gas: 162839)
[PASS] test_external_call_default() (gas: 28889)
[PASS] test_external_call_execution() (gas: 453341)
[PASS] test_initialize_twice() (gas: 20907)
[PASS] test_set_default_validator() (gas: 361312)
[PASS] test_set_execution() (gas: 411646)
[PASS] test_disable_mode() (gas: 162625)
[PASS] test_external_call_default() (gas: 28867)
[PASS] test_external_call_execution() (gas: 453097)
[PASS] test_initialize_twice() (gas: 20885)
[PASS] test_set_default_validator() (gas: 361098)
[PASS] test_set_execution() (gas: 411432)
[PASS] test_validate_signature() (gas: 163702)
[PASS] test_validate_userOp() (gas: 1727980)
Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.81ms
[PASS] test_validate_userOp() (gas: 1711945)
Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.87ms
| src/Kernel.sol:Kernel contract | | | | | |
|--------------------------------|-----------------|-------|--------|-------|---------|
| Deployment Cost | Deployment Size | | | | |
| 1585184 | 8326 | | | | |
| 1569370 | 8247 | | | | |
| Function Name | min | avg | median | max | # calls |
| disableMode | 3765 | 3765 | 3765 | 3765 | 1 |
| getDefaultValidator | 341 | 341 | 341 | 341 | 1 |
Expand All @@ -23,16 +23,16 @@ Test result: ok. 8 passed; 0 failed; 0 skipped; finished in 2.81ms
| isValidSignature | 6047 | 6047 | 6047 | 6047 | 1 |
| setDefaultValidator | 7870 | 7870 | 7870 | 7870 | 1 |
| setExecution | 49874 | 49874 | 49874 | 49874 | 2 |
| validateUserOp | 46040 | 46234 | 46256 | 46386 | 4 |
| validateUserOp | 45764 | 45958 | 45980 | 46110 | 4 |


| src/factory/KernelFactory.sol:KernelFactory contract | | | | | |
|------------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 437471 | 2268 | | | | |
| 564969 | 2862 | | | | |
| Function Name | min | avg | median | max | # calls |
| createAccount | 130967 | 131744 | 130967 | 137967 | 9 |
| setImplementation | 22796 | 22796 | 22796 | 22796 | 8 |
| createAccount | 130989 | 131766 | 130989 | 137989 | 9 |
| setImplementation | 22862 | 22862 | 22862 | 22862 | 8 |



Expand Down
49 changes: 33 additions & 16 deletions src/Kernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import "./abstract/Compatibility.sol";
import "./abstract/KernelStorage.sol";
import "./utils/KernelHelper.sol";

import "forge-std/console.sol";

enum Operation {
Call,
DelegateCall
Expand Down Expand Up @@ -89,11 +91,19 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
/// @param userOpHash The hash of the user operation
/// @param missingAccountFunds The funds needed to be reimbursed
/// @return validationData The data used for validation
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
function validateUserOp(UserOperation memory userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
payable
returns (uint256 validationData)
{
bytes calldata userOpSignature;
uint256 userOpEndOffset;
assembly {
userOpEndOffset := add(calldataload(0x04), 0x24)
userOpSignature.offset := add(calldataload(add(userOpEndOffset, 0x120)), userOpEndOffset)
userOpSignature.length := calldataload(sub(userOpSignature.offset, 0x20))
}

if (msg.sender != address(entryPoint)) {
revert NotEntryPoint();
}
Expand All @@ -102,43 +112,49 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
storage_slot_1 := sload(KERNEL_STORAGE_SLOT_1)
}
// mode based signature
bytes4 mode = bytes4(userOp.signature[0:4]); // mode == 00..00 use validators
bytes4 mode = bytes4(userOpSignature[0:4]); // mode == 00..00 use validators
// mode == 0x00000000 use sudo validator
// mode == 0x00000001 use given validator
// mode == 0x00000002 enable validator
UserOperation memory op = userOp;
IKernelValidator validator;
if (mode == 0x00000000) {
// sudo mode (use default validator)
op.signature = userOp.signature[4:];
userOpSignature = userOpSignature[4:];
assembly {
validator := shr(80, storage_slot_1)
}
} else if (mode & (storage_slot_1 << 224) != 0x00000000) {
revert DisabledMode();
} else if (mode == 0x00000001) {
bytes4 sig = bytes4(userOp.callData[0:4]);
ExecutionDetail storage detail = getKernelStorage().execution[sig];
bytes calldata userOpCallData;
assembly {
userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset)
userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20))
}
ExecutionDetail storage detail = getKernelStorage().execution[bytes4(userOpCallData[0:4])];
validator = detail.validator;
if (address(validator) == address(0)) {
assembly {
validator := shr(80, storage_slot_1)
}
}
op.signature = userOp.signature[4:];
userOpSignature = userOpSignature[4:];
validationData = (uint256(detail.validAfter) << 208) | (uint256(detail.validUntil) << 160);
} else if (mode == 0x00000002) {
bytes4 sig = bytes4(userOp.callData[0:4]);
bytes calldata userOpCallData;
assembly {
userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset)
userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20))
}
// use given validator
// userOp.signature[4:10] = validAfter,
// userOp.signature[10:16] = validUntil,
// userOp.signature[16:36] = validator address,
validator = IKernelValidator(address(bytes20(userOp.signature[16:36])));
// userOpSignature[4:10] = validAfter,
// userOpSignature[10:16] = validUntil,
// userOpSignature[16:36] = validator address,
validator = IKernelValidator(address(bytes20(userOpSignature[16:36])));
bytes calldata enableData;
bytes calldata remainSig;
(validationData, enableData, remainSig) = _approveValidator(sig, userOp.signature);
(validationData, enableData, userOpSignature) =
_approveValidator(bytes4(userOpCallData[0:4]), userOpSignature);
validator.enable(enableData);
op.signature = remainSig;
} else {
return SIG_VALIDATION_FAILED;
}
Expand All @@ -148,8 +164,9 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
}
//ignore failure (its EntryPoint's job to verify, not account.)
}
userOp.signature = userOpSignature;
validationData =
_intersectValidationData(validationData, validator.validateUserOp(op, userOpHash, missingAccountFunds));
_intersectValidationData(validationData, validator.validateUserOp(userOp, userOpHash, missingAccountFunds));
return validationData;
}

Expand Down
21 changes: 20 additions & 1 deletion src/factory/KernelFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ import "src/validator/ECDSAValidator.sol";
import "solady/auth/Ownable.sol";

contract KernelFactory is AdminLessERC1967Factory, Ownable {
IEntryPoint public entryPoint;
mapping(address => bool) public isAllowedImplementation;

constructor(address _owner) {
constructor(address _owner, IEntryPoint _entryPoint) {
_initializeOwner(_owner);
entryPoint = _entryPoint;
}

function setImplementation(address _implementation, bool _allow) external onlyOwner {
isAllowedImplementation[_implementation] = _allow;
}

function setEntryPoint(IEntryPoint _entryPoint) external onlyOwner {
entryPoint = _entryPoint;
}

function createAccount(address _implementation, bytes calldata _data, uint256 _index)
external
payable
Expand All @@ -33,4 +39,17 @@ contract KernelFactory is AdminLessERC1967Factory, Ownable {
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_data, _index))) & type(uint96).max);
return predictDeterministicAddress(salt);
}

// stake functions
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{value: msg.value}(unstakeDelaySec);
}

function unlockStake() external onlyOwner {
entryPoint.unlockStake();
}

function withdrawStake(address payable withdrawAddress) external onlyOwner {
entryPoint.withdrawStake(withdrawAddress);
}
}
2 changes: 1 addition & 1 deletion test/foundry/Kernel.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract KernelTest is KernelTestBase {
(factoryOwner,) = makeAddrAndKey("factoryOwner");
entryPoint = new EntryPoint();
kernelImpl = new Kernel(entryPoint);
factory = new KernelFactory(factoryOwner);
factory = new KernelFactory(factoryOwner, entryPoint);
vm.startPrank(factoryOwner);
factory.setImplementation(address(kernelImpl), true);
vm.stopPrank();
Expand Down
2 changes: 1 addition & 1 deletion test/foundry/KernelExecution.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract KernelExecutionTest is KernelTestBase {
(factoryOwner,) = makeAddrAndKey("factoryOwner");
entryPoint = new EntryPoint();
kernelImpl = new Kernel(entryPoint);
factory = new KernelFactory(factoryOwner);
factory = new KernelFactory(factoryOwner, entryPoint);
vm.startPrank(factoryOwner);
factory.setImplementation(address(kernelImpl), true);
vm.stopPrank();
Expand Down