diff --git a/contracts/OutflowLimitedAMMSV.sol b/contracts/OutflowLimitedAMMSV.sol index fa7943d..0fd6355 100644 --- a/contracts/OutflowLimitedAMMSV.sol +++ b/contracts/OutflowLimitedAMMSV.sol @@ -56,7 +56,8 @@ contract OutflowLimitedAMMSV is AccessManagedMSV { * WARNING: changing the slotSize effectivelly resets the recorded outflows, so after this call (if slotSize * changed), the delta will be zero. * - * @param slotSize The duration in seconds of the timeframe used to limit the amount of outflows. + * @param slotSize The duration in seconds of the timeframe used to limit the amount of outflows. Setting slotSize + * to zero disables the outflow limit checks and the vault behaves like a normal AccessManagedMSV * @param limit The max amount of outflows that will be allowed in a given time slot. */ function setupOutflowLimit(uint256 slotSize, uint256 limit) external { @@ -132,26 +133,32 @@ contract OutflowLimitedAMMSV is AccessManagedMSV { uint256 assets, uint256 shares ) internal virtual override { - SlotIndex slot = _slotIndex(); - - // Check delta doesn't exceed the threshold - SlotIndex prevSlot = SlotIndex.wrap(SlotIndex.unwrap(slot) - 1); LOMStorage storage $ = _getLOMStorage(); - int256 deltaLastTwoSlots = -int256(assets) + $.assetsDelta[slot] + $.assetsDelta[prevSlot]; - // To check the limit, uses TWO slots, the current one and the previous one. This is to avoid someone doing - // several operations in the slot limit, like withdrawal at 11:59PM and another withdrawal at 12:01 AM. - if (deltaLastTwoSlots < 0 && uint256(-deltaLastTwoSlots) > $.limit) revert LimitReached(deltaLastTwoSlots, $.limit); - - // Update the delta and pass the message to parent contract - $.assetsDelta[slot] -= assets.toInt256(); + if ($.slotSize != 0) { + SlotIndex slot = _slotIndex(); + + // Check delta doesn't exceed the threshold + SlotIndex prevSlot = SlotIndex.wrap(SlotIndex.unwrap(slot) - 1); + int256 deltaLastTwoSlots = -int256(assets) + $.assetsDelta[slot] + $.assetsDelta[prevSlot]; + // To check the limit, uses TWO slots, the current one and the previous one. This is to avoid someone doing + // several operations in the slot limit, like withdrawal at 11:59PM and another withdrawal at 12:01 AM. + if (deltaLastTwoSlots < 0 && uint256(-deltaLastTwoSlots) > $.limit) + revert LimitReached(deltaLastTwoSlots, $.limit); + + // Update the delta and pass the message to parent contract + $.assetsDelta[slot] -= assets.toInt256(); + } super._withdraw(caller, receiver, owner, assets, shares); } /// @inheritdoc ERC4626Upgradeable function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override { - // Just update the delta and pass the message to parent contract - SlotIndex slot = _slotIndex(); - _getLOMStorage().assetsDelta[slot] += assets.toInt256(); + LOMStorage storage $ = _getLOMStorage(); + if ($.slotSize != 0) { + // Just update the delta and pass the message to parent contract + SlotIndex slot = _slotIndex(); + $.assetsDelta[slot] += assets.toInt256(); + } super._deposit(caller, receiver, assets, shares); } } diff --git a/test/test-compound-v3-vault.js b/test/test-compound-v3-vault.js index 74544e3..4fa3a36 100644 --- a/test/test-compound-v3-vault.js +++ b/test/test-compound-v3-vault.js @@ -335,7 +335,7 @@ const variants = [ tagit: tagit, cToken: ADDRESSES.cUSDCv3, supplyToken: ADDRESSES.USDC, - fixture: async () => { + fixture: async (accessManagedMSVClass = "AccessManagedMSV") => { const { currency, adminAddr, swapConfig, admin, lp, lp2, guardian, anon, swapLibrary } = await setUp(); const CompoundV3InvestStrategy = await ethers.getContractFactory("CompoundV3InvestStrategy", { libraries: { @@ -344,7 +344,7 @@ const variants = [ }); const strategy = await CompoundV3InvestStrategy.deploy(ADDRESSES.cUSDCv3, ADDRESSES.REWARDS); const AccessManager = await ethers.getContractFactory("AccessManager"); - const AccessManagedMSV = await ethers.getContractFactory("AccessManagedMSV"); + const AccessManagedMSV = await ethers.getContractFactory(accessManagedMSVClass); const AccessManagedProxy = await ethers.getContractFactory("AccessManagedProxy"); const acMgr = await AccessManager.deploy(admin); @@ -522,6 +522,14 @@ const variants = [ }, ]; +// Checks an OutflowLimitiedAMMSV without slotSize set behaves the same way as AccessManagedMSV +const compAccessVariant = variants.find((variant) => variant.name === "CompoundV3Strategy+AccessManaged"); +variants.push({ + ...compAccessVariant, + name: "CompoundV3Strategy+OutflowLimitiedAMMSV", + fixture: async () => compAccessVariant.fixture("OutflowLimitedAMMSV"), +}); + variants.forEach((variant) => { describe(`${variant.name} contract tests`, function () { before(async () => {