From 6faea6449f52767ed66c1f6c95623d542a35e3a0 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 14 Aug 2023 10:35:51 +0200 Subject: [PATCH 1/2] fix: nonce check --- src/Morpho.sol | 3 ++- src/libraries/ErrorsLib.sol | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Morpho.sol b/src/Morpho.sol index 0fb6eb187..5bacee0ab 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -395,6 +395,7 @@ 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)); @@ -402,7 +403,7 @@ contract Morpho is IMorpho { 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; diff --git a/src/libraries/ErrorsLib.sol b/src/libraries/ErrorsLib.sol index f23efbe9a..630c689f8 100644 --- a/src/libraries/ErrorsLib.sol +++ b/src/libraries/ErrorsLib.sol @@ -49,4 +49,7 @@ 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"; } From 148d199d1c6ab0218d432febe00c52a071377bcb Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 14 Aug 2023 10:38:13 +0200 Subject: [PATCH 2/2] test: nonce fix --- test/forge/Morpho.t.sol | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/forge/Morpho.t.sol b/test/forge/Morpho.t.sol index 8acb6f8a7..cf209b207 100644 --- a/test/forge/Morpho.t.sol +++ b/test/forge/Morpho.t.sol @@ -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);