diff --git a/contracts/strategy/StrategyLib.sol b/contracts/strategy/StrategyLib.sol index ec616fd..8260ebf 100644 --- a/contracts/strategy/StrategyLib.sol +++ b/contracts/strategy/StrategyLib.sol @@ -118,9 +118,8 @@ library StrategyLib { uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0; uint withdrewUSD = withdrew * assetPrice / 1e18; - uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee(); uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0; - require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH); + require(difference * 1e18 / expectedWithdrewUSD < 1e16, TOO_HIGH); } } diff --git a/contracts/vault/ERC4626Upgradeable.sol b/contracts/vault/ERC4626Upgradeable.sol index 0e9cd7d..6607b98 100644 --- a/contracts/vault/ERC4626Upgradeable.sol +++ b/contracts/vault/ERC4626Upgradeable.sol @@ -21,6 +21,15 @@ abstract contract ERC4626Upgradeable is ERC20PermitUpgradeable, ReentrancyGuard, /// depositing, and withdrawing IERC20 internal _asset; + uint internal _withdrawLoss; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint[50 - 2] private __gap; + function __ERC4626_init( IERC20 asset_, string memory _name, @@ -114,6 +123,12 @@ abstract contract ERC4626Upgradeable is ERC20PermitUpgradeable, ReentrancyGuard, _burn(owner, shares); + uint withdrawLoss = _withdrawLoss; + if (withdrawLoss != 0) { + assets -= withdrawLoss; + _withdrawLoss = 0; + } + emit Withdraw(msg.sender, receiver, owner, assets, shares); _asset.safeTransfer(receiver, assets); @@ -143,6 +158,12 @@ abstract contract ERC4626Upgradeable is ERC20PermitUpgradeable, ReentrancyGuard, _burn(owner, shares); + uint withdrawLoss = _withdrawLoss; + if (withdrawLoss != 0) { + assets -= withdrawLoss; + _withdrawLoss = 0; + } + emit Withdraw(msg.sender, receiver, owner, assets, shares); _asset.safeTransfer(receiver, assets); @@ -216,11 +237,4 @@ abstract contract ERC4626Upgradeable is ERC20PermitUpgradeable, ReentrancyGuard, /// @param receiver The receiver of the shares received after deposit function afterDeposit(uint assets, uint shares, address receiver) internal virtual {} - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint[49] private __gap; } diff --git a/contracts/vault/TetuVaultV2.sol b/contracts/vault/TetuVaultV2.sol index ef27b95..fb0169e 100644 --- a/contracts/vault/TetuVaultV2.sol +++ b/contracts/vault/TetuVaultV2.sol @@ -1,5 +1,4 @@ // SPDX-License-Identifier: BUSL-1.1 - pragma solidity 0.8.17; import "../openzeppelin/Math.sol"; @@ -11,6 +10,7 @@ import "./ERC4626Upgradeable.sol"; /// @title Vault for storing underlying tokens and managing them with strategy splitter. /// @author belbix +/// @author a17 contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { using SafeERC20 for IERC20; using Math for uint; @@ -20,13 +20,14 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { // ************************************************************* /// @dev Version of this contract. Adjust manually on each code modification. - string public constant VAULT_VERSION = "2.2.0"; + string public constant VAULT_VERSION = "3.0.0"; + /// @dev Denominator for buffer calculation. 100% of the buffer amount. uint constant public BUFFER_DENOMINATOR = 100_000; - /// @dev Denominator for fee calculation. - uint constant public FEE_DENOMINATOR = 100_000; - /// @dev Max 1% fee. - uint constant public MAX_FEE = FEE_DENOMINATOR / 100; + + uint constant internal SLIPPAGE_DENOMINATOR = 100_000; // 100% + + uint constant internal MAX_WITHDRAW_SLIPPAGE = 500; // 0.5% // ************************************************************* // VARIABLES @@ -43,13 +44,13 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { /// @dev Percent of assets that will always stay in this vault. uint public buffer; - /// @dev Maximum amount for withdraw. Max UINT256 by default. + /// @dev Maximum amount for withdraw. Max uint by default. uint public maxWithdrawAssets; - /// @dev Maximum amount for redeem. Max UINT256 by default. + /// @dev Maximum amount for redeem. Max uint by default. uint public maxRedeemShares; - /// @dev Maximum amount for deposit. Max UINT256 by default. + /// @dev Maximum amount for deposit. Max uint by default. uint public maxDepositAssets; - /// @dev Maximum amount for mint. Max UINT256 by default. + /// @dev Maximum amount for mint. Max uint by default. uint public maxMintShares; /// @dev Fee for deposit/mint actions. Zero by default. uint public override depositFee; @@ -83,9 +84,7 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { event Invest(address splitter, uint amount); event MaxWithdrawChanged(uint maxAssets, uint maxShares); event MaxDepositChanged(uint maxAssets, uint maxShares); - event FeeChanged(uint depositFee, uint withdrawFee); event DoHardWorkOnInvestChanged(bool oldValue, bool newValue); - event FeeTransfer(uint amount); event LossCovered(uint amount, uint requestedAmount, uint balance); event WithdrawRequested(address sender, uint startBlock); event WithdrawRequestBlocks(uint blocks); @@ -183,16 +182,6 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { emit MaxWithdrawChanged(maxAssets, maxShares); } - /// @dev Set deposit/withdraw fees - function setFees(uint _depositFee, uint _withdrawFee) external { - require(isGovernance(msg.sender), "DENIED"); - require(_depositFee <= MAX_FEE && _withdrawFee <= MAX_FEE, "TOO_HIGH"); - - depositFee = _depositFee; - withdrawFee = _withdrawFee; - emit FeeChanged(_depositFee, _withdrawFee); - } - /// @dev If activated will call doHardWork on splitter on each invest action. function setDoHardWorkOnInvest(bool value) external { require(isGovernance(msg.sender), "DENIED"); @@ -229,7 +218,7 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { /// @dev Price of 1 full share function sharePrice() external view returns (uint) { - uint units = 10 ** uint256(decimals()); + uint units = 10 ** uint(decimals()); uint totalSupply_ = totalSupply(); return totalSupply_ == 0 ? units @@ -246,18 +235,15 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { // ************************************************************* function previewDeposit(uint assets) public view virtual override returns (uint) { - uint shares = convertToShares(assets); - return shares - (shares * depositFee / FEE_DENOMINATOR); + return convertToShares(assets); } function previewMint(uint shares) public view virtual override returns (uint) { uint supply = totalSupply(); if (supply != 0) { - uint assets = shares.mulDiv(totalAssets(), supply, Math.Rounding.Up); - return assets * FEE_DENOMINATOR / (FEE_DENOMINATOR - depositFee); - } else { - return shares * FEE_DENOMINATOR / (FEE_DENOMINATOR - depositFee); + return shares.mulDiv(totalAssets(), supply, Math.Rounding.Up); } + return shares; } /// @dev Calculate available to invest amount and send this amount to splitter @@ -269,14 +255,7 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { address _splitter = address(splitter); IERC20 asset_ = _asset; - uint _depositFee = depositFee; - // send fee to insurance contract - if (_depositFee != 0) { - uint toFees = assets * _depositFee / FEE_DENOMINATOR; - asset_.safeTransfer(address(insurance), toFees); - emit FeeTransfer(toFees); - } - uint256 toInvest = _availableToInvest(_splitter, asset_); + uint toInvest = _availableToInvest(_splitter, asset_); // invest only when buffer is filled if (toInvest > 0) { @@ -331,12 +310,10 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { return assets; } uint shares = assets.mulDiv(supply, _totalAssets, Math.Rounding.Up); - shares = shares * FEE_DENOMINATOR / (FEE_DENOMINATOR - withdrawFee); return supply == 0 ? assets : shares; } function previewRedeem(uint shares) public view virtual override returns (uint) { - shares = shares - (shares * withdrawFee / FEE_DENOMINATOR); return convertToAssets(shares); } @@ -350,7 +327,6 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { function maxWithdraw(address owner) public view override returns (uint) { uint assets = convertToAssets(balanceOf(owner)); - assets -= assets.mulDiv(withdrawFee, FEE_DENOMINATOR, Math.Rounding.Up); return Math.min(maxWithdrawAssets, assets); } @@ -369,14 +345,7 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { withdrawRequests[owner_] = block.number; } - uint _withdrawFee = withdrawFee; - uint fromSplitter; - if (_withdrawFee != 0) { - // add fee amount - fromSplitter = assets * FEE_DENOMINATOR / (FEE_DENOMINATOR - _withdrawFee); - } else { - fromSplitter = assets; - } + uint fromSplitter = assets; IERC20 asset_ = _asset; uint balance = asset_.balanceOf(address(this)); @@ -392,19 +361,13 @@ contract TetuVaultV2 is ERC4626Upgradeable, ControllableV3, ITetuVaultV2 { ); } balance = asset_.balanceOf(address(this)); - require(assets <= balance, "SLIPPAGE"); - - // send fee amount to insurance for keep correct calculations - // in case of compensation it will lead to double transfer - // but we assume that it will be rare case - if (_withdrawFee != 0) { - // we should compensate possible slippage from user fee too - uint toFees = Math.min(fromSplitter - assets, balance - assets); - if (toFees != 0) { - asset_.safeTransfer(address(insurance), toFees); - emit FeeTransfer(toFees); - } + uint slippage; + if (assets > balance) { + uint withdrawLoss = assets - balance; + _withdrawLoss = withdrawLoss; + slippage = SLIPPAGE_DENOMINATOR * withdrawLoss / assets; } + require(slippage <= MAX_WITHDRAW_SLIPPAGE, "SLIPPAGE"); } /// @dev Do necessary calculation for withdrawing from splitter and move assets to vault. diff --git a/test/tools/SplitterRebalanceResolverTest.ts b/test/tools/SplitterRebalanceResolverTest.ts index d33bc28..aa113e6 100644 --- a/test/tools/SplitterRebalanceResolverTest.ts +++ b/test/tools/SplitterRebalanceResolverTest.ts @@ -118,7 +118,7 @@ describe("SplitterRebalanceResolverTest", function () { it("maxGasAdjusted", async () => { for (let i = 0; i < 30; i++) { const gas = formatUnits(await resolver.maxGasAdjusted(), 9); - console.log(i, gas); + // console.log(i, gas); await TimeUtils.advanceBlocksOnTs(60 * 60 * 24); } }); @@ -166,7 +166,7 @@ describe("SplitterRebalanceResolverTest", function () { it("execute call", async () => { const data = await resolver.checker(); expect(data.canExec).eq(true) - console.log('data.execPayload', data.execPayload) + // console.log('data.execPayload', data.execPayload) const vaultCall = SplitterRebalanceResolver__factory.createInterface().decodeFunctionData('call', data.execPayload).vault expect(vaultCall).eq(vault.address) diff --git a/test/vault/CheckWithdrawImpactTest.ts b/test/vault/CheckWithdrawImpactTest.ts index 2c9f0ee..12d80f6 100644 --- a/test/vault/CheckWithdrawImpactTest.ts +++ b/test/vault/CheckWithdrawImpactTest.ts @@ -95,7 +95,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { // prepare the strategy await strategy.init(controller.address, splitter.address); - await vault.setFees(0, withdrawFee); + // await vault.setFees(0, withdrawFee); // set strategy balance to expected value await asset.transfer(strategy.address, balanceAfterWithdraw); @@ -120,7 +120,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { parseUnits("99", 6), parseUnits("245", 6), // (99 - 50) * 5 parseUnits("5", 18), - 100 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ); expect(retBalance.eq(parseUnits("99", 6))).eq(true); }); @@ -131,7 +131,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { parseUnits("99", 8), parseUnits("245", 8), // (99 - 50) * 5 parseUnits("5", 18), - 100 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ); expect(retBalance.eq(parseUnits("99", 8))).eq(true); }); @@ -145,7 +145,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { parseUnits("99", 6), parseUnits("247", 6), // (99 - 50) * 5 + delta parseUnits("5", 18), - 1000 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ); expect(retBalance.eq(parseUnits("99", 6))).eq(true); }); @@ -156,7 +156,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { parseUnits("99", 8), parseUnits("247", 8), // (99 - 50) * 5 + delta parseUnits("5", 18), - 1000 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ); expect(retBalance.eq(parseUnits("99", 8))).eq(true); }); @@ -168,10 +168,10 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { makeCheckWithdrawImpactTest( usdc, parseUnits("50", 6), - parseUnits("99", 6), + parseUnits("90", 6), parseUnits("247", 6), // (99 - 50) * 5 + delta parseUnits("5", 18), - 100 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ) ).revertedWith("SB: Too high"); }); @@ -180,10 +180,10 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { makeCheckWithdrawImpactTest( usdc, parseUnits("50", 8), - parseUnits("99", 8), + parseUnits("90", 8), parseUnits("247", 8), // (99 - 50) * 5 + delta parseUnits("5", 18), - 100 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ) ).revertedWith("SB: Too high"); }); @@ -197,7 +197,7 @@ describe("Tests for StrategyBaseV2._checkWithdrawImpact", function () { parseUnits("99", 8), parseUnits("0", 8), // (!) investedAssetsUSD is zero parseUnits("0", 18), // (!) price is zero - 100 // fee denominator is 100_000 + 0 // fee denominator is 100_000 ); expect(retBalance.eq(parseUnits("99", 8))).eq(true); }); diff --git a/test/vault/SplitterForBaseStrategyV3Tests.ts b/test/vault/SplitterForBaseStrategyV3Tests.ts index a4814a0..1813c02 100644 --- a/test/vault/SplitterForBaseStrategyV3Tests.ts +++ b/test/vault/SplitterForBaseStrategyV3Tests.ts @@ -9,9 +9,9 @@ import { InterfaceIds, MockGauge, MockGauge__factory, + MockStrategyV3, MockStrategyV3__factory, - MockStrategySimple, - MockStrategySimple__factory, MockStrategyV3, + MockStrategySimple__factory, MockToken, StrategySplitterV2, TetuVaultV2 @@ -71,8 +71,6 @@ describe("SplitterForBaseStrategyV3Tests", function () { const forwarder = await DeployerUtils.deployContract(signer, 'MockForwarder') await controller.setForwarder(forwarder.address); - - }); after(async function () { @@ -117,6 +115,12 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect((await splitter.allStrategies()).length).eq(1); }); + it("refreshValidStrategies", async () => { + await strategy.init(controller.address, splitter.address); + await splitter.addStrategies([strategy.address], [100], [0]); + await splitter.refreshValidStrategies() + }); + it("set strategy with time lock test", async () => { await strategy.init(controller.address, splitter.address); await splitter.addStrategies([strategy.address], [100], [0]); @@ -371,7 +375,7 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect(await strategy3.totalAssets()).eq(10); expect(await usdc.balanceOf(splitter.address)).eq(999990); - console.log("REBALANCE 1 OK"); + // console.log("REBALANCE 1 OK"); await splitter.rebalance(100, 30) expect(await strategy.totalAssets()).eq(0); @@ -379,7 +383,7 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect(await strategy3.totalAssets()).eq(10); expect(await usdc.balanceOf(splitter.address)).eq(999980); - console.log("REBALANCE 2 OK"); + // console.log("REBALANCE 2 OK"); await splitter.rebalance(100, 30) expect(await strategy.totalAssets()).eq(10); @@ -493,43 +497,42 @@ describe("SplitterForBaseStrategyV3Tests", function () { it("withdraw all with slippage revert", async () => { await vault.deposit(1000, signer.address); - await strategy2.setSlippage(300); - await expect(vault.withdrawAll()).revertedWith("SLIPPAGE"); + await strategy2.setSlippage(601); + await expect(vault.withdrawAll()).revertedWith("SS: Loss too high"); }); it("withdraw all with slippage covering from insurance test", async () => { await vault.deposit(1000, signer.address); await strategy2.setSlippage(300); - await vault.setFees(0, 1_000) await vault.withdrawAll() }); - it("withdraw all with slippage covering from insurance not enough revert", async () => { + it("withdraw all with slippage NOT covering from insurance not enough revert", async () => { await vault.deposit(1000, signer.address); - await strategy2.setSlippage(300); - await vault.setFees(0, 250) - await expect(vault.withdrawAll()).revertedWith("SLIPPAGE"); + await strategy2.setSlippage(600); + // await vault.setFees(0, 250) + await expect(vault.withdrawAll()).revertedWith("SS: Loss too hig"); }); - it("withdraw with 100% slippage covering from insurance test", async () => { + it("withdraw with 100% slippage NOT covering from insurance test", async () => { await strategy2.setUseTrueExpectedWithdraw(true); - await strategy2.setSlippage(1_100); - await vault.setFees(1_000, 1_000) + await strategy2.setSlippage(10); + // await vault.setFees(1_000, 1_000) await vault.deposit(10_000_000, signer.address) - await expect(vault.withdraw(1000, signer.address, signer.address)).revertedWith("SB: Too high"); + await vault.withdraw(1000, signer.address, signer.address) await strategy2.setSlippage(1_000); - await vault.withdraw(1000, signer.address, signer.address); + await expect(vault.withdraw(1000, signer.address, signer.address)).revertedWith('SB: Too high'); }); // todo probably need to fix it("withdraw all with 100% slippage covering from insurance test", async () => { await vault.redeem(900, signer.address, signer.address) - await vault.setFees(100, 100) + await vault.deposit(1000_000, signer.address) await vault.withdrawAll(); await vault.deposit(10000, signer.address) await vault.connect(await Misc.impersonate('0xdEad000000000000000000000000000000000000')).transfer(signer.address, 1000); - await strategy2.setSlippage(300); + await strategy2.setSlippage(100); await vault.withdrawAll(); }); @@ -559,7 +562,7 @@ describe("SplitterForBaseStrategyV3Tests", function () { it("withdraw with slippage covering from insurance test", async () => { await vault.deposit(1000, signer.address); await strategy2.setSlippage(1_000); - await vault.setFees(0, 1_000) + // await vault.setFees(0, 1_000) await vault.withdraw(99, signer.address, signer.address,); }); @@ -605,23 +608,21 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect(await vault.sharePrice()).eq(999500); }); - it("deposit with loss with covering", async () => { + it("deposit with loss without covering", async () => { expect(await vault.sharePrice()).eq(1000000); await strategy2.setSlippageDeposit(100); - await vault.setFees(300, 0); await vault.deposit(1000_000, signer.address); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1997000); + expect(await vault.sharePrice()).eq(999500); + expect(await vault.totalAssets()).eq(1999000); }); - it("hardwork with loss with covering", async () => { + it("hardwork with loss without covering", async () => { expect(await vault.sharePrice()).eq(1000000); await strategy2.setSlippageHardWork(30); - await vault.setFees(1_000, 0); await vault.deposit(1000_000, signer.address); await splitter.doHardWorkForStrategy(strategy2.address, true); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1990000); + expect(await vault.sharePrice()).eq(999700); + expect(await vault.totalAssets()).eq(1999400); }); it("hardwork with loss without covering", async () => { @@ -647,19 +648,18 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect(await vault.totalAssets()).eq(1000750); }); - it("rebalance with loss with covering", async () => { + it("rebalance with loss WITHOUT covering", async () => { expect(await vault.sharePrice()).eq(1000000); await splitter.setAPRs([strategy.address], [200]); - await vault.setFees(1_000, 0); - await vault.deposit(1000_000, signer.address); + await vault.deposit(1_000_000, signer.address); await strategy.setSlippageDeposit(25); await splitter.rebalance(100, 30); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1990000); + expect(await vault.sharePrice()).eq(999875); + expect(await vault.totalAssets()).eq(1999750); }); it("rebalance with negative totalAssetsDelta", async () => { @@ -724,10 +724,25 @@ describe("SplitterForBaseStrategyV3Tests", function () { await strategy.connect(await Misc.impersonate(splitter.address)).investAll(0, true); }); + // describe("withdraw to splitter when enough balance test", () => { + // it("withdraw to splitter when the amount on balance is registered in baseAmounts", async () => { + // await usdc.transfer(strategy.address, parseUnits('1', 6)); + // // await strategy.setBaseAmount(await strategy.asset(), parseUnits('1', 6)); + // await strategy.connect(await Misc.impersonate(splitter.address)).withdrawToSplitter(parseUnits('1', 6)); + // }); + // it("revert when the amount on balance is partly not registered in baseAmounts", async () => { + // await usdc.transfer(strategy.address, parseUnits('1', 6)); + // await strategy.setBaseAmount(await strategy.asset(), parseUnits('0.5', 6)); + // await expect( + // strategy.connect(await Misc.impersonate(splitter.address)).withdrawToSplitter(parseUnits('1', 6)) + // ).revertedWith("SB: Wrong value"); // WRONG_VALUE + // }); + // }); + it("set compound ratio test", async () => { await controller.setPlatformVoter(signer.address); await strategy.setCompoundRatio(100); - expect(await strategy.compoundRatio()).eq(100) + await controller.setPlatformVoter(strategy.address); }); it("set compound ratio from not voter revert", async () => { @@ -773,20 +788,20 @@ describe("SplitterForBaseStrategyV3Tests", function () { }); }); describe("withdrawToVault", () => { - it("should cover expected loss if totalAssets-after is less than totalAssets-before", async () => { + it.skip("should cover expected loss if totalAssets-after is less than totalAssets-before", async () => { const insurance = await vault.insurance(); await splitter.addStrategies([strategy.address], [100], [0]); await usdc.mint(insurance, 50000); await vault.deposit(100000, signer.address); - await vault.setFees(0, 200) + // await vault.setFees(0, 200) const insuranceBefore = await usdc.balanceOf(insurance); await strategy.setSlippage(100); await vault.withdraw(50000, signer.address, signer.address); const insuranceAfter = await usdc.balanceOf(insurance); - expect(insuranceAfter).eq(50050); + expect(insuranceAfter).eq(49950); }); it("should not use insurance if totalAssets-after is greater than totalAssets-before", async () => { const insurance = await vault.insurance(); @@ -817,8 +832,8 @@ describe("SplitterForBaseStrategyV3Tests", function () { await vault.withdrawAll(); const insuranceAfter = await usdc.balanceOf(insurance); - console.log("insuranceBefore", insuranceBefore); - console.log("insuranceAfter", insuranceAfter); + // console.log("insuranceBefore", insuranceBefore); + // console.log("insuranceAfter", insuranceAfter); expect(insuranceAfter).eq(insuranceBefore.sub(10000)); }); // it("should not use insurance if totalAssets-after is greater than totalAssets-before", async () => { @@ -839,7 +854,7 @@ describe("SplitterForBaseStrategyV3Tests", function () { }); }); - it("should not change share price during insurance covering", async () => { + it("should not withdraw when MockStrategy has UseTrueExpectedWithdraw enabled, but in real slippage exist", async () => { const insurance = await vault.insurance(); await strategy.init(controller.address, splitter.address); @@ -859,36 +874,34 @@ describe("SplitterForBaseStrategyV3Tests", function () { expect(sharePriceBefore).eq(await vault.sharePrice()); - const insuranceBefore = await usdc.balanceOf(insurance); - console.log('insuranceBefore', insuranceBefore) + // const insuranceBefore = await usdc.balanceOf(insurance); + // console.log('insuranceBefore', insuranceBefore) await strategy.setUseTrueExpectedWithdraw(true) await strategy.setSlippage(10); - await vault.setFees(0, 1000) - await vault.withdrawAll(); + await expect(vault.withdrawAll()).revertedWith('SB: Too high') const insuranceAfter = await usdc.balanceOf(insurance); - console.log('insuranceAfter', insuranceAfter) - expect(insuranceAfter).eq(9891); - + // console.log('insuranceAfter', insuranceAfter) + expect(insuranceAfter).eq(0); expect(sharePriceBefore).eq(await vault.sharePrice()); }); it("should register loss with coverPossibleStrategyLoss call", async () => { await strategy.init(controller.address, splitter.address); - await vault.setFees(300, 300); + // await vault.setFees(300, 300); - console.log('add strategy') + // console.log('add strategy') await splitter.addStrategies([strategy.address], [100], [0]); - console.log('check not a strategy') + // console.log('check not a strategy') await expect(splitter.coverPossibleStrategyLoss(0, 500_000)).rejectedWith("SS: Invalid strategy"); - console.log('deposit') + // console.log('deposit') await vault.deposit(10_000_000, signer.address); - console.log('register huge loss revert') + // console.log('register huge loss revert') await expect(splitter.connect(await Misc.impersonate(strategy.address)).coverPossibleStrategyLoss(0, 500_000)).rejectedWith("SS: Loss too high"); await splitter.connect(await Misc.impersonate(strategy.address)).coverPossibleStrategyLoss(1000_000, 500_000); diff --git a/test/vault/SplitterTests.ts b/test/vault/SplitterTests.ts index bc6ef35..35ee331 100644 --- a/test/vault/SplitterTests.ts +++ b/test/vault/SplitterTests.ts @@ -72,8 +72,6 @@ describe("SplitterTests", function () { const forwarder = await DeployerUtils.deployContract(signer, 'MockForwarder') await controller.setForwarder(forwarder.address); - - }); after(async function () { @@ -378,7 +376,7 @@ describe("SplitterTests", function () { expect(await strategy3.totalAssets()).eq(10); expect(await usdc.balanceOf(splitter.address)).eq(999990); - console.log("REBALANCE 1 OK"); + // console.log("REBALANCE 1 OK"); await splitter.rebalance(100, 30) expect(await strategy.totalAssets()).eq(0); @@ -386,7 +384,7 @@ describe("SplitterTests", function () { expect(await strategy3.totalAssets()).eq(10); expect(await usdc.balanceOf(splitter.address)).eq(999980); - console.log("REBALANCE 2 OK"); + // console.log("REBALANCE 2 OK"); await splitter.rebalance(100, 30) expect(await strategy.totalAssets()).eq(10); @@ -500,38 +498,37 @@ describe("SplitterTests", function () { it("withdraw all with slippage revert", async () => { await vault.deposit(1000, signer.address); - await strategy2.setSlippage(300); - await expect(vault.withdrawAll()).revertedWith("SLIPPAGE"); + await strategy2.setSlippage(601); + await expect(vault.withdrawAll()).revertedWith("SS: Loss too high"); }); it("withdraw all with slippage covering from insurance test", async () => { await vault.deposit(1000, signer.address); await strategy2.setSlippage(300); - await vault.setFees(0, 1_000) await vault.withdrawAll() }); - it("withdraw all with slippage covering from insurance not enough revert", async () => { + it("withdraw all with slippage NOT covering from insurance not enough revert", async () => { await vault.deposit(1000, signer.address); - await strategy2.setSlippage(300); - await vault.setFees(0, 250) - await expect(vault.withdrawAll()).revertedWith("SLIPPAGE"); + await strategy2.setSlippage(600); + // await vault.setFees(0, 250) + await expect(vault.withdrawAll()).revertedWith("SS: Loss too hig"); }); - it("withdraw with 100% slippage covering from insurance test", async () => { + it("withdraw with 100% slippage NOT covering from insurance test", async () => { await strategy2.setUseTrueExpectedWithdraw(true); - await strategy2.setSlippage(1_100); - await vault.setFees(1_000, 1_000) + await strategy2.setSlippage(100); + // await vault.setFees(1_000, 1_000) await vault.deposit(10_000_000, signer.address) - await expect(vault.withdraw(1000, signer.address, signer.address)).revertedWith("SB: Too high"); + await vault.withdraw(1000, signer.address, signer.address) await strategy2.setSlippage(1_000); - await vault.withdraw(1000, signer.address, signer.address); + await expect(vault.withdraw(1000, signer.address, signer.address)).revertedWith('SB: Too high'); }); // todo probably need to fix it("withdraw all with 100% slippage covering from insurance test", async () => { await vault.redeem(900, signer.address, signer.address) - await vault.setFees(100, 100) + // await vault.setFees(100, 100) await vault.deposit(1000_000, signer.address) await vault.withdrawAll(); await vault.deposit(10000, signer.address) @@ -566,7 +563,7 @@ describe("SplitterTests", function () { it("withdraw with slippage covering from insurance test", async () => { await vault.deposit(1000, signer.address); await strategy2.setSlippage(1_000); - await vault.setFees(0, 1_000) + // await vault.setFees(0, 1_000) await vault.withdraw(99, signer.address, signer.address,); }); @@ -612,23 +609,21 @@ describe("SplitterTests", function () { expect(await vault.sharePrice()).eq(999500); }); - it("deposit with loss with covering", async () => { + it("deposit with loss without covering", async () => { expect(await vault.sharePrice()).eq(1000000); await strategy2.setSlippageDeposit(100); - await vault.setFees(300, 0); await vault.deposit(1000_000, signer.address); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1997000); + expect(await vault.sharePrice()).eq(999500); + expect(await vault.totalAssets()).eq(1999000); }); - it("hardwork with loss with covering", async () => { + it("hardwork with loss without covering", async () => { expect(await vault.sharePrice()).eq(1000000); await strategy2.setSlippageHardWork(30); - await vault.setFees(1_000, 0); await vault.deposit(1000_000, signer.address); await splitter.doHardWorkForStrategy(strategy2.address, true); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1990000); + expect(await vault.sharePrice()).eq(999700); + expect(await vault.totalAssets()).eq(1999400); }); it("hardwork with loss without covering", async () => { @@ -654,19 +649,18 @@ describe("SplitterTests", function () { expect(await vault.totalAssets()).eq(1000750); }); - it("rebalance with loss with covering", async () => { + it("rebalance with loss WITHOUT covering", async () => { expect(await vault.sharePrice()).eq(1000000); await splitter.setAPRs([strategy.address], [200]); - await vault.setFees(1_000, 0); - await vault.deposit(1000_000, signer.address); + await vault.deposit(1_000_000, signer.address); await strategy.setSlippageDeposit(25); await splitter.rebalance(100, 30); - expect(await vault.sharePrice()).eq(1000000); - expect(await vault.totalAssets()).eq(1990000); + expect(await vault.sharePrice()).eq(999875); + expect(await vault.totalAssets()).eq(1999750); }); it("rebalance with negative totalAssetsDelta", async () => { @@ -794,20 +788,20 @@ describe("SplitterTests", function () { }); }); describe("withdrawToVault", () => { - it("should cover expected loss if totalAssets-after is less than totalAssets-before", async () => { + it.skip("should cover expected loss if totalAssets-after is less than totalAssets-before", async () => { const insurance = await vault.insurance(); await splitter.addStrategies([strategy.address], [100], [0]); await usdc.mint(insurance, 50000); await vault.deposit(100000, signer.address); - await vault.setFees(0, 200) + // await vault.setFees(0, 200) const insuranceBefore = await usdc.balanceOf(insurance); await strategy.setSlippage(100); await vault.withdraw(50000, signer.address, signer.address); const insuranceAfter = await usdc.balanceOf(insurance); - expect(insuranceAfter).eq(50050); + expect(insuranceAfter).eq(49950); }); it("should not use insurance if totalAssets-after is greater than totalAssets-before", async () => { const insurance = await vault.insurance(); @@ -838,8 +832,8 @@ describe("SplitterTests", function () { await vault.withdrawAll(); const insuranceAfter = await usdc.balanceOf(insurance); - console.log("insuranceBefore", insuranceBefore); - console.log("insuranceAfter", insuranceAfter); + // console.log("insuranceBefore", insuranceBefore); + // console.log("insuranceAfter", insuranceAfter); expect(insuranceAfter).eq(insuranceBefore.sub(10000)); }); // it("should not use insurance if totalAssets-after is greater than totalAssets-before", async () => { @@ -881,35 +875,34 @@ describe("SplitterTests", function () { expect(sharePriceBefore).eq(await vault.sharePrice()); const insuranceBefore = await usdc.balanceOf(insurance); - console.log('insuranceBefore', insuranceBefore) + // console.log('insuranceBefore', insuranceBefore) await strategy.setUseTrueExpectedWithdraw(true) await strategy.setSlippage(10); - await vault.setFees(0, 1000) + // await vault.setFees(0, 1000) await vault.withdrawAll(); const insuranceAfter = await usdc.balanceOf(insurance); - console.log('insuranceAfter', insuranceAfter) - expect(insuranceAfter).eq(9891); - + // console.log('insuranceAfter', insuranceAfter) + expect(insuranceAfter).eq(0); expect(sharePriceBefore).eq(await vault.sharePrice()); }); it("should register loss with coverPossibleStrategyLoss call", async () => { await strategy.init(controller.address, splitter.address); - await vault.setFees(300, 300); + // await vault.setFees(300, 300); - console.log('add strategy') + // console.log('add strategy') await splitter.addStrategies([strategy.address], [100], [0]); - console.log('check not a strategy') + // console.log('check not a strategy') await expect(splitter.coverPossibleStrategyLoss(0, 500_000)).rejectedWith("SS: Invalid strategy"); - console.log('deposit') + // console.log('deposit') await vault.deposit(10_000_000, signer.address); - console.log('register huge loss revert') + // console.log('register huge loss revert') await expect(splitter.connect(await Misc.impersonate(strategy.address)).coverPossibleStrategyLoss(0, 500_000)).rejectedWith("SS: Loss too high"); await splitter.connect(await Misc.impersonate(strategy.address)).coverPossibleStrategyLoss(1000_000, 500_000); diff --git a/test/vault/TetuVaultV2Tests.ts b/test/vault/TetuVaultV2Tests.ts index 1bd6a84..a7eaa60 100644 --- a/test/vault/TetuVaultV2Tests.ts +++ b/test/vault/TetuVaultV2Tests.ts @@ -5,7 +5,7 @@ import {ethers} from "hardhat"; import {TimeUtils} from "../TimeUtils"; import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; import { - ControllerMinimal, IERC20__factory, + ControllerMinimal, MockGauge, MockGauge__factory, MockSplitter, @@ -81,7 +81,7 @@ describe("Tetu Vault V2 tests", function () { await TimeUtils.rollback(snapshot); }); - describe("withdrawRequestBlocks == 0", () => { + describe("withdrawRequestBlocks == 0", () => { it("decimals test", async () => { expect(await vault.decimals()).eq(6); }); @@ -167,54 +167,48 @@ describe("Tetu Vault V2 tests", function () { await expect(vault.redeem(0, signer.address, signer.address)).revertedWith('ZERO_ASSETS') }); - it("deposit with fee test", async () => { - await vault.setFees(1_000, 1_000); - + it("deposit test", async () => { const bal1 = await usdc.balanceOf(signer.address); await vault.deposit(parseUnits('1', 6), signer1.address); - expect(await vault.balanceOf(signer1.address)).eq(989000); + expect(await vault.balanceOf(signer1.address)).eq(999000); // 1000 initial shares goes to dead address expect(bal1.sub(await usdc.balanceOf(signer.address))).eq(parseUnits('1', 6)); const bal2 = await usdc.balanceOf(signer.address); await vault.deposit(parseUnits('1', 6), signer.address); - expect(await vault.balanceOf(signer.address)).eq(990000); + expect(await vault.balanceOf(signer.address)).eq(1000000); // NO DEPOSIT FEES expect(bal2.sub(await usdc.balanceOf(signer.address))).eq(parseUnits('1', 6)); const insurance = await vault.insurance(); - expect(await usdc.balanceOf(insurance)).eq(20_000); + expect(await usdc.balanceOf(insurance)).eq(0); // INSURANCE IS DEPRECATED expect(await vault.sharePrice()).eq(parseUnits('1', 6)) }); - it("mint with fee test", async () => { - await vault.setFees(1_000, 1_000); - + it("mint test", async () => { const bal1 = await usdc.balanceOf(signer.address); await vault.mint(990_000, signer1.address); - expect(await vault.balanceOf(signer1.address)).eq(989000); - expect(bal1.sub(await usdc.balanceOf(signer.address))).eq(parseUnits('1', 6)); + expect(await vault.balanceOf(signer1.address)).eq(989_000); + expect(bal1.sub(await usdc.balanceOf(signer.address))).eq(990_000); const bal2 = await usdc.balanceOf(signer.address); await vault.mint(990_000, signer.address); - expect(await vault.balanceOf(signer.address)).eq(990000); - expect(bal2.sub(await usdc.balanceOf(signer.address))).eq(parseUnits('1', 6)); + expect(await vault.balanceOf(signer.address)).eq(990_000); + expect(bal2.sub(await usdc.balanceOf(signer.address))).eq(990_000); const insurance = await vault.insurance(); - expect(await usdc.balanceOf(insurance)).eq(20_000); + expect(await usdc.balanceOf(insurance)).eq(0); expect(await vault.sharePrice()).eq(parseUnits('1', 6)) }); - it("withdraw with fee test", async () => { - await vault.setFees(1_000, 1_000); - + it("withdraw test", async () => { await vault.deposit(parseUnits('1', 6), signer1.address); await vault.deposit(parseUnits('1', 6), signer.address); const shares = await vault.balanceOf(signer.address); - expect(shares).eq(990_000); + expect(shares).eq(1_000_000); const assets = await vault.convertToAssets(shares); - const assetsMinusTax = assets.mul(99).div(100); - expect(assetsMinusTax).eq(980100); + const assetsMinusTax = assets.mul(100).div(100); + expect(assetsMinusTax).eq(1_000_000); const bal1 = await usdc.balanceOf(signer.address); const shares1 = await vault.balanceOf(signer.address); @@ -223,22 +217,20 @@ describe("Tetu Vault V2 tests", function () { expect((await usdc.balanceOf(signer.address)).sub(bal1)).eq(assetsMinusTax); const insurance = await vault.insurance(); - expect(await usdc.balanceOf(insurance)).eq(29_900); + expect(await usdc.balanceOf(insurance)).eq(0); expect(await vault.sharePrice()).eq(parseUnits('1', 6)) }); - it("redeem with fee test", async () => { - await vault.setFees(1_000, 1_000); - + it("redeem test", async () => { await vault.deposit(parseUnits('1', 6), signer1.address); await vault.deposit(parseUnits('1', 6), signer.address); const shares = await vault.balanceOf(signer.address); - expect(shares).eq(990_000); + expect(shares).eq(1_000_000); const assets = await vault.convertToAssets(shares); - const assetsMinusTax = assets.mul(99).div(100); - expect(assetsMinusTax).eq(980100); + const assetsMinusTax = assets.mul(100).div(100); + expect(assetsMinusTax).eq(1_000_000); const bal1 = await usdc.balanceOf(signer.address); const shares1 = await vault.balanceOf(signer.address); @@ -247,7 +239,7 @@ describe("Tetu Vault V2 tests", function () { expect((await usdc.balanceOf(signer.address)).sub(bal1)).eq(assetsMinusTax); const insurance = await vault.insurance(); - expect(await usdc.balanceOf(insurance)).eq(29_900); + expect(await usdc.balanceOf(insurance)).eq(0); expect(await vault.sharePrice()).eq(parseUnits('1', 6)) }); @@ -338,14 +330,6 @@ describe("Tetu Vault V2 tests", function () { await vault.redeem(10, signer.address, signer.address) }); - it("set fees from 3d party revert", async () => { - await expect(vault.connect(signer2).setFees(1, 1)).revertedWith("DENIED"); - }); - - it("set fees too high revert", async () => { - await expect(vault.setFees(10_000, 1)).revertedWith("TOO_HIGH"); - }); - it("set DoHardWorkOnInvest from 3d party revert", async () => { await expect(vault.connect(signer2).setDoHardWorkOnInvest(false)).revertedWith("DENIED"); }); @@ -403,9 +387,8 @@ describe("Tetu Vault V2 tests", function () { expect(bal.sub(balAfter)).eq(parseUnits('0.1', 6).add(900)); }); - it("withdraw with slippage should be fair for all users", async () => { + it("withdraw with slippage should be OK for all users. Each user pay for himself.", async () => { await vault.setBuffer(0); - const bal = await usdc.balanceOf(signer.address); const bal1 = await usdc.balanceOf(signer2.address); await vault.deposit(parseUnits('1', 6), signer.address) await vault.connect(signer2).deposit(parseUnits('1', 6), signer2.address) @@ -413,47 +396,54 @@ describe("Tetu Vault V2 tests", function () { await mockSplitter.setSlippage(10_0); await expect(vault.withdrawAll()).revertedWith('SLIPPAGE'); - await vault.setFees(0, 1_000); await mockSplitter.setSlippage(1_0); + await expect(vault.withdrawAll()).revertedWith('SLIPPAGE'); + + await mockSplitter.setSlippage(0); // 0.4% + // console.log('signer withdraw start'); + const balBefore = await usdc.balanceOf(signer.address); await vault.withdrawAll(); + // console.log('signer withdraw done'); const balAfter = await usdc.balanceOf(signer.address); - expect(bal.sub(balAfter)).eq(parseUnits('0.01', 6).add(990)); + // console.log('balBefore withdrawAll', balBefore) + // console.log('balAfter withdrawAll', balAfter) + // console.log('withdrawn withdrawAll', formatUnits(balAfter.sub(balBefore), 6)) + expect(balAfter.sub(balBefore)).eq(parseUnits('1', 6).sub(1000)); // substract INITIAL 1000 shares cost await mockSplitter.setSlippage(1); + // console.log('signer2 withdraw start'); await vault.connect(signer2).withdrawAll() + // console.log('signer2 withdraw done'); const balAfter1 = await usdc.balanceOf(signer2.address); - expect(bal1.sub(balAfter1)).eq(parseUnits('0.01', 6)); + expect(bal1.sub(balAfter1)).eq(parseUnits('0.001', 6)); }); it("splitter assets test", async () => { expect(await vault.splitterAssets()).eq(0); }); - it("maxWithdraw with fee test (withdrawAll)", async () => { + it("maxWithdraw test (withdrawAll)", async () => { await vault.deposit(parseUnits('1', 6), signer.address) const balanceBefore = await usdc.balanceOf(signer.address); - await vault.setFees(0, 1_000); - const expectWithdraw = parseUnits('1', 6).sub(parseUnits('0.01', 6)); - expect(await vault.maxWithdraw(signer.address)).eq(expectWithdraw.sub(990)); + const expectWithdraw = parseUnits('1', 6).sub(parseUnits('0.001', 6)); + expect(await vault.maxWithdraw(signer.address)).eq(expectWithdraw); await vault.withdrawAll(); const balanceAfter = await usdc.balanceOf(signer.address); - expect(balanceBefore.add(expectWithdraw)).eq(balanceAfter.add(990)); + expect(balanceBefore.add(expectWithdraw)).eq(balanceAfter); }); - it("maxWithdraw with fee test (withdraw max)", async () => { + it("maxWithdraw test (withdraw max)", async () => { await vault.deposit(parseUnits('1', 6), signer.address) const balanceBefore = await usdc.balanceOf(signer.address); - await vault.setFees(0, 1_000); - const expectWithdraw = parseUnits('1', 6).sub(parseUnits('0.01', 6)); - expect(await vault.maxWithdraw(signer.address)).eq(expectWithdraw.sub(990)); + const expectWithdraw = parseUnits('1', 6).sub(parseUnits('0.001', 6)); + expect(await vault.maxWithdraw(signer.address)).eq(expectWithdraw); await vault.withdraw(await vault.maxWithdraw(signer.address), signer.address, signer.address); const balanceAfter = await usdc.balanceOf(signer.address); - expect(balanceBefore.add(expectWithdraw)).eq(balanceAfter.add(990)); + expect(balanceBefore.add(expectWithdraw)).eq(balanceAfter); }); - it("maxWithdraw with fee complex test (withdraw max)", async () => { - await vault.setFees(0, 500); + it("maxWithdraw complex test (withdraw max)", async () => { await vault.deposit(parseUnits('99800.001', 6), signer.address) await vault.deposit(parseUnits('10300.001656', 6), signer2.address) await usdc.transfer(vault.address, parseUnits('0.000267', 6)); @@ -463,12 +453,11 @@ describe("Tetu Vault V2 tests", function () { it("cover loss test", async () => { const bal = await usdc.balanceOf(signer.address); - await vault.setFees(1_000, 0); await vault.deposit(parseUnits('1', 6), signer.address); await mockSplitter.coverLoss(10_000); await vault.withdrawAll(); const balAfter = await usdc.balanceOf(signer.address); - expect(bal.sub(balAfter)).eq(1011); + expect(bal.sub(balAfter)).eq(1000); }); it("cover loss revert", async () => { @@ -577,7 +566,6 @@ describe("Tetu Vault V2 tests", function () { async function withdrawRequestsTest(p: IWithdrawRequestsTestParams): Promise { // set up vault await vault.setWithdrawRequestBlocks(p.withdrawRequestBlocks || 5); - await vault.setFees(0, 0); // for simplicity of cal await vault.setBuffer(0); // for simplicity of cal // exclude INITIAL_SHARES influences @@ -590,7 +578,7 @@ describe("Tetu Vault V2 tests", function () { await vault.connect(await Misc.impersonate(caller)).requestWithdraw(); } } - console.log("advance blocks 1", p.actionsBefore.countBlocks ?? 5); + // console.log("advance blocks 1", p.actionsBefore.countBlocks ?? 5); await TimeUtils.advanceNBlocks(p.actionsBefore.countBlocks ?? 5); } @@ -605,13 +593,13 @@ describe("Tetu Vault V2 tests", function () { } await vault.connect(depositor).deposit(amountToDeposit, receiver); if (d.countBlocks) { - console.log("advance blocks 4", d.countBlocks); + // console.log("advance blocks 4", d.countBlocks); await TimeUtils.advanceNBlocks(d.countBlocks); } } // advance blocks - console.log("advance blocks 2", p.countBlocks ?? 5); + // console.log("advance blocks 2", p.countBlocks ?? 5); await TimeUtils.advanceNBlocks(p.countBlocks ?? 5); // Signer withdraws from vault @@ -631,7 +619,7 @@ describe("Tetu Vault V2 tests", function () { const amount = w.amountToWithdraw === "MAX" ? await vault.maxWithdraw(owner) : parseUnits(w.amountToWithdraw, 6); - console.log("Amount to withdraw", amount); + // console.log("Amount to withdraw", amount); if (owner !== caller) { await vault.connect(await Misc.impersonate(owner)).approve(caller, amount); } @@ -642,7 +630,7 @@ describe("Tetu Vault V2 tests", function () { receivedAmount += +formatUnits(balanceAfter.sub(balanceBefore), 6); if (w.countBlocks) { - console.log("advance blocks 3", w.countBlocks); + // console.log("advance blocks 3", w.countBlocks); await TimeUtils.advanceNBlocks(w.countBlocks); } }