From e8edd2c3f0453003255022d69b716f64be66ce27 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Tue, 5 Dec 2023 11:24:31 +0100 Subject: [PATCH 01/19] docs: on all markets --- src/interfaces/IMorpho.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index b928e50ad..8d250832f 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -70,7 +70,7 @@ interface IMorphoBase { /// @notice Whether the `lltv` is enabled. function isLltvEnabled(uint256 lltv) external view returns (bool); - /// @notice Whether `authorized` is authorized to modify `authorizer`'s positions. + /// @notice Whether `authorized` is authorized to modify `authorizer`'s positions on all markets. /// @dev Anyone is authorized to modify their own positions, regardless of this variable. function isAuthorized(address authorizer, address authorized) external view returns (bool); From dcb9ff2e63c15f8fbb27e7b5035f1782fcf99f17 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Tue, 5 Dec 2023 11:26:37 +0100 Subject: [PATCH 02/19] docs: minor improvement --- src/interfaces/IMorpho.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index 8d250832f..7fd02b166 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -70,7 +70,7 @@ interface IMorphoBase { /// @notice Whether the `lltv` is enabled. function isLltvEnabled(uint256 lltv) external view returns (bool); - /// @notice Whether `authorized` is authorized to modify `authorizer`'s positions on all markets. + /// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets. /// @dev Anyone is authorized to modify their own positions, regardless of this variable. function isAuthorized(address authorizer, address authorized) external view returns (bool); From f50c7096a91ba69cc13d77ea8cbd1afc8bc62d3c Mon Sep 17 00:00:00 2001 From: MathisGD Date: Tue, 5 Dec 2023 11:46:04 +0100 Subject: [PATCH 03/19] docs: cantina-23 --- src/libraries/EventsLib.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/EventsLib.sol b/src/libraries/EventsLib.sol index 825ea1791..1630dad56 100644 --- a/src/libraries/EventsLib.sol +++ b/src/libraries/EventsLib.sol @@ -37,7 +37,7 @@ library EventsLib { /// @notice Emitted on supply of assets. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address that received the supply. + /// @param onBehalf The owner of the modified position. /// @param assets The amount of assets supplied. /// @param shares The amount of shares minted. event Supply(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares); @@ -45,7 +45,7 @@ library EventsLib { /// @notice Emitted on withdrawal of assets. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address from which the assets were withdrawn. + /// @param onBehalf The owner of the modified position. /// @param receiver The address that received the withdrawn assets. /// @param assets The amount of assets withdrawn. /// @param shares The amount of shares burned. @@ -61,7 +61,7 @@ library EventsLib { /// @notice Emitted on borrow of assets. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address from which the assets were borrowed. + /// @param onBehalf The owner of the modified position. /// @param receiver The address that received the borrowed assets. /// @param assets The amount of assets borrowed. /// @param shares The amount of shares minted. @@ -77,7 +77,7 @@ library EventsLib { /// @notice Emitted on repayment of assets. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address for which the assets were repaid. + /// @param onBehalf The owner of the modified position. /// @param assets The amount of assets repaid. May be 1 over the corresponding market's `totalBorrowAssets`. /// @param shares The amount of shares burned. event Repay(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares); @@ -85,14 +85,14 @@ library EventsLib { /// @notice Emitted on supply of collateral. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address that received the collateral. + /// @param onBehalf The owner of the modified position. /// @param assets The amount of collateral supplied. event SupplyCollateral(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets); /// @notice Emitted on withdrawal of collateral. /// @param id The market id. /// @param caller The caller. - /// @param onBehalf The address from which the collateral was withdrawn. + /// @param onBehalf The owner of the modified position. /// @param receiver The address that received the withdrawn collateral. /// @param assets The amount of collateral withdrawn. event WithdrawCollateral( From c8424419d6e84c645f889abade7bd6156561b8d7 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Tue, 5 Dec 2023 15:57:25 +0100 Subject: [PATCH 04/19] docs: cantina-48 --- src/interfaces/IMorpho.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index 7fd02b166..fa1ca2134 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -91,6 +91,7 @@ interface IMorphoBase { function enableLltv(uint256 lltv) external; /// @notice Sets the `newFee` for the given market `marketParams`. + /// @param newFee The new fee, scaled by wad. /// @dev Warning: The recipient can be the zero address. function setFee(MarketParams memory marketParams, uint256 newFee) external; From af5ea2778b4dc23519ea782457668f78130c6e86 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Tue, 5 Dec 2023 16:28:06 +0100 Subject: [PATCH 05/19] docs: cantina-90 --- src/interfaces/IMorpho.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index fa1ca2134..fa65408dc 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -201,6 +201,7 @@ interface IMorphoBase { /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow. /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion /// roundings between shares and assets. + /// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow. /// @param marketParams The market to repay assets to. /// @param assets The amount of assets to repay. /// @param shares The amount of shares to burn. @@ -243,6 +244,7 @@ interface IMorphoBase { /// @dev Either `seizedAssets` or `repaidShares` should be zero. /// @dev Seizing more than the collateral balance will underflow and revert without any error message. /// @dev Repaying more than the borrow balance will underflow and revert without any error message. + /// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow. /// @param marketParams The market of the position. /// @param borrower The owner of the position. /// @param seizedAssets The amount of collateral to seize. From 9c87b92318c1c5aad0b1c80e2124ae5eb4b73e0f Mon Sep 17 00:00:00 2001 From: MathisGD Date: Wed, 6 Dec 2023 15:45:22 +0100 Subject: [PATCH 06/19] chore: minor improvements --- src/Morpho.sol | 2 +- src/libraries/UtilsLib.sol | 2 +- test/forge/helpers/SigUtils.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Morpho.sol b/src/Morpho.sol index f755904b6..d5be6b9f0 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -437,7 +437,7 @@ contract Morpho is IMorphoStaticTyping { 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)); + bytes32 digest = keccak256(bytes.concat("\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); diff --git a/src/libraries/UtilsLib.sol b/src/libraries/UtilsLib.sol index 066043d13..f343ef769 100644 --- a/src/libraries/UtilsLib.sol +++ b/src/libraries/UtilsLib.sol @@ -29,7 +29,7 @@ library UtilsLib { return uint128(x); } - /// @dev Returns max(x - y, 0). + /// @dev Returns max(0, x - y). function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := mul(gt(x, y), sub(x, y)) diff --git a/test/forge/helpers/SigUtils.sol b/test/forge/helpers/SigUtils.sol index 9a60b52f0..b8e90ea51 100644 --- a/test/forge/helpers/SigUtils.sol +++ b/test/forge/helpers/SigUtils.sol @@ -12,7 +12,7 @@ library SigUtils { pure returns (bytes32) { - return keccak256(abi.encodePacked("\x19\x01", domainSeparator, hashStruct(authorization))); + return keccak256(bytes.concat("\x19\x01", domainSeparator, hashStruct(authorization))); } function hashStruct(Authorization memory authorization) internal pure returns (bytes32) { From d9792e28188cd4d88c6c5ea1f58f6a8da542ccfa Mon Sep 17 00:00:00 2001 From: MathisGD Date: Sun, 10 Dec 2023 15:48:04 +0100 Subject: [PATCH 07/19] fix: issue-431 --- src/Morpho.sol | 2 ++ test/forge/integration/AuthorizationIntegrationTest.sol | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/Morpho.sol b/src/Morpho.sol index d5be6b9f0..e64155fb2 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -426,6 +426,8 @@ contract Morpho is IMorphoStaticTyping { /// @inheritdoc IMorphoBase function setAuthorization(address authorized, bool newIsAuthorized) external { + require(newIsAuthorized != isAuthorized[msg.sender][authorized], ErrorsLib.ALREADY_SET); + isAuthorized[msg.sender][authorized] = newIsAuthorized; emit EventsLib.SetAuthorization(msg.sender, msg.sender, authorized, newIsAuthorized); diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index 263eaa550..69ef8f8de 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -16,6 +16,12 @@ contract AuthorizationIntegrationTest is BaseTest { assertFalse(morpho.isAuthorized(address(this), addressFuzz)); } + function testAlreadySet(address addressFuzz, bool status) public { + morpho.setAuthorization(addressFuzz, status); + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); + morpho.setAuthorization(addressFuzz, status); + } + function testSetAuthorizationWithSignatureDeadlineOutdated( Authorization memory authorization, uint256 privateKey, From 32ba44979a7b9f892bf5d24cef36a7b80a54d575 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Sun, 10 Dec 2023 16:34:46 +0100 Subject: [PATCH 08/19] fix: issue-503 --- src/Morpho.sol | 8 ++++---- src/interfaces/IMorpho.sol | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Morpho.sol b/src/Morpho.sol index e64155fb2..830fd421d 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -397,11 +397,11 @@ contract Morpho is IMorphoStaticTyping { position[id][borrower].borrowShares = 0; } - IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets); - // `repaidAssets` may be greater than `totalBorrowAssets` by 1. emit EventsLib.Liquidate(id, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets, badDebtShares); + IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets); + if (data.length > 0) IMorphoLiquidateCallback(msg.sender).onMorphoLiquidate(repaidAssets, data); IERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), repaidAssets); @@ -413,10 +413,10 @@ contract Morpho is IMorphoStaticTyping { /// @inheritdoc IMorphoBase function flashLoan(address token, uint256 assets, bytes calldata data) external { - IERC20(token).safeTransfer(msg.sender, assets); - emit EventsLib.FlashLoan(msg.sender, token, assets); + IERC20(token).safeTransfer(msg.sender, assets); + IMorphoFlashLoanCallback(msg.sender).onMorphoFlashLoan(assets, data); IERC20(token).safeTransferFrom(msg.sender, address(this), assets); diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index fa65408dc..9e7564f6d 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -130,7 +130,8 @@ interface IMorphoBase { /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's /// `onMorphoSupply` function with the given `data`. - /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller + /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the + /// caller /// is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific amount /// of shares is given for full compatibility and precision. /// @dev If the supply of a market gets depleted, the supply share price instantly resets to @@ -173,7 +174,8 @@ interface IMorphoBase { ) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn); /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` to `receiver`. - /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller + /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the + /// caller /// is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is given for /// full compatibility and precision. /// @dev If the borrow of a market gets depleted, the borrow share price instantly resets to From 70e2636aba706186de8b097e195e5e0e3853f869 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 11:51:12 +0100 Subject: [PATCH 09/19] fix: cantina-670 --- src/Morpho.sol | 2 ++ test/forge/integration/CallbacksIntegrationTest.sol | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/Morpho.sol b/src/Morpho.sol index 830fd421d..b153e8481 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -413,6 +413,8 @@ contract Morpho is IMorphoStaticTyping { /// @inheritdoc IMorphoBase function flashLoan(address token, uint256 assets, bytes calldata data) external { + require(assets != 0, ErrorsLib.ZERO_ASSETS); + emit EventsLib.FlashLoan(msg.sender, token, assets); IERC20(token).safeTransfer(msg.sender, assets); diff --git a/test/forge/integration/CallbacksIntegrationTest.sol b/test/forge/integration/CallbacksIntegrationTest.sol index 62578aa19..512522e5e 100644 --- a/test/forge/integration/CallbacksIntegrationTest.sol +++ b/test/forge/integration/CallbacksIntegrationTest.sol @@ -83,6 +83,11 @@ contract CallbacksIntegrationTest is assertEq(loanToken.balanceOf(address(morpho)), amount, "balanceOf"); } + function testFlashLoanZero() public { + vm.expectRevert(bytes(ErrorsLib.ZERO_ASSETS)); + morpho.flashLoan(address(loanToken), 0, abi.encode(this.testFlashLoan.selector, hex"")); + } + function testFlashLoanShouldRevertIfNotReimbursed(uint256 amount) public { amount = bound(amount, 1, MAX_TEST_AMOUNT); From 915cd56c449f99eb197c8ee0bbacc5e162597ea2 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 11:53:44 +0100 Subject: [PATCH 10/19] fix: cantina-686 --- src/interfaces/IIrm.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/interfaces/IIrm.sol b/src/interfaces/IIrm.sol index db2aaf873..bab747b57 100644 --- a/src/interfaces/IIrm.sol +++ b/src/interfaces/IIrm.sol @@ -8,11 +8,12 @@ import {MarketParams, Market} from "./IMorpho.sol"; /// @custom:contact security@morpho.org /// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement. interface IIrm { - /// @notice Returns the borrow rate of the market `marketParams`. + /// @notice Returns the borrow rate per second (scaled by wad) of the market `marketParams`. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256); - /// @notice Returns the borrow rate of the market `marketParams` without modifying any storage. + /// @notice Returns the borrow rate per second (scaled by wad) of the market `marketParams` without modifying any + /// storage. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256); } From 429912c66cd7489dc55db14e139b6aae203249d1 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 11:57:03 +0100 Subject: [PATCH 11/19] fix: cantina-699 --- src/libraries/EventsLib.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/EventsLib.sol b/src/libraries/EventsLib.sol index 1630dad56..bc57b511a 100644 --- a/src/libraries/EventsLib.sol +++ b/src/libraries/EventsLib.sol @@ -35,6 +35,7 @@ library EventsLib { event CreateMarket(Id indexed id, MarketParams marketParams); /// @notice Emitted on supply of assets. + /// @dev Warning: `feeRecipient` receives some shares during interest accrual without any supply event emitted. /// @param id The market id. /// @param caller The caller. /// @param onBehalf The owner of the modified position. From 94c9f5746866de20b0c2b2d16e81433b4ff8b5c4 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 12:14:19 +0100 Subject: [PATCH 12/19] fix: auth already set --- src/Morpho.sol | 4 ++++ .../AuthorizationIntegrationTest.sol | 18 ++++++++++++++---- .../integration/BorrowIntegrationTest.sol | 4 ++-- .../WithdrawCollateralIntegrationTest.sol | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Morpho.sol b/src/Morpho.sol index b153e8481..863d619b9 100644 --- a/src/Morpho.sol +++ b/src/Morpho.sol @@ -437,6 +437,10 @@ contract Morpho is IMorphoStaticTyping { /// @inheritdoc IMorphoBase function setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external { + require( + authorization.isAuthorized != isAuthorized[authorization.authorizer][authorization.authorized], + ErrorsLib.ALREADY_SET + ); require(block.timestamp <= authorization.deadline, ErrorsLib.SIGNATURE_EXPIRED); require(authorization.nonce == nonce[authorization.authorizer]++, ErrorsLib.INVALID_NONCE); diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index 69ef8f8de..7c4c25506 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -16,10 +16,19 @@ contract AuthorizationIntegrationTest is BaseTest { assertFalse(morpho.isAuthorized(address(this), addressFuzz)); } - function testAlreadySet(address addressFuzz, bool status) public { - morpho.setAuthorization(addressFuzz, status); + function testAlreadySet(address addressFuzz) public { vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); - morpho.setAuthorization(addressFuzz, status); + morpho.setAuthorization(addressFuzz, false); + morpho.setAuthorization(addressFuzz, true); + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); + morpho.setAuthorization(addressFuzz, true); + } + + function testAlreadySetWithSig(Authorization memory authorization, Signature memory sig) public { + authorization.isAuthorized = false; + authorization.authorizer = address(this); + morpho.setAuthorization(authorization.authorized, true); + morpho.setAuthorizationWithSig(authorization, sig); } function testSetAuthorizationWithSignatureDeadlineOutdated( @@ -83,6 +92,7 @@ contract AuthorizationIntegrationTest is BaseTest { privateKey = bound(privateKey, 1, type(uint32).max); authorization.nonce = 0; authorization.authorizer = vm.addr(privateKey); + authorization.isAuthorized = true; Signature memory sig; bytes32 digest = SigUtils.getTypedDataHash(morpho.DOMAIN_SEPARATOR(), authorization); @@ -90,7 +100,7 @@ contract AuthorizationIntegrationTest is BaseTest { morpho.setAuthorizationWithSig(authorization, sig); - assertEq(morpho.isAuthorized(authorization.authorizer, authorization.authorized), authorization.isAuthorized); + assertEq(morpho.isAuthorized(authorization.authorizer, authorization.authorized), true); assertEq(morpho.nonce(authorization.authorizer), 1); } diff --git a/test/forge/integration/BorrowIntegrationTest.sol b/test/forge/integration/BorrowIntegrationTest.sol index 1733c7872..d02a83efb 100644 --- a/test/forge/integration/BorrowIntegrationTest.sol +++ b/test/forge/integration/BorrowIntegrationTest.sol @@ -202,7 +202,7 @@ contract BorrowIntegrationTest is BaseTest { vm.startPrank(ONBEHALF); collateralToken.approve(address(morpho), amountCollateral); morpho.supplyCollateral(marketParams, amountCollateral, ONBEHALF, hex""); - morpho.setAuthorization(BORROWER, true); + // BORROWER is already authorized. vm.stopPrank(); uint256 expectedBorrowShares = amountBorrowed.toSharesUp(0, 0); @@ -248,7 +248,7 @@ contract BorrowIntegrationTest is BaseTest { vm.startPrank(ONBEHALF); collateralToken.approve(address(morpho), amountCollateral); morpho.supplyCollateral(marketParams, amountCollateral, ONBEHALF, hex""); - morpho.setAuthorization(BORROWER, true); + // BORROWER is already authorized. vm.stopPrank(); vm.prank(BORROWER); diff --git a/test/forge/integration/WithdrawCollateralIntegrationTest.sol b/test/forge/integration/WithdrawCollateralIntegrationTest.sol index 8a5b0ce58..c9798d0ad 100644 --- a/test/forge/integration/WithdrawCollateralIntegrationTest.sol +++ b/test/forge/integration/WithdrawCollateralIntegrationTest.sol @@ -145,7 +145,7 @@ contract WithdrawCollateralIntegrationTest is BaseTest { vm.startPrank(ONBEHALF); morpho.supplyCollateral(marketParams, amountCollateral + amountCollateralExcess, ONBEHALF, hex""); - morpho.setAuthorization(BORROWER, true); + // BORROWER is already authorized. morpho.borrow(marketParams, amountBorrowed, 0, ONBEHALF, ONBEHALF); vm.stopPrank(); From 691d3ffdf50b1c5597230518f857223c9658e723 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 12:23:56 +0100 Subject: [PATCH 13/19] test: fix auth already set --- test/forge/integration/AuthorizationIntegrationTest.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index 7c4c25506..8047ec32c 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -36,6 +36,7 @@ contract AuthorizationIntegrationTest is BaseTest { uint256 privateKey, uint256 blocks ) public { + authorization.isAuthorized = true; blocks = _boundBlocks(blocks); authorization.deadline = block.timestamp - 1; @@ -55,6 +56,7 @@ contract AuthorizationIntegrationTest is BaseTest { } function testAuthorizationWithSigWrongPK(Authorization memory authorization, uint256 privateKey) public { + authorization.isAuthorized = true; authorization.deadline = bound(authorization.deadline, block.timestamp, type(uint256).max); // Private key must be less than the secp256k1 curve order. @@ -70,6 +72,7 @@ contract AuthorizationIntegrationTest is BaseTest { } function testAuthorizationWithSigWrongNonce(Authorization memory authorization, uint256 privateKey) public { + authorization.isAuthorized = true; authorization.deadline = bound(authorization.deadline, block.timestamp, type(uint256).max); authorization.nonce = bound(authorization.nonce, 1, type(uint256).max); @@ -86,13 +89,13 @@ contract AuthorizationIntegrationTest is BaseTest { } function testAuthorizationWithSig(Authorization memory authorization, uint256 privateKey) public { + authorization.isAuthorized = true; authorization.deadline = bound(authorization.deadline, block.timestamp, type(uint256).max); // 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); - authorization.isAuthorized = true; Signature memory sig; bytes32 digest = SigUtils.getTypedDataHash(morpho.DOMAIN_SEPARATOR(), authorization); @@ -105,6 +108,7 @@ contract AuthorizationIntegrationTest is BaseTest { } function testAuthorizationFailsWithReusedSig(Authorization memory authorization, uint256 privateKey) public { + authorization.isAuthorized = true; authorization.deadline = bound(authorization.deadline, block.timestamp, type(uint256).max); // Private key must be less than the secp256k1 curve order. From 91036d494a970084e432ea10ee978d826f234fe1 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 13:51:47 +0100 Subject: [PATCH 14/19] test: fix auth already set --- test/forge/integration/AuthorizationIntegrationTest.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index 8047ec32c..f5a45183f 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -25,9 +25,12 @@ contract AuthorizationIntegrationTest is BaseTest { } function testAlreadySetWithSig(Authorization memory authorization, Signature memory sig) public { + morpho.setAuthorization(authorization.authorized, true); + authorization.isAuthorized = false; authorization.authorizer = address(this); - morpho.setAuthorization(authorization.authorized, true); + authorization.deadline = block.timestamp - 1; + authorization.nonce = 0; morpho.setAuthorizationWithSig(authorization, sig); } @@ -122,6 +125,7 @@ contract AuthorizationIntegrationTest is BaseTest { morpho.setAuthorizationWithSig(authorization, sig); + authorization.isAuthorized = false; vm.expectRevert(bytes(ErrorsLib.INVALID_NONCE)); morpho.setAuthorizationWithSig(authorization, sig); } From 7dd997a1bb52ab9a63d8606815bd49a807df3dca Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 14:00:08 +0100 Subject: [PATCH 15/19] test: fix auth already set --- test/forge/integration/AuthorizationIntegrationTest.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index f5a45183f..547ffb24f 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -29,7 +29,7 @@ contract AuthorizationIntegrationTest is BaseTest { authorization.isAuthorized = false; authorization.authorizer = address(this); - authorization.deadline = block.timestamp - 1; + authorization.deadline = block.timestamp; authorization.nonce = 0; morpho.setAuthorizationWithSig(authorization, sig); } From dd43449267a3accc669cf716a74381d6e10d3849 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 14:20:27 +0100 Subject: [PATCH 16/19] test: fix auth already set --- .../integration/AuthorizationIntegrationTest.sol | 12 ++++++++++-- test/forge/invariant/MorphoInvariantTest.sol | 8 +++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/test/forge/integration/AuthorizationIntegrationTest.sol b/test/forge/integration/AuthorizationIntegrationTest.sol index 547ffb24f..e7933d19f 100644 --- a/test/forge/integration/AuthorizationIntegrationTest.sol +++ b/test/forge/integration/AuthorizationIntegrationTest.sol @@ -19,18 +19,26 @@ contract AuthorizationIntegrationTest is BaseTest { function testAlreadySet(address addressFuzz) public { vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); morpho.setAuthorization(addressFuzz, false); + morpho.setAuthorization(addressFuzz, true); + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); morpho.setAuthorization(addressFuzz, true); } function testAlreadySetWithSig(Authorization memory authorization, Signature memory sig) public { - morpho.setAuthorization(authorization.authorized, true); - authorization.isAuthorized = false; authorization.authorizer = address(this); authorization.deadline = block.timestamp; authorization.nonce = 0; + + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); + morpho.setAuthorizationWithSig(authorization, sig); + + morpho.setAuthorization(authorization.authorized, true); + + authorization.isAuthorized = true; + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); morpho.setAuthorizationWithSig(authorization, sig); } diff --git a/test/forge/invariant/MorphoInvariantTest.sol b/test/forge/invariant/MorphoInvariantTest.sol index edb423473..122d5f515 100644 --- a/test/forge/invariant/MorphoInvariantTest.sol +++ b/test/forge/invariant/MorphoInvariantTest.sol @@ -62,15 +62,17 @@ contract MorphoInvariantTest is InvariantTest { } modifier authorized(address onBehalf) { - if (onBehalf != msg.sender) { + if (onBehalf != msg.sender && !morpho.isAuthorized(onBehalf, msg.sender)) { vm.prank(onBehalf); morpho.setAuthorization(msg.sender, true); } _; - vm.prank(onBehalf); - morpho.setAuthorization(msg.sender, false); + if (morpho.isAuthorized(onBehalf, msg.sender)) { + vm.prank(onBehalf); + morpho.setAuthorization(msg.sender, false); + } } function _randomMarket(uint256 marketSeed) internal view returns (MarketParams memory _marketParams) { From 0a7c4602a734697806d8603d5ec65edc6ff2cedc Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 14:36:25 +0100 Subject: [PATCH 17/19] chore: fmt --- src/interfaces/IMorpho.sol | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index 9e7564f6d..8cedc984d 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -131,9 +131,8 @@ interface IMorphoBase { /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's /// `onMorphoSupply` function with the given `data`. /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the - /// caller - /// is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific amount - /// of shares is given for full compatibility and precision. + /// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific + /// amount of shares is given for full compatibility and precision. /// @dev If the supply of a market gets depleted, the supply share price instantly resets to /// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`. /// @dev Supplying a large amount can revert for overflow. @@ -175,9 +174,8 @@ interface IMorphoBase { /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` to `receiver`. /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the - /// caller - /// is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is given for - /// full compatibility and precision. + /// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is + /// given for full compatibility and precision. /// @dev If the borrow of a market gets depleted, the borrow share price instantly resets to /// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`. /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions. From 9bf3dd3f2310ed36f5078e106c896fc1ca6cdb0d Mon Sep 17 00:00:00 2001 From: MathisGD <74971347+MathisGD@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:56:13 +0100 Subject: [PATCH 18/19] docs: minor improvement Co-authored-by: Romain Milon Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com> --- src/interfaces/IIrm.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/IIrm.sol b/src/interfaces/IIrm.sol index bab747b57..58fb5bf21 100644 --- a/src/interfaces/IIrm.sol +++ b/src/interfaces/IIrm.sol @@ -8,7 +8,7 @@ import {MarketParams, Market} from "./IMorpho.sol"; /// @custom:contact security@morpho.org /// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement. interface IIrm { - /// @notice Returns the borrow rate per second (scaled by wad) of the market `marketParams`. + /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams`. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256); From 2b052d11140584d39645bd7e4d569930c9894e3b Mon Sep 17 00:00:00 2001 From: MathisGD Date: Mon, 11 Dec 2023 15:04:20 +0100 Subject: [PATCH 19/19] docs: minor improvements --- src/interfaces/IIrm.sol | 2 +- src/interfaces/IMorpho.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interfaces/IIrm.sol b/src/interfaces/IIrm.sol index 58fb5bf21..3de0bc1e8 100644 --- a/src/interfaces/IIrm.sol +++ b/src/interfaces/IIrm.sol @@ -12,7 +12,7 @@ interface IIrm { /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256); - /// @notice Returns the borrow rate per second (scaled by wad) of the market `marketParams` without modifying any + /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams` without modifying any /// storage. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256); diff --git a/src/interfaces/IMorpho.sol b/src/interfaces/IMorpho.sol index 71cd58e28..83b12302b 100644 --- a/src/interfaces/IMorpho.sol +++ b/src/interfaces/IMorpho.sol @@ -91,7 +91,7 @@ interface IMorphoBase { function enableLltv(uint256 lltv) external; /// @notice Sets the `newFee` for the given market `marketParams`. - /// @param newFee The new fee, scaled by wad. + /// @param newFee The new fee, scaled by WAD. /// @dev Warning: The recipient can be the zero address. function setFee(MarketParams memory marketParams, uint256 newFee) external;