Skip to content

Commit 0db9873

Browse files
authored
V2.1 stake factory (#23)
* gas optimization by using memory for validateUserOp * optimization with calldata parsing * stake for factory * stake factory * report * fmt * removed unused file
1 parent 69f7508 commit 0db9873

File tree

5 files changed

+68
-32
lines changed

5 files changed

+68
-32
lines changed

gas/ecdsa/report.txt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
No files changed, compilation skipped
22

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

2828

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

3737

3838

src/Kernel.sol

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import "./abstract/Compatibility.sol";
1111
import "./abstract/KernelStorage.sol";
1212
import "./utils/KernelHelper.sol";
1313

14+
import "forge-std/console.sol";
15+
1416
enum Operation {
1517
Call,
1618
DelegateCall
@@ -89,11 +91,19 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
8991
/// @param userOpHash The hash of the user operation
9092
/// @param missingAccountFunds The funds needed to be reimbursed
9193
/// @return validationData The data used for validation
92-
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
94+
function validateUserOp(UserOperation memory userOp, bytes32 userOpHash, uint256 missingAccountFunds)
9395
external
9496
payable
9597
returns (uint256 validationData)
9698
{
99+
bytes calldata userOpSignature;
100+
uint256 userOpEndOffset;
101+
assembly {
102+
userOpEndOffset := add(calldataload(0x04), 0x24)
103+
userOpSignature.offset := add(calldataload(add(userOpEndOffset, 0x120)), userOpEndOffset)
104+
userOpSignature.length := calldataload(sub(userOpSignature.offset, 0x20))
105+
}
106+
97107
if (msg.sender != address(entryPoint)) {
98108
revert NotEntryPoint();
99109
}
@@ -102,43 +112,49 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
102112
storage_slot_1 := sload(KERNEL_STORAGE_SLOT_1)
103113
}
104114
// mode based signature
105-
bytes4 mode = bytes4(userOp.signature[0:4]); // mode == 00..00 use validators
115+
bytes4 mode = bytes4(userOpSignature[0:4]); // mode == 00..00 use validators
106116
// mode == 0x00000000 use sudo validator
107117
// mode == 0x00000001 use given validator
108118
// mode == 0x00000002 enable validator
109-
UserOperation memory op = userOp;
110119
IKernelValidator validator;
111120
if (mode == 0x00000000) {
112121
// sudo mode (use default validator)
113-
op.signature = userOp.signature[4:];
122+
userOpSignature = userOpSignature[4:];
114123
assembly {
115124
validator := shr(80, storage_slot_1)
116125
}
117126
} else if (mode & (storage_slot_1 << 224) != 0x00000000) {
118127
revert DisabledMode();
119128
} else if (mode == 0x00000001) {
120-
bytes4 sig = bytes4(userOp.callData[0:4]);
121-
ExecutionDetail storage detail = getKernelStorage().execution[sig];
129+
bytes calldata userOpCallData;
130+
assembly {
131+
userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset)
132+
userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20))
133+
}
134+
ExecutionDetail storage detail = getKernelStorage().execution[bytes4(userOpCallData[0:4])];
122135
validator = detail.validator;
123136
if (address(validator) == address(0)) {
124137
assembly {
125138
validator := shr(80, storage_slot_1)
126139
}
127140
}
128-
op.signature = userOp.signature[4:];
141+
userOpSignature = userOpSignature[4:];
129142
validationData = (uint256(detail.validAfter) << 208) | (uint256(detail.validUntil) << 160);
130143
} else if (mode == 0x00000002) {
131-
bytes4 sig = bytes4(userOp.callData[0:4]);
144+
bytes calldata userOpCallData;
145+
assembly {
146+
userOpCallData.offset := add(calldataload(add(userOpEndOffset, 0x40)), userOpEndOffset)
147+
userOpCallData.length := calldataload(sub(userOpCallData.offset, 0x20))
148+
}
132149
// use given validator
133-
// userOp.signature[4:10] = validAfter,
134-
// userOp.signature[10:16] = validUntil,
135-
// userOp.signature[16:36] = validator address,
136-
validator = IKernelValidator(address(bytes20(userOp.signature[16:36])));
150+
// userOpSignature[4:10] = validAfter,
151+
// userOpSignature[10:16] = validUntil,
152+
// userOpSignature[16:36] = validator address,
153+
validator = IKernelValidator(address(bytes20(userOpSignature[16:36])));
137154
bytes calldata enableData;
138-
bytes calldata remainSig;
139-
(validationData, enableData, remainSig) = _approveValidator(sig, userOp.signature);
155+
(validationData, enableData, userOpSignature) =
156+
_approveValidator(bytes4(userOpCallData[0:4]), userOpSignature);
140157
validator.enable(enableData);
141-
op.signature = remainSig;
142158
} else {
143159
return SIG_VALIDATION_FAILED;
144160
}
@@ -148,8 +164,9 @@ contract Kernel is EIP712, Compatibility, KernelStorage {
148164
}
149165
//ignore failure (its EntryPoint's job to verify, not account.)
150166
}
167+
userOp.signature = userOpSignature;
151168
validationData =
152-
_intersectValidationData(validationData, validator.validateUserOp(op, userOpHash, missingAccountFunds));
169+
_intersectValidationData(validationData, validator.validateUserOp(userOp, userOpHash, missingAccountFunds));
153170
return validationData;
154171
}
155172

