diff --git a/test/forge/BaseTest.sol b/test/forge/BaseTest.sol index 33a8bfa81..f00917261 100644 --- a/test/forge/BaseTest.sol +++ b/test/forge/BaseTest.sol @@ -95,19 +95,19 @@ contract BaseTest is Test { loanToken.approve(address(morpho), type(uint256).max); collateralToken.approve(address(morpho), type(uint256).max); - changePrank(BORROWER); + vm.startPrank(BORROWER); loanToken.approve(address(morpho), type(uint256).max); collateralToken.approve(address(morpho), type(uint256).max); - changePrank(REPAYER); + vm.startPrank(REPAYER); loanToken.approve(address(morpho), type(uint256).max); collateralToken.approve(address(morpho), type(uint256).max); - changePrank(LIQUIDATOR); + vm.startPrank(LIQUIDATOR); loanToken.approve(address(morpho), type(uint256).max); collateralToken.approve(address(morpho), type(uint256).max); - changePrank(ONBEHALF); + vm.startPrank(ONBEHALF); loanToken.approve(address(morpho), type(uint256).max); collateralToken.approve(address(morpho), type(uint256).max); morpho.setAuthorization(BORROWER, true); diff --git a/test/forge/integration/BorrowIntegrationTest.sol b/test/forge/integration/BorrowIntegrationTest.sol index d02a83efb..7b44ef931 100644 --- a/test/forge/integration/BorrowIntegrationTest.sol +++ b/test/forge/integration/BorrowIntegrationTest.sol @@ -55,7 +55,7 @@ contract BorrowIntegrationTest is BaseTest { collateralToken.approve(address(morpho), amountCollateral); morpho.supplyCollateral(marketParams, amountCollateral, supplier, hex""); - changePrank(attacker); + vm.startPrank(attacker); vm.expectRevert(bytes(ErrorsLib.UNAUTHORIZED)); morpho.borrow(marketParams, amountBorrowed, 0, supplier, RECEIVER); } diff --git a/test/morpho_tests.tree b/test/morpho_tests.tree deleted file mode 100644 index a2faa9950..000000000 --- a/test/morpho_tests.tree +++ /dev/null @@ -1,288 +0,0 @@ -. -└── setOwner(address newOwner) external - ├── when msg.sender not owner - │ └── revert with NOT_OWNER - └── when msg.sender is owner - ├── it should set owner to newOwner - └── it should emit SetOwner(newOwner) -. -└── enableIrm(address irm) external - ├── when msg.sender not owner - │ └── revert with NOT_OWNER - └── when msg.sender is owner - ├── it should set isIrmEnabled[irm] to true - └── it should emit EnableIrm(irm) -. -└── enableLltv(uint256 lltv) external - ├── when msg.sender not owner - │ └── revert with NOT_OWNER - └── when msg.sender is owner - ├── when lltv >= WAD - │ └── revert with MAX_LLTV_EXCEEDED - └── when lltv < WAD - ├── it should set isLltvEnabled[lltv] to true - └── it should emit EnableLltv(lltv) -. -└── setFee(MarketParams memory marketParams, uint256 newFee) external - ├── when msg.sender not owner - │ └── revert with NOT_OWNER - └── when msg.sender is owner - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when newFee > MAX_FEE - │ └── revert with MAX_FEE_EXCEEDED - └── when newFee <= MAX_FEE - ├── it should accrue the interest - ├── it should set fee[marketParams.id] to newFee - └── it should emit SetFee(marketParams.id, newFee) -. -└── setFeeRecipient(address recipient) external - ├── when msg.sender not owner - │ └── revert with NOT_OWNER - └── when msg.sender is owner - ├── it should set feeRecipient to recipient - └── it should emit SetFeeRecipient(recipient) -. -└── createMarket(MarketParams memory marketParams) external - ├── when irm is not enabled - │ └── revert with IRM_NOT_ENABLED - └── when irm is enabled - ├── when marketParams.lltv is not enabled - │ └── revert with LLTV_NOT_ENABLED - └── when marketParams.lltv is enabled - ├── when market is already created - │ └── revert with MARKET_ALREADY_CREATED - └── when market is not already created - ├── it should set lastUpdate[marketParams.id] to block.timestamp - ├── it should set idToMarket[id] to marketParams - └── it should emit CreateMarket(marketParams.id, marketParams) -. -└── supply(MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, bytes calldata data) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when both assets and shares are null or both assets and shares are not null - │ └─ revert with INCONSISTENT_INPUT - └── when one of assets or shares is null and one of assets or shares is not null - ├── when onBehalf is the zero address - │ └── revert with ZERO_ADDRESS - └── when onBehalf is not the zero address - ├── it should accrue the interest - ├── when assets is not zero - │ └── it should set shares to assets.toSharesUp(totalSupplyAssets[marketParams.id], totalSupplyShares[marketParams.id]) - ├── when assets is zero - │ └── it should set assets to shares.toAssetsDown(totalSupplyAssets[id], totalSupplyShares[id]) - ├── it should add shares to supplyShares[marketParams.id][onBehalf] - ├── it should add shares to totalSupplyShares[marketParams.id] - ├── it should add assets to totalSupplyAssets[marketParams.id] - ├── it should emit Supply(marketParams.id, msg.sender, onBehalf, assets, shares) - ├── if data.length > 0 - │ └── it should call sender's onMorphoSupply callback - ├── it should transfer assets of the loan asset from the sender to Morpho - └── it should return the assets and the shares supplied -. -└── withdraw(MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when both assets and shares are null or both assets and shares are not null - │ └─ revert with INCONSISTENT_INPUT - └── when one of assets or shares is null and one of assets or shares is not null - ├── when receiver is the zero address - │ └── revert with ZERO_ADDRESS - └── when receiver is not the zero address - ├── when not sender and not approved - │ └── revert with UNAUTHORIZED - └── when sender or approved - ├── it should accrue the interest - ├── when assets is not zero - │ └── it should set shares to assets.toSharesUp(totalSupplyAssets[marketParams.id], totalSupplyShares[marketParams.id]) - ├── when assets is zero - │ └── it should set assets to shares.toAssetsDown(totalSupplyAssets[id], totalSupplyShares[id]) - ├── it should remove shares from supplyShares[marketParams.id][onBehalf] - ├── it should remove shares from totalSupplyShares[marketParams.id] - ├── it should remove assets from totalSupplyAssets[marketParams.id] - ├── it should emit Withdraw(marketParams.id, msg.sender, onBehalf, receiver, assets, shares) - ├── it should transfer assets of the loan asset to the receiver - ├── when totalBorrowAssets[marketParams.id] > totalSupplyAssets[marketParams.id] - │ └── revert with INSUFFICIENT_LIQUIDITY - └── when totalBorrowAssets[marketParams.id] <= totalSupplyAssets[marketParams.id] - └── it should return the assets and the shares withdrawn -. -└── borrow(MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when both assets and shares are null or both assets and shares are not null - │ └─ revert with INCONSISTENT_INPUT - └── when one of assets or shares is null and one of assets or shares is not null - ├── when receiver is the zero address - │ └── revert with ZERO_ADDRESS - └── when receiver is not the zero address - ├── when not sender and not approved - │ └── revert with UNAUTHORIZED - └── when sender or approved - ├── it should accrue the interest - ├── when assets is not zero - │ └── it should set shares to assets.toSharesUp(totalSupplyAssets[marketParams.id], totalSupplyShares[marketParams.id]) - ├── when assets is zero - │ └── it should set assets to shares.toAssetsDown(totalSupplyAssets[id], totalSupplyShares[id]) - ├── it should add shares to borrowShares[marketParams.id][onBehalf] - ├── it should add shares to totalBorrowShares[marketParams.id] - ├── it should add assets to totalBorrowAssets[marketParams.id] - ├── it should emit Borrow(marketParams.id, msg.sender, onBehalf, receiver, assets, shares) - ├── it should transfer assets of the loan asset to the receiver - ├── when position is not healthy - │ └── revert with INSUFFICIENT_COLLATERAL - └── when position is healthy - ├── when totalBorrowAssets[marketParams.id] > totalSupplyAssets[marketParams.id] - │ └── revert with INSUFFICIENT_LIQUIDITY - └── when totalBorrowAssets[marketParams.id] <= totalSupplyAssets[marketParams.id] - └── it should return the assets and the shares borrowed - -. -└── repay(MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, bytes calldata data) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when both assets and shares are null or both assets and shares are not null - │ └─ revert with INCONSISTENT_INPUT - └── when one of assets or shares is null and one of assets or shares is not null - ├── when onBehalf is the zero address - │ └── revert with ZERO_ADDRESS - └── when onBehalf is not the zero address - ├── it should accrue the interest - ├── when assets is not zero - │ └── it should set shares to assets.toSharesUp(totalSupplyAssets[marketParams.id], totalSupplyShares[marketParams.id]) - ├── when assets is zero - │ └── it should set assets to shares.toAssetsDown(totalSupplyAssets[id], totalSupplyShares[id]) - ├── it should remove shares from borrowShares[marketParams.id][onBehalf] - ├── it should remove shares from totalBorrowShares[marketParams.id] - ├── it should remove assets from totalBorrowAssets[marketParams.id] - ├── it should emit Repay(marketParams.id, msg.sender, onBehalf, assets, shares) - ├── if data.length > 0 - │ └── it should call sender's onMorphoRepay callback - ├── it should transfer assets of the loan asset from the sender to Morpho - └── it should return the assets and the shares repaid -. -└── supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes calldata data) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when the assets to supply is zero - │ └── revert with ZERO_ASSETS - └── when the assets to supply is not zero - ├── when onBehalf is the zero address - │ └── revert with ZERO_ADDRESS - └── when onBehalf is not the zero address - ├── it should add assets to collateral[marketParams.id][onBehalf] - ├── it should emit SupplyCollateral(marketParams.id, msg.sender, onBehalf, assets) - ├── if data.length > 0 - │ └── it should call sender's onMorphoSupplyCollateral callback - └── it should transfer assets of the collateral asset from the sender to Morpho -. -└── withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when the assets to withdraw is zero - │ └── revert with ZERO_ASSETS - └── when the assets to withdraw is not zero - ├── when receiver is the zero address - │ └── revert with ZERO_ADDRESS - └── when receiver is not the zero address - ├── when not sender and not approved - │ └── revert with MANAGER_NOT_APPROVED - └── when sender or approved - ├── it should accrue the interest - ├── it should remove assets from collateral[marketParams.id][onBehalf] - ├── it should emit WithdrawCollateral(marketParams.id, msg.sender, onBehalf, receiver, assets) - ├── it should transfer assets of the collateral asset to the receiver - └── when position is not healthy - └── revert with INSUFFICIENT_COLLATERAL -. -└── liquidate(MarketParams memory marketParams, address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - ├── when both seizedAssets and repaidShares are null or both seizedAssets and repaidShares are not null - │ └─ revert with INCONSISTENT_INPUT - └── when one of seizedAssets or repaidShares is null and one of seizedAssets or repaidShares is not null - ├── it should accrue the interest - ├── when position is healthy - │ └── revert with HEALTHY_POSITION - └── when the position is not healthy - ├── when seizedAssets is not zero - │ ├── it should compute assetsRepaid = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor(marketParams.lltv)) - │ └── it should compute repaidShares = assetsRepaid.toSharesDown(totalBorrow[marketParams.id], totalBorrowShares[market.id]) - ├── when repaidShares is not zero - │ ├── it should compute assetsRepaid = repaidShares.toAssetsUp(totalBorrow[marketParams.id], totalBorrowShares[marketParams.id]) - │ └── it should compute seizedAssets = assetsRepaid.wMulDown(liquidationIncentiveFactor).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice) - ├── it should remove repaidShares from totalBorrowShares[marketParams.id] - ├── it should remove assetsRepaid from totalBorrow[marketParams.id] - ├── it should remove repaidShares from collateral[marketParams.id][borrower] - ├── if after the liquidation the borrower's collateral is 0 - │ └── it should realize bad debt - │ ├── it should compute badDebt = borrowShares[marketParams.id][borrower].toAssetsUp(totalBorrow[marketParams.id], totalBorrowShares[marketParams.id]) - │ ├── it should remove badDebt from totalSupplyAssets[marketParams.id] - │ ├── it should remove badDebt from totalBorrowAssets[marketParams.id] - │ ├── it should remove borrowShares[marketParams.id][borrower] from totalBorrowShares[marketParams.id] - │ └── it should set borrowShares[marketParams.id][borrower] to 0 - ├── it should transfer repaidShares of collateral asset to the sender - ├── it should emit Liquidate(marketParams.id, msg.sender, borrower, assetsRepaid, repaidShares, seizedAssets, badDebtShares) - ├── if data.length > 0 - │ └── it should call sender's onMorphoLiquidate callback - └── it should transfer assetsRepaid of loan asset from the sender to Morpho -. -└── flashLoan(address token, uint256 assets, bytes calldata data) external - ├── it should transfer assets of token from Morpho to the sender - ├── it should call sender's onMorphoFlashLoan callback - ├── it should emit FlashLoan(msg.sender, token, assets) - └── it should transfer assets of token from the sender to Morpho -. -└── setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external - ├── when block.timestamp > authorization.deadline - │ └── revert with SIGNATURE_EXPIRED - └── when block.timestamp <= deadline - ├── when authorization.nonce != nonce[authorization.authorizer] - │ └── revert with INVALID_NONCE - └── when authorization.nonce == nonce[authorization.authorizer] - ├── when the signature is invalid or not signed by authorization.authorizer - │ └── revert with INVALID_SIGNATURE - └── when the signature is valid and signed by authorization.authorizer - ├── it should increment authorization.authorizer's nonce - ├── it should emit IncrementNonce(msg.sender, authorization.authorizer, authorization.nonce) - ├── it should set isAuthorized[authorization.authorizer][authorization.authorized] to authorization.isAuthorized - └── it should emit SetAuthorization(msg.sender, authorization.authorizer, authorization.authorized, authorization.isAuthorized) -. -└── setAuthorization(address authorized, bool newIsAuthorized) external - ├── should set isApproved[msg.sender][authorized] to newIsAuthorized - └── it should emit SetAuthorization(msg.sender, msg.sender, authorized, newIsAuthorized) -. -└── accrueInterest(MarketParams memory marketParams) external - ├── when market is not created - │ └── revert with MARKET_NOT_CREATED - └── when market is created - └── it should accrue the interest -. -└── _accrueInterest(MarketParams memory marketParams, Id id) internal - └── when interest not already accrued in the block - ├── it should set lastUpdate to block.timestamp - └── when marketTotalBorrow is not 0 - ├── it should compute accruedInterest = marketTotalBorrow.wMulDown(borrowRate.wTaylorCompounded(elapsed)) - ├── it should add accruedInterest to totalBorrowAssets - ├── it should add accruedInterest to totalSupplyAssets - └── when fee[id] != 0 - │ ├── it should add accruedInterest.wMulDown(fee[id]) to feeAmount - │ ├── it should add feeAmount.mulDivDown(totalSupplyShares[id], totalSupplyAssets[id] - feeAmount) to supplyShares[id][feeRecipient] - │ └── it should add feeAmount.mulDivDown(totalSupplyShares[id], totalSupplyAssets[id] - feeAmount) to totalSupplyShares[id] - └── it should emit AccrueInterest(id, borrowRate, accruedInterest, feeShares) -. -└── _isHealthy(MarketParams memory marketParams, Id id, address user, uint256 collateralPrice) internal - ├── it should compute borrowed = borrowShares[id][user].toAssetsUp(totalBorrowAssets[id], totalBorrowShares[id]) - ├── it should compute maxBorrow = collateral[id][user].mulDivDown(collateralPrice, ORACLE_PRICE_SCALE).wMulDown(marketParams.lltv) - └── it should return maxBorrow >= borrowed -. -└── liquidationIncentiveFactor(uint256 lltv) internal - └── it should return min(MAX_LIQUIDATION_INCENTIVE_FACTOR, WAD.wDivDown(WAD - LIQUIDATION_CURSOR.wMulDown(WAD - lltv)))