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

Update lastTotalAsset in updateWithdrawQueue #2

Closed
wants to merge 3 commits into from
Closed
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
20 changes: 19 additions & 1 deletion src/MetaMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {MorphoLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoLib.so
import {MarketParamsLib} from "../lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {MorphoBalancesLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoBalancesLib.sol";
import {MorphoStorageLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoStorageLib.sol";

import {Multicall} from "../lib/openzeppelin-contracts/contracts/utils/Multicall.sol";
import {Ownable2Step, Ownable} from "../lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol";
Expand All @@ -48,6 +49,7 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph
using MorphoLib for IMorpho;
using SharesMathLib for uint256;
using MorphoBalancesLib for IMorpho;
using MorphoStorageLib for Id;
using MarketParamsLib for MarketParams;
using PendingLib for MarketConfig;
using PendingLib for PendingUint192;
Expand Down Expand Up @@ -350,6 +352,8 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph
bool[] memory seen = new bool[](currLength);
Id[] memory newWithdrawQueue = new Id[](newLength);

uint256 lostAssets;

for (uint256 i; i < newLength; ++i) {
uint256 prevIndex = indexes[i];

Expand All @@ -367,12 +371,23 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph

if (config[id].cap != 0) revert ErrorsLib.InvalidMarketRemovalNonZeroCap(id);

if (MORPHO.supplyShares(id, address(this)) != 0) {
uint256 supplyShares = MORPHO.supplyShares(id, address(this));

if (supplyShares != 0) {
if (config[id].removableAt == 0) revert ErrorsLib.InvalidMarketRemovalNonZeroSupply(id);

if (block.timestamp < config[id].removableAt) {
revert ErrorsLib.InvalidMarketRemovalTimelockNotElapsed(id);
}

bytes32[] memory slot = new bytes32[](1);
slot[0] = id.marketTotalSupplyAssetsAndSharesSlot();
bytes32[] memory res = MORPHO.extSloads(slot);

uint256 totalSupplyAssets = uint128(uint256(res[0]));
uint256 totalSupplyShares = uint256(res[0] >> 128);

lostAssets += supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);
}

delete config[id];
Expand All @@ -381,6 +396,9 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph

withdrawQueue = newWithdrawQueue;

// Accrue interests on all the enabled markets except the removed ones.
_updateLastTotalAssets(lastTotalAssets.zeroFloorSub(lostAssets));

emit EventsLib.SetWithdrawQueue(_msgSender(), newWithdrawQueue);
}

Expand Down
54 changes: 53 additions & 1 deletion test/forge/MarketTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,59 @@ contract MarketTest is IntegrationTest {
assertEq(Id.unwrap(vault.withdrawQueue(3)), Id.unwrap(expectedWithdrawQueue[3]));
}

function testUpdateWithdrawQueueRemovingDisabledMarket() public {
function testUpdateWithdrawQueueRemovingDisabledMarket(uint256 firstAmountSupplied, uint256 secondAmountSupplied)
public
{
firstAmountSupplied = bound(firstAmountSupplied, MIN_TEST_ASSETS, MAX_TEST_ASSETS);
secondAmountSupplied = bound(secondAmountSupplied, MIN_TEST_ASSETS, MAX_TEST_ASSETS);

_setCap(allMarkets[0], firstAmountSupplied);
_setCap(allMarkets[1], secondAmountSupplied);

Id[] memory supplyQueue = new Id[](2);
supplyQueue[0] = allMarkets[0].id();
supplyQueue[1] = allMarkets[1].id();

_setCap(allMarkets[0], firstAmountSupplied);
_setCap(allMarkets[1], secondAmountSupplied);
Comment on lines +168 to +169
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it done twice?

vm.prank(ALLOCATOR);
vault.setSupplyQueue(supplyQueue);

loanToken.setBalance(SUPPLIER, firstAmountSupplied + secondAmountSupplied);

vm.prank(SUPPLIER);
vault.deposit(firstAmountSupplied + secondAmountSupplied, ONBEHALF);

_setCap(allMarkets[1], 0);

vm.prank(CURATOR);
vault.submitMarketRemoval(allMarkets[1].id());

vm.warp(block.timestamp + TIMELOCK);

uint256[] memory indexes = new uint256[](3);
indexes[0] = 0;
indexes[1] = 1;
indexes[2] = 3;

Id[] memory expectedWithdrawQueue = new Id[](3);
expectedWithdrawQueue[0] = idleParams.id();
expectedWithdrawQueue[1] = allMarkets[0].id();
expectedWithdrawQueue[2] = allMarkets[2].id();

vm.expectEmit();
emit EventsLib.SetWithdrawQueue(ALLOCATOR, expectedWithdrawQueue);
Comment on lines +195 to +196
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool to have tested this here but I think it's out of context, better than removing it now, but next time I think it's better to have isolated purpose tests 😁

vm.prank(ALLOCATOR);
vault.updateWithdrawQueue(indexes);

assertEq(Id.unwrap(vault.withdrawQueue(0)), Id.unwrap(expectedWithdrawQueue[0]));
assertEq(Id.unwrap(vault.withdrawQueue(1)), Id.unwrap(expectedWithdrawQueue[1]));
assertEq(Id.unwrap(vault.withdrawQueue(2)), Id.unwrap(expectedWithdrawQueue[2]));
assertFalse(vault.config(allMarkets[1].id()).enabled);
assertEq(vault.totalAssets(), firstAmountSupplied);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we need to check lastTotalAssets! And check that the fee accrued after the next interaction is as expected!

}

function testUpdateWithdrawQueueRemovingDisabledMarketWithSupply() public {
_setCap(allMarkets[2], 0);

vm.prank(CURATOR);
Expand Down
Loading