Skip to content

Commit

Permalink
Add utility methods for determining the next valid nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
ezynda3 committed Aug 30, 2024
1 parent 056a8c2 commit 1755f86
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 4 deletions.
79 changes: 79 additions & 0 deletions src/Periphery/Permit2Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,83 @@ contract Permit2Proxy {
revert CallToDiamondFailed(data);
}
}

/// The following code was adapted from https://github.com/flood-protocol/permit2-nonce-finder/blob/7a4ac8a58d0b499308000b75ddb2384834f31fac/src/Permit2NonceFinder.sol
/// Provides utility functions for determining the next valid Permit2 nonce

/// @notice Finds the next valid nonce for a user, starting from 0.
/// @param owner The owner of the nonces
/// @return nonce The first valid nonce starting from 0
function nextNonce(address owner) external view returns (uint256 nonce) {
nonce = _nextNonce(owner, 0, 0);
}

/// @notice Finds the next valid nonce for a user, after from a given nonce.
/// @dev This can be helpful if you're signing multiple nonces in a row and need the next nonce to sign but the start one is still valid.
/// @param owner The owner of the nonces
/// @param start The nonce to start from
/// @return nonce The first valid nonce after the given nonce
function nextNonceAfter(
address owner,
uint256 start
) external view returns (uint256 nonce) {
uint248 word = uint248(start >> 8);
uint8 pos = uint8(start);
if (pos == type(uint8).max) {
// If the position is 255, we need to move to the next word
word++;
pos = 0;
} else {
// Otherwise, we just move to the next position
pos++;
}
nonce = _nextNonce(owner, word, pos);
}

/// @notice Finds the next valid nonce for a user, starting from a given word and position.
/// @param owner The owner of the nonces
/// @param word Word to start looking from
/// @param pos Position inside the word to start looking from
function _nextNonce(
address owner,
uint248 word,
uint8 pos
) internal view returns (uint256 nonce) {
while (true) {
uint256 bitmap = PERMIT2.nonceBitmap(owner, word);

// Check if the bitmap is completely full
if (bitmap == type(uint256).max) {
// If so, move to the next word
++word;
pos = 0;
continue;
}
if (pos != 0) {
// If the position is not 0, we need to shift the bitmap to ignore the bits before position
bitmap = bitmap >> pos;
}
// Find the first zero bit in the bitmap
while (bitmap & 1 == 1) {
bitmap = bitmap >> 1;
++pos;
}

return _nonceFromWordAndPos(word, pos);
}
}

/// @notice Constructs a nonce from a word and a position inside the word
/// @param word The word containing the nonce
/// @param pos The position of the nonce inside the word
/// @return nonce The nonce constructed from the word and position
function _nonceFromWordAndPos(
uint248 word,
uint8 pos
) internal pure returns (uint256 nonce) {
// The last 248 bits of the word are the nonce bits
nonce = uint256(word) << 8;
// The first 8 bits of the word are the position inside the word
nonce |= pos;
}
}
14 changes: 10 additions & 4 deletions test/solidity/Periphery/Permit2Proxy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -439,20 +439,23 @@ contract Permit2ProxyTest is TestBase {
);
bytes32 permit = _getTokenPermissionsHash(tokenPermissions);

// Nonce
uint256 nonce = permit2Proxy.nextNonce(PERMIT2_USER);

// PermitTransferFrom
msgHash = _getPermitTransferFromHash(
uniPermit2.DOMAIN_SEPARATOR(),
permit,
address(permit2Proxy),
0,
nonce,
block.timestamp + 1000
);

signature = _signMsgHash(msgHash, PRIVATE_KEY);

permitTransferFrom = ISignatureTransfer.PermitTransferFrom(
tokenPermissions,
0,
nonce,
block.timestamp + 1000
);
}
Expand Down Expand Up @@ -483,12 +486,15 @@ contract Permit2ProxyTest is TestBase {
);
bytes32 witness = _getWitnessHash(lifiCall);

// Nonce
uint256 nonce = permit2Proxy.nextNonce(PERMIT2_USER);

// PermitTransferWithWitness
msgHash = _getPermitWitnessTransferFromHash(
uniPermit2.DOMAIN_SEPARATOR(),
permit,
address(permit2Proxy),
0,
nonce,
block.timestamp + 1000,
witness
);
Expand All @@ -497,7 +503,7 @@ contract Permit2ProxyTest is TestBase {

permitTransferFrom = ISignatureTransfer.PermitTransferFrom(
tokenPermissions,
0,
nonce,
block.timestamp + 1000
);
}
Expand Down

0 comments on commit 1755f86

Please sign in to comment.