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
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
[submodule "lib/I4337"]
path = lib/I4337
url = https://github.com/leekt/I4337
[submodule "lib/p256-verifier"]
path = lib/p256-verifier
url = https://github.com/daimo-eth/p256-verifier
[submodule "lib/FreshCryptoLib"]
path = lib/FreshCryptoLib
url = https://github.com/rdubois-crypto/FreshCryptoLib
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
src = 'src'
out = 'out'
libs = ['lib']
solc_version = '0.8.19'
solc_version = '0.8.21'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is not required to use 0.8.21, let's stick with 0.8.19 since there are some L2 that does not support PUSH0 (which is default from 0.8.20 if i remember it correctly)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You actually use the latest solidity version without targeting shangai evm version (that's the version with push0), just have to specify evm_version = 'paris' in the foundry config

bytecode_hash = "none"
cbor_metadata = false
optimize = true
Expand Down
1 change: 1 addition & 0 deletions lib/FreshCryptoLib
Submodule FreshCryptoLib added at e2830c
2 changes: 1 addition & 1 deletion lib/forge-std
1 change: 1 addition & 0 deletions lib/p256-verifier
Submodule p256-verifier added at fcaa17
2 changes: 1 addition & 1 deletion lib/solady
Submodule solady updated 53 files
+683 −611 .gas-snapshot
+15 −10 .github/workflows/ci-all-via-ir.yml
+41 −27 .github/workflows/ci.yml
+10 −2 README.md
+1 −23 foundry.toml
+1 −1 package.json
+7 −33 src/Milady.sol
+104 −0 src/accounts/ERC1271.sol
+388 −0 src/accounts/ERC4337.sol
+71 −0 src/accounts/ERC4337Factory.sol
+321 −0 src/accounts/ERC6551.sol
+72 −0 src/accounts/ERC6551Proxy.sol
+33 −0 src/accounts/Receiver.sol
+59 −21 src/auth/Ownable.sol
+1 −1 src/auth/OwnableRoles.sol
+11 −11 src/tokens/ERC1155.sol
+3 −3 src/tokens/ERC20.sol
+6 −5 src/tokens/ERC6909.sol
+10 −11 src/tokens/ERC721.sol
+1 −1 src/tokens/WETH.sol
+9 −4 src/utils/CREATE3.sol
+90 −53 src/utils/ECDSA.sol
+12 −12 src/utils/EIP712.sol
+84 −13 src/utils/FixedPointMathLib.sol
+29 −2 src/utils/JSONParserLib.sol
+5 −5 src/utils/LibBit.sol
+306 −80 src/utils/LibClone.sol
+24 −3 src/utils/LibString.sol
+1 −1 src/utils/LibZip.sol
+1 −1 src/utils/MerkleProofLib.sol
+5 −5 src/utils/Multicallable.sol
+14 −21 src/utils/SafeTransferLib.sol
+101 −9 src/utils/SignatureCheckerLib.sol
+148 −0 src/utils/UUPSUpgradeable.sol
+6 −8 test/ECDSA.t.sol
+555 −0 test/ERC4337.t.sol
+75 −0 test/ERC4337Factory.t.sol
+415 −0 test/ERC6551.t.sol
+9 −2 test/ERC6909.t.sol
+162 −0 test/FixedPointMathLib.t.sol
+76 −0 test/JSONParserLib.t.sol
+70 −13 test/LibClone.t.sol
+7 −0 test/LibString.t.sol
+43 −0 test/Receiver.t.sol
+19 −0 test/SignatureCheckerLib.t.sol
+84 −0 test/UUPSUpgradeable.t.sol
+2 −2 test/utils/TestPlus.sol
+50 −0 test/utils/mocks/MockERC4337.sol
+55 −0 test/utils/mocks/MockERC6551.sol
+115 −0 test/utils/mocks/MockERC6551Registry.sol
+34 −0 test/utils/mocks/MockEntryPoint.sol
+8 −0 test/utils/mocks/MockReceiver.sol
+46 −0 test/utils/mocks/MockUUPSImplementation.sol
2 changes: 2 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
solady/=lib/solady/src/
p256-verifier/=lib/p256-verifier/src/
FreshCryptoLib/=lib/FreshCryptoLib/solidity/src/
66 changes: 66 additions & 0 deletions src/validator/P256Validator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {UserOperation} from "I4337/interfaces/UserOperation.sol";
import {ECDSA} from "solady/utils/ECDSA.sol";
import {IKernelValidator} from "../interfaces/IKernelValidator.sol";
import {ValidationData} from "../common/Types.sol";
import {SIG_VALIDATION_FAILED} from "../common/Constants.sol";
import {P256} from "p256-verifier/P256.sol";

