Skip to content

Commit 49b1f79

Browse files
authored
Semi-abstracted nonces (#4)
* implement semi abstracted nonces * abstract * Update contracts/utils/SemiAbstractedNonces.sol * Update contracts/utils/SemiAbstractedNonces.sol
1 parent 98aa45c commit 49b1f79

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
5+
6+
/**
7+
* @dev Alternative to {Nonces}, that support key-ed nonces. Follows the ERC-4337's semi-abstracted nonce system.
8+
*/
9+
abstract contract SemiAbstractedNonces is Nonces {
10+
mapping(address owner => mapping(uint192 key => uint64)) private _nonce;
11+
12+
/**
13+
* @dev Returns the next unused nonce for an address.
14+
*/
15+
function nonces(address owner) public view virtual override returns (uint256) {
16+
return nonces(owner, 0);
17+
}
18+
19+
/**
20+
* @dev Returns the next unused nonce for an address and key. Result contains the key prefix.
21+
*/
22+
function nonces(address owner, uint192 key) public view virtual returns (uint256) {
23+
return (uint256(key) << 64) | _nonce[owner][key];
24+
}
25+
26+
/**
27+
* @dev Consumes a nonce from the default key.
28+
*
29+
* Returns the current value and increments nonce.
30+
*/
31+
function _useNonce(address owner) internal virtual override returns (uint256) {
32+
return _useNonce(owner, 0);
33+
}
34+
35+
/**
36+
* @dev Consumes a nonce from the given key.
37+
*
38+
* Returns the current value and increments nonce.
39+
*/
40+
function _useNonce(address owner, uint192 key) internal virtual returns (uint256) {
41+
// TODO: use unchecked here? Do we expect 2**64 nonce ever be used for a single owner?
42+
return _nonce[owner][key]++;
43+
}
44+
45+
/**
46+
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
47+
*
48+
* This version takes a the key and the nonce in a single uint256 parameter:
49+
* - use the first 8 bytes for the key
50+
* - use the last 24 bytes for the nonce
51+
*/
52+
function _useCheckedNonce(address owner, uint256 keyNonce) internal virtual override {
53+
_useCheckedNonce(owner, uint192(keyNonce >> 64), uint64(keyNonce));
54+
}
55+
56+
/**
57+
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
58+
*
59+
* This version takes a the key and the nonce as two different parameters.
60+
*/
61+
function _useCheckedNonce(address owner, uint192 key, uint64 nonce) internal virtual {
62+
uint256 current = _useNonce(owner, key);
63+
if (nonce != current) {
64+
revert InvalidAccountNonce(owner, current);
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)