src/factory/KernelFactory.sol

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@ import "src/validator/ECDSAValidator.sol";
99
import "solady/auth/Ownable.sol";
1010

1111
contract KernelFactory is AdminLessERC1967Factory, Ownable {
12+
IEntryPoint public entryPoint;
1213
mapping(address => bool) public isAllowedImplementation;
1314

14-
constructor(address _owner) {
15+
constructor(address _owner, IEntryPoint _entryPoint) {
1516
_initializeOwner(_owner);
17+
entryPoint = _entryPoint;
1618
}
1719

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

24+
function setEntryPoint(IEntryPoint _entryPoint) external onlyOwner {
25+
entryPoint = _entryPoint;
26+
}
27+
2228
function createAccount(address _implementation, bytes calldata _data, uint256 _index)
2329
external
2430
payable
@@ -33,4 +39,17 @@ contract KernelFactory is AdminLessERC1967Factory, Ownable {
3339
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(_data, _index))) & type(uint96).max);
3440
return predictDeterministicAddress(salt);
3541
}
42+
43+
// stake functions
44+
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
45+
entryPoint.addStake{value: msg.value}(unstakeDelaySec);
46+
}
47+
48+
function unlockStake() external onlyOwner {
49+
entryPoint.unlockStake();
50+
}
51+
52+
function withdrawStake(address payable withdrawAddress) external onlyOwner {
53+
entryPoint.withdrawStake(withdrawAddress);
54+
}
3655
}

test/foundry/Kernel.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ contract KernelTest is KernelTestBase {
2121
(factoryOwner,) = makeAddrAndKey("factoryOwner");
2222
entryPoint = new EntryPoint();
2323
kernelImpl = new Kernel(entryPoint);
24-
factory = new KernelFactory(factoryOwner);
24+
factory = new KernelFactory(factoryOwner, entryPoint);
2525
vm.startPrank(factoryOwner);
2626
factory.setImplementation(address(kernelImpl), true);
2727
vm.stopPrank();

test/foundry/KernelExecution.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ contract KernelExecutionTest is KernelTestBase {
2424
(factoryOwner,) = makeAddrAndKey("factoryOwner");
2525
entryPoint = new EntryPoint();
2626
kernelImpl = new Kernel(entryPoint);
27-
factory = new KernelFactory(factoryOwner);
27+
factory = new KernelFactory(factoryOwner, entryPoint);
2828
vm.startPrank(factoryOwner);
2929
factory.setImplementation(address(kernelImpl), true);
3030
vm.stopPrank();

0 commit comments

Comments
 (0)