contract P256Validator is IKernelValidator {
event P256PublicKeysChanged(address indexed kernel, PublicKey indexed oldKeys, PublicKey indexed newKeys);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why indexing the oldKeys & newKeys? It will increase gas usage.
And oldKeys isn't rly needed here I think, it will prevent two sload (for x & y), during module enabling


struct PublicKey {
uint256 x;
uint256 y;
}

error BadKey();

mapping(address => PublicKey) public p256PublicKey;

function enable(bytes calldata _data) external payable override {
PublicKey memory key = abi.decode(_data, (PublicKey));
if (key.x == 0 || key.y == 0) {
revert BadKey();
}
PublicKey memory oldKey = p256PublicKey[msg.sender];
p256PublicKey[msg.sender] = key;
emit P256PublicKeysChanged(msg.sender, oldKey, key);
}

function disable(bytes calldata) external payable override {
delete p256PublicKey[msg.sender];
}

function validateUserOp(UserOperation calldata _userOp, bytes32 _userOpHash, uint256) external payable override returns (ValidationData validationData) {
(uint256 r, uint256 s) = abi.decode(_userOp.signature, (uint256, uint256));
PublicKey memory key = p256PublicKey[_userOp.sender];
bytes32 hash = ECDSA.toEthSignedMessageHash(_userOpHash);
if (P256.verifySignature(hash, r, s, key.x, key.y)) {
return ValidationData.wrap(0);
}
if (!P256.verifySignature(_userOpHash, r, s, key.x, key.y)) {
return SIG_VALIDATION_FAILED;
}
}

function validateSignature(bytes32 hash, bytes calldata signature) external view override returns (ValidationData) {
(uint256 r, uint256 s) = abi.decode(signature, (uint256, uint256));
PublicKey memory key = p256PublicKey[msg.sender];
if (P256.verifySignature(hash, r, s, key.x, key.y)) {
return ValidationData.wrap(0);
}
bytes32 ethHash = ECDSA.toEthSignedMessageHash(hash);
if (!P256.verifySignature(ethHash, r, s, key.x, key.y)) {
return SIG_VALIDATION_FAILED;
}
return ValidationData.wrap(0);
}

function validCaller(address _caller, bytes calldata) external view override returns (bool) {
revert NotImplemented();
}
}
16 changes: 4 additions & 12 deletions test/foundry/KernelECDSA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ contract KernelECDSATest is KernelTestBase {
}

function test_default_validator_enable() external override {
UserOperation memory op = entryPoint.fillUserOp(
address(kernel),
UserOperation memory op = buildUserOperation(
abi.encodeWithSelector(
IKernel.execute.selector,
address(defaultValidator),
Expand All @@ -78,17 +77,13 @@ contract KernelECDSATest is KernelTestBase {
Operation.Call
)
);
op.signature = signUserOp(op);
UserOperation[] memory ops = new UserOperation[](1);
ops[0] = op;
entryPoint.handleOps(ops, beneficiary);
performUserOperationWithSig(op);
(address owner) = ECDSAValidator(address(defaultValidator)).ecdsaValidatorStorage(address(kernel));
assertEq(owner, address(0xdeadbeef), "owner should be 0xdeadbeef");
}

function test_default_validator_disable() external override {
UserOperation memory op = entryPoint.fillUserOp(
address(kernel),
UserOperation memory op = buildUserOperation(
abi.encodeWithSelector(
IKernel.execute.selector,
address(defaultValidator),
Expand All @@ -97,10 +92,7 @@ contract KernelECDSATest is KernelTestBase {
Operation.Call
)
);
op.signature = signUserOp(op);
UserOperation[] memory ops = new UserOperation[](1);
ops[0] = op;
entryPoint.handleOps(ops, beneficiary);
performUserOperationWithSig(op);
(address owner) = ECDSAValidator(address(defaultValidator)).ecdsaValidatorStorage(address(kernel));
assertEq(owner, address(0), "owner should be 0");
}
Expand Down
17 changes: 4 additions & 13 deletions test/foundry/KernelLiteECDSA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,12 @@ contract KernelECDSATest is KernelTestBase {
function test_set_default_validator() external override {
TestValidator newValidator = new TestValidator();
bytes memory empty;
UserOperation memory op = entryPoint.fillUserOp(
address(kernel),
UserOperation memory op = buildUserOperation(
abi.encodeWithSelector(KernelStorage.setDefaultValidator.selector, address(newValidator), empty)
);
op.signature = signUserOp(op);
UserOperation[] memory ops = new UserOperation[](1);
ops[0] = op;
vm.expectEmit(true, true, true, false, address(entryPoint));
emit UserOperationEvent(entryPoint.getUserOpHash(op), address(kernel), address(0), op.nonce, false, 0, 0);
entryPoint.handleOps(ops, beneficiary);
performUserOperationWithSig(op);
}

function signUserOp(UserOperation memory op) internal view override returns (bytes memory) {
Expand Down Expand Up @@ -101,14 +97,9 @@ contract KernelECDSATest is KernelTestBase {

function test_transfer_ownership() external {
address newOwner = makeAddr("new owner");
UserOperation memory op = entryPoint.fillUserOp(
address(kernel), abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner)
);
op.signature = signUserOp(op);
UserOperation[] memory ops = new UserOperation[](1);
ops[0] = op;
UserOperation memory op = buildUserOperation(abi.encodeWithSelector(KernelLiteECDSA.transferOwnership.selector, newOwner));
vm.expectEmit(true, true, true, false, address(entryPoint));
emit UserOperationEvent(entryPoint.getUserOpHash(op), address(kernel), address(0), op.nonce, false, 0, 0);
entryPoint.handleOps(ops, beneficiary);
performUserOperationWithSig(op);
}
}
Loading