From 3c5e1ce0ed9db1f48f7bc11fe64ae5ecc578fd1e Mon Sep 17 00:00:00 2001 From: eukadish Date: Wed, 18 Sep 2024 16:54:41 -0400 Subject: [PATCH 1/4] add check for passing test --- test/morpho/MorphoUnderlyingAdapter.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/test/morpho/MorphoUnderlyingAdapter.t.sol b/test/morpho/MorphoUnderlyingAdapter.t.sol index cac67d4..d66b3a2 100644 --- a/test/morpho/MorphoUnderlyingAdapter.t.sol +++ b/test/morpho/MorphoUnderlyingAdapter.t.sol @@ -498,6 +498,7 @@ contract MorphoUnderlyingAdapterTest is Test { function testRecover(uint256 _amount, address _reciever) external { vm.assume(_reciever != address(0)); + vm.assume(_reciever != address(adapter)); ERC20 testToken = new ERC20("Test Token", "TTT"); deal(address(testToken), address(adapter), _amount); From 5b79a766893551eb487791deebfbfc958312c836 Mon Sep 17 00:00:00 2001 From: eukadish Date: Wed, 18 Sep 2024 18:47:22 -0400 Subject: [PATCH 2/4] add mainnet rpc url for hard fork --- .env.template | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.env.template b/.env.template index c802988..5de79f3 100644 --- a/.env.template +++ b/.env.template @@ -5,6 +5,8 @@ PRIVATE_KEY= # RPC_URL=http://127.0.0.1:8545 RPC_URL=https://gateway.tenderly.co/public/polygon +MAINNET_RPC_URL=https://eth-mainnet.nodereal.io/v1/1659dfb40aa24bbb8153a677b98064d7 + ETHERSCAN_API_KEY= OWNER= From 3afae1b0bdfad154928f2ab0f4917e49afed8323 Mon Sep 17 00:00:00 2001 From: Nika Khachiashvili Date: Tue, 1 Oct 2024 15:50:24 -0400 Subject: [PATCH 3/4] fix [HAL-04]: Unintended Burning of Excess Stablecoins in Redeem Function --- src/adapters/MorphoRUSDAdapter.sol | 11 +++++--- test/morpho/MorphoRUSDAdapter.t.sol | 40 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/adapters/MorphoRUSDAdapter.sol b/src/adapters/MorphoRUSDAdapter.sol index 02f79ac..7568a03 100644 --- a/src/adapters/MorphoRUSDAdapter.sol +++ b/src/adapters/MorphoRUSDAdapter.sol @@ -60,10 +60,15 @@ contract MorphoRUSDAdapter is IAssetAdapter, AccessControl { function redeem(uint256 shares) public onlyRole(CONTROLLER) { Stablecoin underlyingStablecoin = Stablecoin(address(underlying)); + + uint256 initialBalance = underlyingStablecoin.balanceOf(address(this)); + vault.redeem(shares, address(this), address(this)); - underlyingStablecoin.burn( - underlyingStablecoin.balanceOf(address(this)) - ); + + uint256 receivedAmount = underlyingStablecoin.balanceOf(address(this)) - + initialBalance; + + underlyingStablecoin.burn(receivedAmount); emit Redeem(msg.sender, shares, block.timestamp); } diff --git a/test/morpho/MorphoRUSDAdapter.t.sol b/test/morpho/MorphoRUSDAdapter.t.sol index 4f548e7..8db5bca 100644 --- a/test/morpho/MorphoRUSDAdapter.t.sol +++ b/test/morpho/MorphoRUSDAdapter.t.sol @@ -255,6 +255,25 @@ contract MorphoRUSDAdapterTest is Test { assertEq(adapter.fundBalance(), metamorpho.balanceOf(address(adapter))); } + function test_redeem_with_accidental_sent_tokens( + uint256 depositAmount, + uint256 redeemAmount, + uint256 accidentalySentAmount + ) external { + vm.assume(depositAmount <= 1_000_000_000e18); + vm.assume(redeemAmount <= depositAmount); + vm.assume(accidentalySentAmount <= 1_000_000_000e18); + + adapter.deposit(depositAmount); + + deal(address(rusd), address(this), accidentalySentAmount, true); + rusd.transfer(address(adapter), accidentalySentAmount); + + adapter.redeem(redeemAmount); + + assertEq(rusd.balanceOf(address(adapter)), accidentalySentAmount); + } + //! DONT KNOW WHATS THE REAL CAP // function testDepositMoreThenCap(uint256 amount) external { // vm.assume(amount > CAP); @@ -330,4 +349,25 @@ contract MorphoRUSDAdapterTest is Test { vm.expectRevert(); adapter.setFundRiskWeight(riskWeight); } + + function test_recover(uint256 _amount) external { + ERC20 testToken = new ERC20("Test Token", "TTT"); + + deal(address(testToken), address(adapter), _amount); + + assertEq(testToken.balanceOf(address(this)), 0); + assertEq(testToken.balanceOf(address(adapter)), _amount); + + adapter.recover(address(testToken)); + + assertEq(testToken.balanceOf(address(this)), _amount); + assertEq(testToken.balanceOf(address(adapter)), 0); + } + + function test_recover_as_non_owner() external { + adapter.revokeRole(adapter.MANAGER(), address(this)); + + vm.expectRevert(); + adapter.recover(address(rusd)); + } } From 90b3c94fe1e4dc1032599d3abba688c28003b41a Mon Sep 17 00:00:00 2001 From: Nika Khachiashvili Date: Tue, 1 Oct 2024 15:53:18 -0400 Subject: [PATCH 4/4] fix [HAL-03] unsafe type casting --- src/adapters/MorphoRUSDAdapter.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/adapters/MorphoRUSDAdapter.sol b/src/adapters/MorphoRUSDAdapter.sol index 7568a03..352a19f 100644 --- a/src/adapters/MorphoRUSDAdapter.sol +++ b/src/adapters/MorphoRUSDAdapter.sol @@ -6,6 +6,7 @@ import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessContr import {IERC4626} from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {SafeCast} from "openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import {Stablecoin} from "../Stablecoin.sol"; import {IOracle} from "src/interfaces/IOracle.sol"; @@ -192,13 +193,13 @@ contract MorphoRUSDAdapter is IAssetAdapter, AccessControl { { int256 latestAnswer = underlyingPriceOracle.latestAnswer(); - return latestAnswer > 0 ? uint256(latestAnswer) : 0; + return latestAnswer > 0 ? SafeCast.toUint256(latestAnswer) : 0; } function _fundPriceOracleLatestAnswer() private view returns (uint256) { int256 latestAnswer = fundPriceOracle.latestAnswer(); - return latestAnswer > 0 ? uint256(latestAnswer) : 0; + return latestAnswer > 0 ? SafeCast.toUint256(latestAnswer) : 0; } function recover(address _token) external onlyRole(MANAGER) {