Sitelet https://github.com/robertodf99/account/commit/c755f9c2ec8d4daf50b63e464e4a82accb72494c
Skip to content

Commit c755f9c

Browse files
authored
Combined updates 2 (ithacaxyz#17)
* Add signature checkers * Add deployment scripts and deployments
1 parent dc29dc9 commit c755f9c

7 files changed

Lines changed: 150 additions & 16 deletions

‎deployments.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Deployments
2+
3+
EntryPoint (proxy):
4+
5+
https://odyssey-explorer.ithaca.xyz/address/0x307AF7d28AfEE82092aA95D35644898311CA5360
6+
7+
Delegation (proxy):
8+
9+
https://odyssey-explorer.ithaca.xyz/address/0x7DFc6Ae9c532EC324Ecd5ce027c425767fcDa757

‎script/DeployDelegation.s.sol‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import "../src/Delegation.sol";
6+
import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol";
7+
import {ERC1967FactoryConstants} from "solady/utils/ERC1967FactoryConstants.sol";
8+
9+
contract DeployDelegationScript is Script {
10+
function run() external {
11+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
12+
address deployer = vm.createWallet(deployerPrivateKey).addr;
13+
ERC1967Factory erc1967Factory = ERC1967Factory(ERC1967FactoryConstants.ADDRESS);
14+
address implementation = 0x2F1114bF790f7115822F1aAEF740A74Ffe19A0aC;
15+
bytes32 salt = bytes32(uint256(1));
16+
vm.startBroadcast(deployerPrivateKey);
17+
erc1967Factory.deployDeterministic(implementation, deployer, salt);
18+
vm.stopBroadcast();
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import "../src/Delegation.sol";
6+
7+
contract DeployDelegationImplementationScript is Script {
8+
function run() external {
9+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
10+
vm.startBroadcast(deployerPrivateKey);
11+
new Delegation{salt: bytes32(0)}();
12+
vm.stopBroadcast();
13+
}
14+
}

‎script/DeployEntryPoint.s.sol‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import "../src/EntryPoint.sol";
6+
import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol";
7+
import {ERC1967FactoryConstants} from "solady/utils/ERC1967FactoryConstants.sol";
8+
9+
contract DeployEntryPointScript is Script {
10+
function run() external {
11+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
12+
address deployer = vm.createWallet(deployerPrivateKey).addr;
13+
ERC1967Factory erc1967Factory = ERC1967Factory(ERC1967FactoryConstants.ADDRESS);
14+
address implementation = 0x7448A2968DbC7ae0104711bbd7b6921380612653;
15+
bytes32 salt = bytes32(0);
16+
vm.startBroadcast(deployerPrivateKey);
17+
erc1967Factory.deployDeterministic(implementation, deployer, salt);
18+
vm.stopBroadcast();
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import "../src/EntryPoint.sol";
6+
7+
contract DeployEntryPointImplementationScript is Script {
8+
function run() external {
9+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
10+
vm.startBroadcast(deployerPrivateKey);
11+
new EntryPoint{salt: bytes32(0)}();
12+
vm.stopBroadcast();
13+
}
14+
}

‎src/Delegation.sol‎

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {ECDSA} from "solady/utils/ECDSA.sol";
1010
import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol";
1111
import {P256} from "solady/utils/P256.sol";
1212
import {WebAuthn} from "solady/utils/WebAuthn.sol";
13+
import {LibStorage} from "solady/utils/LibStorage.sol";
1314
import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
1415
import {GuardedExecutor} from "./GuardedExecutor.sol";
1516
import {TokenTransferLib} from "./TokenTransferLib.sol";
@@ -21,6 +22,7 @@ contract Delegation is EIP712, GuardedExecutor {
2122
using EnumerableSetLib for *;
2223
using LibBytes for LibBytes.BytesStorage;
2324
using LibBitmap for LibBitmap.Bitmap;
25+
using LibStorage for LibStorage.Bump;
2426

2527
////////////////////////////////////////////////////////////////////////
2628
// Data Structures
@@ -51,6 +53,13 @@ contract Delegation is EIP712, GuardedExecutor {
5153
// Storage
5254
////////////////////////////////////////////////////////////////////////
5355

56+
/// @dev This struct contains extra data for a given key hash.
57+
struct KeyExtraStorage {
58+
/// @dev The `msg.senders` that can use `isValidSignature`
59+
/// to successfully validate a signature for a given key hash.
60+
EnumerableSetLib.AddressSet checkers;
61+
}
62+
5463
/// @dev Holds the storage.
5564
struct DelegationStorage {
5665
/// @dev The label.
@@ -63,6 +72,8 @@ contract Delegation is EIP712, GuardedExecutor {
6372
EnumerableSetLib.Bytes32Set keyHashes;
6473
/// @dev Mapping of key hash to the key in encoded form.
6574
mapping(bytes32 => LibBytes.BytesStorage) keyStorage;
75+
/// @dev Mapping of key hash to the key's extra storage.
76+
mapping(bytes32 => LibStorage.Bump) keyExtraStorage;
6677
/// @dev Set of approved implementations for delegate calls.
6778
EnumerableSetLib.AddressSet approvedImplementations;
6879
}
@@ -76,6 +87,18 @@ contract Delegation is EIP712, GuardedExecutor {
7687
}
7788
}
7889

90+
/// @dev Returns the storage pointer.
91+
function _getKeyExtraStorage(bytes32 keyHash)
92+
internal
93+
view
94+
returns (KeyExtraStorage storage $)
95+
{
96+
bytes32 s = _getDelegationStorage().keyExtraStorage[keyHash].slot();
97+
assembly ("memory-safe") {
98+
$.slot := s
99+
}
100+
}
101+
79102
////////////////////////////////////////////////////////////////////////
80103
// Errors
81104
////////////////////////////////////////////////////////////////////////
@@ -92,6 +115,9 @@ contract Delegation is EIP712, GuardedExecutor {
92115
/// @dev There are too many approved implementations.
93116
error ExceededApprovedImplementationsCapacity();
94117

118+
/// @dev There are too many signature checkers.
119+
error ExceededSignatureCheckersCapacity();
120+
95121
////////////////////////////////////////////////////////////////////////
96122
// Events
97123
////////////////////////////////////////////////////////////////////////
@@ -114,12 +140,17 @@ contract Delegation is EIP712, GuardedExecutor {
114140
/// @dev The nonce salt has been incremented to `newNonceSalt`.
115141
event NonceSaltIncremented(uint256 newNonceSalt);
116142

143+
/// @dev The `checker` has been authorized to use `isValidSignature` for `keyHash`.
144+
event SignatureCheckerApprovalSet(
145+
bytes32 indexed keyHash, address indexed checker, bool isApproved
146+
);
147+
117148
////////////////////////////////////////////////////////////////////////
118149
// Constants
119150
////////////////////////////////////////////////////////////////////////
120151

121152
/// @dev The entry point address.
122-
address public constant ENTRY_POINT = 0x00000000aC830f1181F6aAb6862E71EDc248941C;
153+
address public constant ENTRY_POINT = 0x307AF7d28AfEE82092aA95D35644898311CA5360;
123154

124155
/// @dev For EIP712 signature digest calculation for the `execute` function.
125156
bytes32 public constant EXECUTE_TYPEHASH = keccak256(
@@ -148,7 +179,11 @@ contract Delegation is EIP712, GuardedExecutor {
148179
virtual
149180
returns (bytes4)
150181
{
151-
(bool isValid,) = _unwrapAndValidateSignature(digest, signature, true);
182+
(bool isValid, bytes32 keyHash) = _unwrapAndValidateSignature(digest, signature);
183+
if (LibBit.and(keyHash != 0, isValid)) {
184+
isValid = getKey(keyHash).isSuperAdmin
185+
|| _getKeyExtraStorage(keyHash).checkers.contains(msg.sender);
186+
}
152187
// `bytes4(keccak256("isValidSignature(bytes32,bytes)")) = 0x1626ba7e`.
153188
// We use `0xffffffff` for invalid, in convention with the reference implementation.
154189
return bytes4(isValid ? 0x1626ba7e : 0xffffffff);
@@ -196,6 +231,23 @@ contract Delegation is EIP712, GuardedExecutor {
196231
emit ImplementationApprovalSet(implementation, isApproved);
197232
}
198233

234+
/// @dev Sets whether `checker` can use `isValidSignature` to successfully validate
235+
/// a signature for a given key hash.
236+
function setSignatureCheckerApproval(bytes32 keyHash, address checker, bool isApproved)
237+
public
238+
virtual
239+
onlyThis
240+
{
241+
EnumerableSetLib.AddressSet storage checkers = _getKeyExtraStorage(keyHash).checkers;
242+
if (isApproved) {
243+
checkers.add(checker);
244+
if (checkers.length() > 512) revert ExceededSignatureCheckersCapacity();
245+
} else {
246+
checkers.remove(checker);
247+
}
248+
emit SignatureCheckerApprovalSet(keyHash, checker, isApproved);
249+
}
250+
199251
/// @dev Invalidates the nonce.
200252
function invalidateNonce(uint256 nonce) public virtual onlyThis {
201253
_invalidateNonce(nonce);
@@ -263,16 +315,21 @@ contract Delegation is EIP712, GuardedExecutor {
263315
return EfficientHashLib.hash(uint8(key.keyType), uint256(keccak256(key.publicKey)));
264316
}
265317

266-
/// @dev Returns whether `implementation` is approved.
267-
function implementationIsApproved(address implementation) public view virtual returns (bool) {
268-
return _getDelegationStorage().approvedImplementations.contains(implementation);
269-
}
270-
271318
/// @dev Returns the list of approved implementations.
272319
function approvedImplementations() public view virtual returns (address[] memory) {
273320
return _getDelegationStorage().approvedImplementations.values();
274321
}
275322

323+
/// @dev Returns the list of approved signature checkers for `keyHash`.
324+
function approvedSignatureCheckers(bytes32 keyHash)
325+
public
326+
view
327+
virtual
328+
returns (address[] memory)
329+
{
330+
return _getKeyExtraStorage(keyHash).checkers.values();
331+
}
332+
276333
/// @dev Computes the EIP712 digest for `calls`, with `nonceSalt` from storage.
277334
/// If the nonce is odd, the digest will be computed without the chain ID.
278335
/// Otherwise, the digest will be computed with the chain ID.
@@ -336,6 +393,7 @@ contract Delegation is EIP712, GuardedExecutor {
336393
function _removeKey(bytes32 keyHash) internal virtual {
337394
DelegationStorage storage $ = _getDelegationStorage();
338395
$.keyStorage[keyHash].clear();
396+
$.keyExtraStorage[keyHash].invalidate();
339397
if (!$.keyHashes.remove(keyHash)) revert KeyDoesNotExist();
340398
}
341399

@@ -359,17 +417,18 @@ contract Delegation is EIP712, GuardedExecutor {
359417
virtual
360418
returns (bool isValid, bytes32 keyHash)
361419
{
362-
return _unwrapAndValidateSignature(digest, signature, false);
420+
return _unwrapAndValidateSignature(digest, signature);
363421
}
364422

365423
/// @dev Returns if the signature is valid, along with its `keyHash`.
366424
/// The `signature` is a wrapped signature, given by
367425
/// `abi.encodePacked(bytes(innerSignature), bytes32(keyHash), bool(prehash))`.
368-
function _unwrapAndValidateSignature(
369-
bytes32 digest,
370-
bytes calldata signature,
371-
bool requireSuperAdmin
372-
) internal view virtual returns (bool isValid, bytes32 keyHash) {
426+
function _unwrapAndValidateSignature(bytes32 digest, bytes calldata signature)
427+
internal
428+
view
429+
virtual
430+
returns (bool isValid, bytes32 keyHash)
431+
{
373432
// If the signature's length is 64 or 65, treat it like an secp256k1 signature.
374433
if (LibBit.or(signature.length == 64, signature.length == 65)) {
375434
return (ECDSA.recoverCalldata(digest, signature) == address(this), 0);
@@ -389,8 +448,6 @@ contract Delegation is EIP712, GuardedExecutor {
389448
}
390449
Key memory key = getKey(keyHash);
391450

392-
if (LibBit.and(requireSuperAdmin, !key.isSuperAdmin)) return (false, keyHash);
393-
394451
// Early return if the key has expired.
395452
if (LibBit.and(key.expiry != 0, block.timestamp > key.expiry)) return (false, keyHash);
396453

0 commit comments

Comments
 (0)