Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: nonce check #289

Merged
merged 3 commits into from
Aug 14, 2023
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
3 changes: 2 additions & 1 deletion src/Morpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -395,14 +395,15 @@ contract Morpho is IMorpho {
/// @dev The signature is malleable, but it has no impact on the security here.
function setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external {
require(block.timestamp < authorization.deadline, ErrorsLib.SIGNATURE_EXPIRED);
require(authorization.nonce == nonce[authorization.authorizer]++, ErrorsLib.INVALID_NONCE);

bytes32 hashStruct = keccak256(abi.encode(AUTHORIZATION_TYPEHASH, authorization));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
address signatory = ecrecover(digest, signature.v, signature.r, signature.s);

require(signatory != address(0) && authorization.authorizer == signatory, ErrorsLib.INVALID_SIGNATURE);

emit EventsLib.IncrementNonce(msg.sender, authorization.authorizer, nonce[authorization.authorizer]++);
emit EventsLib.IncrementNonce(msg.sender, authorization.authorizer, authorization.nonce);

isAuthorized[authorization.authorizer][authorization.authorized] = authorization.isAuthorized;

Expand Down
3 changes: 3 additions & 0 deletions src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ library ErrorsLib {
/// @notice Thrown when the authorization signature is expired.
string internal constant SIGNATURE_EXPIRED = "signature expired";

/// @notice Thrown when the nonce is invalid.
string internal constant INVALID_NONCE = "invalid nonce";

/// @notice Thrown when a token transfer has failed.
string internal constant TRANSFER_FAILED = "transfer failed";

Expand Down
32 changes: 32 additions & 0 deletions test/forge/Morpho.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,38 @@ contract MorphoTest is
morpho.setAuthorizationWithSig(authorization, sig);
}

function testAuthorizationWithSigWrongNonce(Authorization memory authorization, uint256 privateKey) public {
vm.assume(authorization.deadline > block.timestamp);
vm.assume(authorization.nonce != 0);

// Private key must be less than the secp256k1 curve order.
privateKey = bound(privateKey, 1, type(uint32).max);
authorization.authorizer = vm.addr(privateKey);

Signature memory sig;
bytes32 digest = SigUtils.getTypedDataHash(morpho.DOMAIN_SEPARATOR(), authorization);
(sig.v, sig.r, sig.s) = vm.sign(privateKey, digest);

vm.expectRevert(bytes(ErrorsLib.INVALID_NONCE));
morpho.setAuthorizationWithSig(authorization, sig);
}

function testAuthorizationWithSigDeadline(Authorization memory authorization, uint256 privateKey) public {
vm.assume(authorization.deadline <= block.timestamp);

// Private key must be less than the secp256k1 curve order.
privateKey = bound(privateKey, 1, type(uint32).max);
authorization.nonce = 0;
authorization.authorizer = vm.addr(privateKey);

Signature memory sig;
bytes32 digest = SigUtils.getTypedDataHash(morpho.DOMAIN_SEPARATOR(), authorization);
(sig.v, sig.r, sig.s) = vm.sign(privateKey, digest);

vm.expectRevert(bytes(ErrorsLib.SIGNATURE_EXPIRED));
morpho.setAuthorizationWithSig(authorization, sig);
}

function testFlashLoan(uint256 assets) public {
assets = bound(assets, 1, 2 ** 64);

Expand Down