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

alternative fix #11

Merged
merged 11 commits into from
Feb 16, 2024
35 changes: 23 additions & 12 deletions src/PublicAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import {
} from "../lib/metamorpho/src/interfaces/IMetaMorpho.sol";

import {MarketParamsLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/MarketParamsLib.sol";

import {MorphoBalancesLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/periphery/MorphoBalancesLib.sol";

import {Market} from "../lib/metamorpho/lib/morpho-blue/src/interfaces/IMorpho.sol";

import {UtilsLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/UtilsLib.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";
Expand Down Expand Up @@ -86,34 +86,45 @@ contract PublicAllocator is IPublicAllocatorStaticTyping {
if (msg.value != fee) revert ErrorsLib.IncorrectFee();

MarketAllocation[] memory allocations = new MarketAllocation[](withdrawals.length + 1);
allocations[withdrawals.length].marketParams = depositMarketParams;
allocations[withdrawals.length].assets = type(uint256).max;

Id depositMarketId = depositMarketParams.id();
uint128 totalWithdrawn;

for (uint256 i = 0; i < withdrawals.length; i++) {
Id id = withdrawals[i].marketParams.id();
MORPHO.accrueInterest(withdrawals[i].marketParams);

// Revert if the market is elsewhere in the list, or is the deposit market.
for (uint256 j = i + 1; j < withdrawals.length; j++) {
if (Id.unwrap(id) == Id.unwrap(withdrawals[j].marketParams.id())) {
revert ErrorsLib.InconsistentWithdrawTo();
}
}
if (Id.unwrap(id) == Id.unwrap(depositMarketId)) revert ErrorsLib.InconsistentWithdrawTo();

uint128 withdrawnAssets = withdrawals[i].amount;
totalWithdrawn += withdrawnAssets;

MORPHO.accrueInterest(withdrawals[i].marketParams);
uint256 assets = MORPHO.expectedSupplyAssets(withdrawals[i].marketParams, address(VAULT));

allocations[i].marketParams = withdrawals[i].marketParams;
allocations[i].assets =
MORPHO.expectedSupplyAssets(withdrawals[i].marketParams, address(VAULT)) - withdrawnAssets;
allocations[i].assets = assets - withdrawnAssets;
flowCap[id].maxIn += withdrawnAssets;
flowCap[id].maxOut -= withdrawnAssets;

emit EventsLib.PublicWithdrawal(id, withdrawnAssets);
}

allocations[withdrawals.length].marketParams = depositMarketParams;
allocations[withdrawals.length].assets = type(uint256).max;
flowCap[depositMarketId].maxIn -= totalWithdrawn;
flowCap[depositMarketId].maxOut += totalWithdrawn;

VAULT.reallocate(allocations);

Id depositMarketId = depositMarketParams.id();
uint256 vaultSupplyInMarket = MORPHO.expectedSupplyAssets(depositMarketParams, address(VAULT));
if (vaultSupplyInMarket > supplyCap[depositMarketId]) {
if (MORPHO.expectedSupplyAssets(depositMarketParams, address(VAULT)) > supplyCap[depositMarketId]) {
revert ErrorsLib.PublicAllocatorSupplyCapExceeded(depositMarketId);
}
flowCap[depositMarketId].maxIn -= totalWithdrawn;
flowCap[depositMarketId].maxOut += totalWithdrawn;

emit EventsLib.PublicReallocateTo(msg.sender, depositMarketId, totalWithdrawn);
}

Expand Down
6 changes: 5 additions & 1 deletion src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Id} from "../../lib/metamorpho/src/interfaces/IMetaMorpho.sol";
import {Id, MarketParams} from "../../lib/metamorpho/src/interfaces/IMetaMorpho.sol";
import {Withdrawal} from "../interfaces/IPublicAllocator.sol";

/// @title ErrorsLib
/// @author Morpho Labs
Expand Down Expand Up @@ -38,6 +39,9 @@ library ErrorsLib {
/// @notice Thrown when the value is already set.
error AlreadySet();

/// @notice Thrown when there are duplicates with nonzero assets in `withdrawTo` arguments.
error InconsistentWithdrawTo();

/// @notice Thrown when attempting to set max inflow/outflow above the MAX_SETTABLE_FLOW_CAP.
error MaxSettableFlowCapExceeded();

Expand Down
File renamed without changes.
27 changes: 27 additions & 0 deletions test/PublicAllocator.t.sol → test/PublicAllocatorTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,33 @@ contract PublicAllocatorTest is IntegrationTest {
assertEq(marketAfter - marketBefore, flow);
}

function testDuplicateInWithdrawals() public {
// Set flow limits
flowCaps.push(FlowConfig(idleParams.id(), FlowCap(MAX_SETTABLE_FLOW_CAP, MAX_SETTABLE_FLOW_CAP)));
flowCaps.push(FlowConfig(allMarkets[0].id(), FlowCap(MAX_SETTABLE_FLOW_CAP, 0)));
vm.prank(OWNER);
publicAllocator.setFlowCaps(flowCaps);

// Prepare public reallocation from 2 markets to 1
// _setCap(allMarkets[1], CAP2);
withdrawals.push(Withdrawal(idleParams, 1e18));
withdrawals.push(Withdrawal(idleParams, 1e18));
vm.expectRevert(ErrorsLib.InconsistentWithdrawTo.selector);
publicAllocator.withdrawTo(withdrawals, allMarkets[0]);
}

function testSameInWithdrawalAndDeposit() public {
// Set flow limits
flowCaps.push(FlowConfig(idleParams.id(), FlowCap(MAX_SETTABLE_FLOW_CAP, MAX_SETTABLE_FLOW_CAP)));
flowCaps.push(FlowConfig(allMarkets[0].id(), FlowCap(MAX_SETTABLE_FLOW_CAP, 0)));
vm.prank(OWNER);
publicAllocator.setFlowCaps(flowCaps);

withdrawals.push(Withdrawal(idleParams, 1e18));
vm.expectRevert(ErrorsLib.InconsistentWithdrawTo.selector);
publicAllocator.withdrawTo(withdrawals, idleParams);
}

function testMaxFlowCapValue() public {
assertEq(MAX_SETTABLE_FLOW_CAP, type(uint128).max / 2);
}
Expand Down