From 87515cb520db52a186355b4800c5a7caab02a684 Mon Sep 17 00:00:00 2001 From: doncesarts Date: Wed, 23 Nov 2022 12:12:25 +0100 Subject: [PATCH] refact: reduce gas consumption while donating tokens (#87) * refact: reduce gas consumption while donating tokens * test: fix test LiquidatorStreamFeeVault.spec * docs: updates convex vaults diagrams --- .../LiquidatorStreamAbstractVault.sol | 66 ++-- .../convex/Convex3CrvAbstractVault.sol | 95 +++++- .../liquidity/convex/Convex3CrvBasicVault.sol | 4 + .../convex/Convex3CrvLiquidatorVault.sol | 23 +- .../convex/ConvexFraxBpAbstractVault.sol | 80 ++++- .../convex/ConvexFraxBpBasicVault.sol | 4 + .../convex/ConvexFraxBpLiquidatorVault.sol | 24 +- docs/Convex3CrvAbstractVault.svg | 305 +++++++++--------- docs/Convex3CrvLiquidatorVault.svg | 165 +++++----- docs/ConvexFraxBpAbstractVault.svg | 133 ++++---- docs/ConvexFraxBpLiquidatorVault.svg | 150 ++++----- .../vault/Convex3CrvLiquidatorVault.spec.ts | 48 +-- .../vault/ConvexFraxBpLiquidatorVault.spec.ts | 12 +- .../vault/shared/Convex3Crv.behaviour.ts | 56 +++- .../vault/shared/ConvexFraxBp.behaviour.ts | 49 ++- .../LiquidatorStreamFeeVault.spec.ts | 2 +- 16 files changed, 705 insertions(+), 511 deletions(-) diff --git a/contracts/vault/liquidator/LiquidatorStreamAbstractVault.sol b/contracts/vault/liquidator/LiquidatorStreamAbstractVault.sol index f992999..ea6900c 100644 --- a/contracts/vault/liquidator/LiquidatorStreamAbstractVault.sol +++ b/contracts/vault/liquidator/LiquidatorStreamAbstractVault.sol @@ -111,32 +111,7 @@ abstract contract LiquidatorStreamAbstractVault is AbstractVault, LiquidatorAbst */ function donate(address token, uint256 amount) external virtual override streamRewards { (uint256 newShares, uint256 newAssets) = _convertTokens(token, amount); - - StreamData memory stream = shareStream; - uint256 remainingStreamShares = _streamedShares(stream); - - if (newShares > 0) { - // Not all shares have to be streamed. Some may be used as a fee. - (uint256 newStreamShares, uint256 streamAssets) = _beforeStreamShare( - newShares, - newAssets - ); - - uint256 sharesPerSecond = ((remainingStreamShares + newStreamShares) * - STREAM_PER_SECOND_SCALE) / STREAM_DURATION; - - // Store updated stream data - shareStream = StreamData( - SafeCast.toUint32(block.timestamp), - SafeCast.toUint32(block.timestamp + STREAM_DURATION), - SafeCast.toUint128(sharesPerSecond) - ); - - // Mint new shares that will be burnt over time. - _mint(address(this), newStreamShares); - - emit Deposit(msg.sender, address(this), streamAssets, newStreamShares); - } + _streamNewShares(newShares, newAssets); } /** @@ -202,6 +177,45 @@ abstract contract LiquidatorStreamAbstractVault is AbstractVault, LiquidatorAbst } } + /** + * @notice Mints shares so the assets per share does not increase initially, + * and then burns the new shares over a period of time + * so the assets per share gradually increases. + * For example, if 1,000 DAI is being donated is worth 800 vault shares and the donation fee is 16%. 128 (800 * 16%) + * of the new vault shares are minted to the fee receiver. The remaining 672 vault shares are minted to the vault so + * the assets per shares of the shareholders does not increase. Over the next week the new vault shares will be burnt + * which will increase the assets per share to the shareholders. + * + * @param newShares The amount of shares to stream. + * @param newAssets The amount of assets to stream. + */ + function _streamNewShares(uint256 newShares, uint256 newAssets) internal virtual { + if (newShares > 0) { + StreamData memory stream = shareStream; + uint256 remainingStreamShares = _streamedShares(stream); + // Not all shares have to be streamed. Some may be used as a fee. + (uint256 newStreamShares, uint256 streamAssets) = _beforeStreamShare( + newShares, + newAssets + ); + + uint256 sharesPerSecond = ((remainingStreamShares + newStreamShares) * + STREAM_PER_SECOND_SCALE) / STREAM_DURATION; + + // Store updated stream data + shareStream = StreamData( + SafeCast.toUint32(block.timestamp), + SafeCast.toUint32(block.timestamp + STREAM_DURATION), + SafeCast.toUint128(sharesPerSecond) + ); + + // Mint new shares that will be burnt over time. + _mint(address(this), newStreamShares); + + emit Deposit(msg.sender, address(this), streamAssets, newStreamShares); + } + } + /*************************************** Streamed Rewards Views ****************************************/ diff --git a/contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol b/contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol index 0992212..80d2e27 100644 --- a/contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol +++ b/contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol @@ -80,7 +80,7 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { _data.booster ).poolInfo(_data.convexPoolId); metapoolToken = metapoolTokenAddress; - metapoolTokenScale = 10**IERC20Metadata(metapoolTokenAddress).decimals(); + metapoolTokenScale = 10 ** IERC20Metadata(metapoolTokenAddress).decimals(); baseRewardPool = IConvexRewardsPool(baseRewardPoolAddress); metapool = _data.metapool; @@ -145,12 +145,23 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { shares = _depositInternal(assets, receiver, depositSlippage); } - /// @dev Vault assets (3Crv) -> Metapool LP tokens, eg musd3Crv -> vault shares + /** + * @dev Vault assets (3Crv) -> Metapool LP tokens, eg musd3Crv -> vault shares + * If the vault has any 3Crv balance, it is added to the mint/deposit 3Crv that is added to the Metapool + * and LP deposited to the Convex pool. The resulting shares are proportionally split between the reciever + * and the vault via _afterSharesMintedHook fn. + * + * @param _assets The amount of underlying assets to be transferred to the vault. + * @param _receiver The account that the vault shares will be minted to. + * @param _slippage Deposit slippage in basis points i.e. 1% = 100. + * @return shares The amount of vault shares that were minted. + */ function _depositInternal( uint256 _assets, address _receiver, uint256 _slippage ) internal virtual returns (uint256 shares) { + uint256 assetsToDeposit = _asset.balanceOf(address(this)) + _assets; // Transfer vault's asssets (3Crv) from the caller. _asset.safeTransferFrom(msg.sender, address(this), _assets); @@ -159,29 +170,34 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { uint256 totalMetapoolTokensBefore = baseRewardPool.balanceOf(address(this)); // Calculate fair amount of metapool LP tokens, eg musd3Crv, using virtual prices for vault assets (3Crv) - uint256 minMetapoolTokens = _getMetapoolTokensForAssets(_assets); + uint256 minMetapoolTokens = _getMetapoolTokensForAssets(assetsToDeposit); // Calculate min amount of metapool LP tokens with max slippage // This is used for sandwich attack protection minMetapoolTokens = (minMetapoolTokens * (BASIS_SCALE - _slippage)) / BASIS_SCALE; // Deposit 3Crv into metapool and the stake into Convex vault - uint256 metapoolTokensReceived = _depositAndStake(_assets, minMetapoolTokens); + uint256 metapoolTokensReceived = _depositAndStake(assetsToDeposit, minMetapoolTokens); // Calculate the proportion of shares to mint based on the amount of Metapool LP tokens. - shares = _getSharesFromMetapoolTokens( + uint256 sharesToMint = _getSharesFromMetapoolTokens( metapoolTokensReceived, totalMetapoolTokensBefore, totalSupply() ); + // Calculate the proportion of shares to mint to the receiver. + shares = (sharesToMint * _assets) / assetsToDeposit; _mint(_receiver, shares); emit Deposit(msg.sender, _receiver, _assets, shares); + // Account any new shares, assets. + _afterSharesMintedHook(sharesToMint - shares, assetsToDeposit - _assets); } /// @dev Converts vault assets to shares in two steps /// Vault assets (3Crv) -> Metapool LP tokens, eg musd3Crv -> vault shares /// Override `AbstractVault._previewDeposit`. + /// changes - It takes into account any asset balance to be included in the deposit. function _previewDeposit(uint256 assets) internal view @@ -190,20 +206,24 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { returns (uint256 shares) { if (assets > 0) { + // Take into account any asset balance. + uint256 assetsToDeposit = _asset.balanceOf(address(this)) + assets; // Calculate Metapool LP tokens, eg musd3Crv, for vault assets (3Crv) (uint256 metapoolTokens, , , ) = Curve3CrvMetapoolCalculatorLibrary.calcDeposit( metapool, metapoolToken, - assets, + assetsToDeposit, 1 ); // Calculate the proportion of shares to mint based on the amount of metapool LP tokens, eg musd3Crv. - shares = _getSharesFromMetapoolTokens( + uint256 sharesToMint = _getSharesFromMetapoolTokens( metapoolTokens, baseRewardPool.balanceOf(address(this)), totalSupply() ); + // Calculate the callers portion of shares + shares = (sharesToMint * assets) / assetsToDeposit; } } @@ -215,19 +235,31 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { override returns (uint256 assets) { + uint256 donatedAssets = _asset.balanceOf(address(this)); + uint256 donatedMetapoolTokens = 0; + if (donatedAssets > 0) { + (donatedMetapoolTokens, , , ) = Curve3CrvMetapoolCalculatorLibrary.calcDeposit( + metapool, + metapoolToken, + donatedAssets, + 1 + ); + } // Calculate Curve Metapool LP tokens, eg musd3CRV, needed to mint the required amount of shares - uint256 requiredMetapoolTokens = _getMetapoolTokensFromShares( + uint256 metapoolTokens = _getMetapoolTokensFromShares( shares, baseRewardPool.balanceOf(address(this)), totalSupply() ); + uint256 requiredMetapoolTokens = metapoolTokens + donatedMetapoolTokens; - // Calculate assets needed to deposit into the metapool for the for required metapool lp tokens. + // Calculate assets needed to deposit into the metapool for the required metapool lp tokens. + uint256 assetsToDeposit; uint256 invariant; uint256 metapoolTotalSupply; uint256 baseVirtualPrice; ( - assets, + assetsToDeposit, invariant, metapoolTotalSupply, baseVirtualPrice @@ -237,39 +269,59 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { requiredMetapoolTokens, 1 ); + assets = (assetsToDeposit * requiredMetapoolTokens) / metapoolTokens; // Protect against sandwich and flash loan attacks where the balance of the metapool is manipulated. uint256 maxAssets = (requiredMetapoolTokens * invariant * VIRTUAL_PRICE_SCALE) / (metapoolTotalSupply * baseVirtualPrice); maxAssets = (maxAssets * (BASIS_SCALE + mintSlippage)) / BASIS_SCALE; - require(assets <= maxAssets, "too much slippage"); + + require(assetsToDeposit <= maxAssets, "too much slippage"); // Transfer vault's asssets (3Crv) from the caller. _asset.safeTransferFrom(msg.sender, address(this), assets); // Deposit 3Crv into metapool and the stake into Convex vault - _depositAndStake(assets, requiredMetapoolTokens); + _depositAndStake(assetsToDeposit, requiredMetapoolTokens); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); + // Account any new shares, assets. + uint256 donatedShares = donatedAssets == 0 + ? 0 + : (shares * requiredMetapoolTokens) / donatedMetapoolTokens; + _afterSharesMintedHook(donatedShares, donatedAssets); } /// @dev Converts vault shares to assets in two steps /// Vault shares -> Metapool LP tokens, eg musd3Crv -> vault assets (3Crv) /// Override `AbstractVault._previewMint`. + /// changes - It takes into account any asset balance to be included in the next mint. function _previewMint(uint256 shares) internal view virtual override returns (uint256 assets) { if (shares > 0) { + uint256 donatedAssets = _asset.balanceOf(address(this)); + uint256 donatedMetapoolTokens = 0; + if (donatedAssets > 0) { + (donatedMetapoolTokens, , , ) = Curve3CrvMetapoolCalculatorLibrary.calcDeposit( + metapool, + metapoolToken, + donatedAssets, + 1 + ); + } uint256 metapoolTokens = _getMetapoolTokensFromShares( shares, baseRewardPool.balanceOf(address(this)), totalSupply() ); - (assets, , , ) = Curve3CrvMetapoolCalculatorLibrary.calcMint( + (uint256 assetsToDeposit, , , ) = Curve3CrvMetapoolCalculatorLibrary.calcMint( metapool, metapoolToken, - metapoolTokens, + metapoolTokens + donatedMetapoolTokens, 1 ); + // Calculate receivers portion of assets. + assets = (assetsToDeposit * (metapoolTokens + donatedMetapoolTokens)) / metapoolTokens; } } @@ -581,6 +633,21 @@ abstract contract Convex3CrvAbstractVault is AbstractSlippage, AbstractVault { } } + /** + * Called be the `deposit` and `mint` functions after the assets have been transferred into the vault + * but before shares are minted. + * Typically, the hook implementation deposits the assets into the underlying vaults or platforms. + * + * @dev the shares returned from `totalSupply` and `balanceOf` have not yet been updated with the minted shares. + * The assets returned from `totalAssets` and `assetsOf` are typically updated as part of the `_afterDepositHook` hook but it depends on the implementation. + * + * If an vault is implementing multiple vault capabilities, the `_afterDepositHook` function that updates the assets amounts should be executed last. + * + * @param newShares the amount of underlying assets to be transferred to the vault. + * @param newAssets the amount of vault shares to be minted. + */ + function _afterSharesMintedHook(uint256 newShares, uint256 newAssets) internal virtual; + /*************************************** Emergency Functions ****************************************/ diff --git a/contracts/vault/liquidity/convex/Convex3CrvBasicVault.sol b/contracts/vault/liquidity/convex/Convex3CrvBasicVault.sol index 6619aef..7429169 100644 --- a/contracts/vault/liquidity/convex/Convex3CrvBasicVault.sol +++ b/contracts/vault/liquidity/convex/Convex3CrvBasicVault.sol @@ -54,4 +54,8 @@ contract Convex3CrvBasicVault is Convex3CrvAbstractVault, Initializable { uint8 decimals_ = InitializableToken(address(metapoolToken)).decimals(); InitializableToken._initialize(_name, _symbol, decimals_); } + + function _afterSharesMintedHook(uint256, uint256) internal virtual override { + // do nothing + } } diff --git a/contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol b/contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol index a598377..490da5e 100644 --- a/contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol +++ b/contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol @@ -144,8 +144,7 @@ contract Convex3CrvLiquidatorVault is * @dev Converts donated tokens (DAI, USDC or USDT) to vault assets (3Crv) and shares. * Transfers token from donor to vault. * Adds the token to the Curve 3Pool to receive the vault asset (3Crv) in exchange. - * The resulting asset (3Crv) is added to the Curve Metapool. - * The Curve Metapool LP token, eg mUSD3Crv, is added to the Convex pool and staked. + * The assets assets (3Crv) stay in the vault without changing the number of shares. */ function _convertTokens(address token, uint256 amount) internal @@ -190,18 +189,8 @@ contract Convex3CrvLiquidatorVault is // Get vault's asset (3Crv) balance after adding token to Curve's 3Pool. assets_ = _asset.balanceOf(address(this)); - // Add asset (3Crv) to metapool with slippage protection. - uint256 metapoolTokens = ICurveMetapool(metapool).add_liquidity([0, assets_], minMetapoolTokens); - - // Calculate share value of the new assets before depositing the metapool tokens to the Convex pool. - shares_ = _getSharesFromMetapoolTokens( - metapoolTokens, - baseRewardPool.balanceOf(address(this)), - totalSupply() - ); - // Deposit Curve.fi Metapool LP token, eg musd3CRV, in Convex pool, eg cvxmusd3CRV, and stake. - booster.deposit(convexPoolId, metapoolTokens, true); + shares_ = 0; } /*************************************** @@ -382,6 +371,14 @@ contract Convex3CrvLiquidatorVault is shares = Convex3CrvAbstractVault._withdraw(assets, receiver, owner); } + /// @dev use LiquidatorStreamAbstractVault._streamNewShares implementation. + function _afterSharesMintedHook( + uint256 newShares, + uint256 newAssets + ) internal virtual override(Convex3CrvAbstractVault) { + LiquidatorStreamAbstractVault._streamNewShares(newShares, newAssets); + } + /*************************************** Internal vault convertions ****************************************/ diff --git a/contracts/vault/liquidity/convex/ConvexFraxBpAbstractVault.sol b/contracts/vault/liquidity/convex/ConvexFraxBpAbstractVault.sol index b9e8fcd..dc5561d 100644 --- a/contracts/vault/liquidity/convex/ConvexFraxBpAbstractVault.sol +++ b/contracts/vault/liquidity/convex/ConvexFraxBpAbstractVault.sol @@ -81,7 +81,7 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { _data.booster ).poolInfo(_data.convexPoolId); metapoolToken = metapoolTokenAddress; - metapoolTokenScale = 10**IERC20Metadata(metapoolTokenAddress).decimals(); + metapoolTokenScale = 10 ** IERC20Metadata(metapoolTokenAddress).decimals(); baseRewardPool = IConvexRewardsPool(baseRewardPoolAddress); metapool = _data.metapool; @@ -146,12 +146,23 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { shares = _depositInternal(assets, receiver, depositSlippage); } - /// @dev Vault assets (crvFRAX) -> Metapool LP tokens, eg BUSDFRAXBP3CRV-f -> vault shares + /** + * @dev Vault assets (crvFRAX) -> Metapool LP tokens, eg BUSDFRAXBP3CRV-f -> vault shares. + * If the vault has any crvFRAX balance, it is added to the mint/deposit crvFRAX that is added to the Metapool + * and LP deposited to the Convex pool. The resulting shares are proportionally split between the reciever + * and the vault via _afterSharesMintedHook fn. + * + * @param _assets The amount of underlying assets to be transferred to the vault. + * @param _receiver The account that the vault shares will be minted to. + * @param _slippage Deposit slippage in basis points i.e. 1% = 100. + * @return shares The amount of vault shares that were minted. + */ function _depositInternal( uint256 _assets, address _receiver, uint256 _slippage ) internal virtual returns (uint256 shares) { + uint256 assetsToDeposit = _asset.balanceOf(address(this)) + _assets; // Transfer vault's asssets (crvFRAX) from the caller. _asset.safeTransferFrom(msg.sender, address(this), _assets); @@ -160,29 +171,34 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { uint256 totalMetapoolTokensBefore = baseRewardPool.balanceOf(address(this)); // Calculate fair amount of metapool LP tokens, eg BUSDFRAXBP3CRV-f, using virtual prices for vault assets (crvFRAX) - uint256 minMetapoolTokens = _getMetapoolTokensForAssets(_assets); + uint256 minMetapoolTokens = _getMetapoolTokensForAssets(assetsToDeposit); // Calculate min amount of metapool LP tokens with max slippage // This is used for sandwich attack protection minMetapoolTokens = (minMetapoolTokens * (BASIS_SCALE - _slippage)) / BASIS_SCALE; // Deposit crvFRAX into metapool and the stake into Convex vault - uint256 metapoolTokensReceived = _depositAndStake(_assets, minMetapoolTokens); + uint256 metapoolTokensReceived = _depositAndStake(assetsToDeposit, minMetapoolTokens); // Calculate the proportion of shares to mint based on the amount of Metapool LP tokens. - shares = _getSharesFromMetapoolTokens( + uint256 sharesToMint = _getSharesFromMetapoolTokens( metapoolTokensReceived, totalMetapoolTokensBefore, totalSupply() ); + // Calculate the proportion of shares to mint to the receiver. + shares = (sharesToMint * _assets) / assetsToDeposit; _mint(_receiver, shares); emit Deposit(msg.sender, _receiver, _assets, shares); + // Account any new shares, assets. + _afterSharesMintedHook(sharesToMint - shares, assetsToDeposit - _assets); } /// @dev Converts vault assets to shares in two steps /// Vault assets (crvFRAX) -> Metapool LP tokens, eg BUSDFRAXBP3CRV-f -> vault shares /// Override `AbstractVault._previewDeposit`. + /// changes - It takes into account any asset balance to be included in the deposit. function _previewDeposit(uint256 assets) internal view @@ -191,20 +207,24 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { returns (uint256 shares) { if (assets > 0) { + // Take into account any asset balance. + uint256 assetsToDeposit = _asset.balanceOf(address(this)) + assets; // Calculate Metapool LP tokens, eg BUSDFRAXBP3CRV-f, for vault assets (crvFRAX) (uint256 metapoolTokens, , , ) = CurveFraxBpMetapoolCalculatorLibrary.calcDeposit( metapool, metapoolToken, - assets, + assetsToDeposit, 1 ); // Calculate the proportion of shares to mint based on the amount of metapool LP tokens, eg BUSDFRAXBP3CRV-f. - shares = _getSharesFromMetapoolTokens( + uint256 sharesToMint = _getSharesFromMetapoolTokens( metapoolTokens, baseRewardPool.balanceOf(address(this)), totalSupply() ); + // Calculate the callers portion of shares + shares = (sharesToMint * assets) / assetsToDeposit; } } @@ -216,19 +236,31 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { override returns (uint256 assets) { + uint256 donatedAssets = _asset.balanceOf(address(this)); + uint256 donatedMetapoolTokens = 0; + if (donatedAssets > 0) { + (donatedMetapoolTokens, , , ) = CurveFraxBpMetapoolCalculatorLibrary.calcDeposit( + metapool, + metapoolToken, + donatedAssets, + 1 + ); + } // Calculate Curve Metapool LP tokens, eg BUSDFRAXBP3CRV-f, needed to mint the required amount of shares - uint256 requiredMetapoolTokens = _getMetapoolTokensFromShares( + uint256 metapoolTokens = _getMetapoolTokensFromShares( shares, baseRewardPool.balanceOf(address(this)), totalSupply() ); + uint256 requiredMetapoolTokens = metapoolTokens + donatedMetapoolTokens; // Calculate assets needed to deposit into the metapool for the for required metapool lp tokens. + uint256 assetsToDeposit; uint256 invariant; uint256 metapoolTotalSupply; uint256 baseVirtualPrice; ( - assets, + assetsToDeposit, invariant, metapoolTotalSupply, baseVirtualPrice @@ -238,14 +270,15 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { requiredMetapoolTokens, 1 ); - + assets = (assetsToDeposit * requiredMetapoolTokens) / metapoolTokens; // Protect against sandwich and flash loan attacks where the balance of the metapool is manipulated. uint256 maxAssets = (requiredMetapoolTokens * invariant * CurveFraxBpMetapoolCalculatorLibrary.VIRTUAL_PRICE_SCALE) / (metapoolTotalSupply * baseVirtualPrice); maxAssets = (maxAssets * (BASIS_SCALE + mintSlippage)) / BASIS_SCALE; - require(assets <= maxAssets, "too much slippage"); + + require(assetsToDeposit <= maxAssets, "too much slippage"); // Transfer vault's asssets (crvFRAX) from the caller. _asset.safeTransferFrom(msg.sender, address(this), assets); @@ -256,24 +289,42 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); + // Account any new shares, assets. + uint256 donatedShares = donatedAssets == 0 + ? 0 + : (shares * requiredMetapoolTokens) / donatedMetapoolTokens; + _afterSharesMintedHook(donatedShares, donatedAssets); } /// @dev Converts vault shares to assets in two steps /// Vault shares -> Metapool LP tokens, eg BUSDFRAXBP3CRV-f -> vault assets (crvFRAX) /// Override `AbstractVault._previewMint`. + /// changes - It takes into account any asset balance to be included in the next mint. function _previewMint(uint256 shares) internal view virtual override returns (uint256 assets) { if (shares > 0) { + uint256 donatedAssets = _asset.balanceOf(address(this)); + uint256 donatedMetapoolTokens = 0; + if (donatedAssets > 0) { + (donatedMetapoolTokens, , , ) = CurveFraxBpMetapoolCalculatorLibrary.calcDeposit( + metapool, + metapoolToken, + donatedAssets, + 1 + ); + } uint256 metapoolTokens = _getMetapoolTokensFromShares( shares, baseRewardPool.balanceOf(address(this)), totalSupply() ); - (assets, , , ) = CurveFraxBpMetapoolCalculatorLibrary.calcMint( + (uint256 assetsToDeposit, , , ) = CurveFraxBpMetapoolCalculatorLibrary.calcMint( metapool, metapoolToken, - metapoolTokens, + metapoolTokens + donatedMetapoolTokens, 1 ); + // Calculate receivers portion of assets. + assets = (assetsToDeposit * (metapoolTokens + donatedMetapoolTokens)) / metapoolTokens; } } @@ -590,6 +641,9 @@ abstract contract ConvexFraxBpAbstractVault is AbstractSlippage, AbstractVault { } } + /// @dev Function accrue rewards to be implemented, invoked after deposit or mint + function _afterSharesMintedHook(uint256 newShares, uint256 newAssets) internal virtual; + /*************************************** Emergency Functions ****************************************/ diff --git a/contracts/vault/liquidity/convex/ConvexFraxBpBasicVault.sol b/contracts/vault/liquidity/convex/ConvexFraxBpBasicVault.sol index 695d869..5dc520c 100644 --- a/contracts/vault/liquidity/convex/ConvexFraxBpBasicVault.sol +++ b/contracts/vault/liquidity/convex/ConvexFraxBpBasicVault.sol @@ -57,4 +57,8 @@ contract ConvexFraxBpBasicVault is ConvexFraxBpAbstractVault, Initializable { uint8 decimals_ = InitializableToken(address(metapoolToken)).decimals(); InitializableToken._initialize(_name, _symbol, decimals_); } + + function _afterSharesMintedHook(uint256, uint256) internal virtual override { + // do nothing + } } diff --git a/contracts/vault/liquidity/convex/ConvexFraxBpLiquidatorVault.sol b/contracts/vault/liquidity/convex/ConvexFraxBpLiquidatorVault.sol index ab493cf..75f9547 100644 --- a/contracts/vault/liquidity/convex/ConvexFraxBpLiquidatorVault.sol +++ b/contracts/vault/liquidity/convex/ConvexFraxBpLiquidatorVault.sol @@ -136,8 +136,7 @@ contract ConvexFraxBpLiquidatorVault is * @dev Converts donated tokens (FRAX, USDC) to vault assets (crvFRAX) and shares. * Transfers token from donor to vault. * Adds the token to the frazBP to receive the vault asset (crvFRAX) in exchange. - * The resulting asset (crvFRAX) is added to the Curve frax Metapool. - * The Curve Metapool LP token, eg BUSDFRAXBP3CRV-f, is added to the Convex pool and staked. + * The resulting asset (crvFRAX) stays in the vault to be deposit in the next deposit / mint tx */ function _convertTokens(address token, uint256 amount) internal @@ -177,18 +176,7 @@ contract ConvexFraxBpLiquidatorVault is minMetapoolTokens = (minMetapoolTokens * (BASIS_SCALE - depositSlippage)) / BASIS_SCALE; assets_ = _asset.balanceOf(address(this)); - // Add asset (crvFRAX) to metapool with slippage protection. - uint256 metapoolTokens = ICurveMetapool(metapool).add_liquidity([0, assets_], minMetapoolTokens); - - // Calculate share value of the new assets before depositing the metapool tokens to the Convex pool. - shares_ = _getSharesFromMetapoolTokens( - metapoolTokens, - baseRewardPool.balanceOf(address(this)), - totalSupply() - ); - - // Deposit Curve.fi Metapool LP token, eg BUSDFRAXBP3CRV-f, in Convex pool, eg cvxBUSDFRAXBP3CRV-f, and stake. - booster.deposit(convexPoolId, metapoolTokens, true); + shares_ = 0; } /*************************************** @@ -329,6 +317,14 @@ contract ConvexFraxBpLiquidatorVault is shares = ConvexFraxBpAbstractVault._withdraw(assets, receiver, owner); } + /// @dev use LiquidatorStreamAbstractVault._streamNewShares implementation. + function _afterSharesMintedHook( + uint256 newShares, + uint256 newAssets + ) internal virtual override(ConvexFraxBpAbstractVault) { + LiquidatorStreamAbstractVault._streamNewShares(newShares, newAssets); + } + function _convertToAssets(uint256 shares) internal view diff --git a/docs/Convex3CrvAbstractVault.svg b/docs/Convex3CrvAbstractVault.svg index 62f095a..96bc0fb 100644 --- a/docs/Convex3CrvAbstractVault.svg +++ b/docs/Convex3CrvAbstractVault.svg @@ -4,150 +4,151 @@ - - + + UmlClassDiagram - - + + -45 - -<<Library>> -Curve3CrvMetapoolCalculatorLibrary -../contracts/peripheral/Curve/Curve3CrvMetapoolCalculatorLibrary.sol - -Public: -   BASE_POOL: ICurve3Pool -   N_COINS: uint256 -   VIRTUAL_PRICE_SCALE: uint256 -   CURVE_FEE_SCALE: uint256 -   BASE_CACHE_EXPIRES: uint256 -   MINT_ADJUST: uint256 -   MINT_ADJUST_SCALE: uint256 - -Internal: -    _baseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) -    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) -    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) -External: -    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) -    getBaseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) -    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) -    getVirtualPrices(metapool: address, metapoolToken: address, cached: bool): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) -    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) -    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) -    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) -    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) -Public: -    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256, cached: bool): (baseLp_: uint256) -    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256, cached: bool): (metaLp_: uint256) +36 + +<<Library>> +Curve3CrvMetapoolCalculatorLibrary +../contracts/peripheral/Curve/Curve3CrvMetapoolCalculatorLibrary.sol + +Public: +   BASE_POOL: address +   N_COINS: uint256 +   VIRTUAL_PRICE_SCALE: uint256 +   CURVE_FEE_SCALE: uint256 +   BASE_CACHE_EXPIRES: uint256 +   MINT_ADJUST: uint256 +   MINT_ADJUST_SCALE: uint256 + +Internal: +    _baseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) +    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) +    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) +External: +    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) +    getBaseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) +    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) +    getVirtualPrices(metapool: address, metapoolToken: address, cached: bool): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) +    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) +    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) +    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) +    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) +Public: +    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256, cached: bool): (baseLp_: uint256) +    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256, cached: bool): (metaLp_: uint256) - + -30 - -<<Abstract>> -AbstractVault -../contracts/vault/AbstractVault.sol - -Internal: -   _asset: IERC20 - -Internal: -    _deposit(assets: uint256, receiver: address): (shares: uint256) -    _previewDeposit(assets: uint256): (shares: uint256) -    _maxDeposit(address): (maxAssets: uint256) -    _mint(shares: uint256, receiver: address): (assets: uint256) -    _previewMint(shares: uint256): (assets: uint256) -    _maxMint(address): (maxShares: uint256) -    _transferAndMint(assets: uint256, shares: uint256, receiver: address, fromDeposit: bool) -    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) -    _previewWithdraw(assets: uint256): (shares: uint256) -    _maxWithdraw(owner: address): (maxAssets: uint256) -    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) -    _previewRedeem(shares: uint256): (assets: uint256) -    _maxRedeem(owner: address): (maxShares: uint256) -    _burnTransfer(assets: uint256, shares: uint256, receiver: address, owner: address, fromRedeem: bool) -    _convertToAssets(shares: uint256): (assets: uint256) -    _convertToShares(assets: uint256): (shares: uint256) -    _afterDepositHook(assets: uint256, shares: uint256, receiver: address, fromDeposit: bool) -    _beforeWithdrawHook(assets: uint256, shares: uint256, owner: address, fromRedeem: bool) -External: -    deposit(assets: uint256, receiver: address): (shares: uint256) <<whenNotPaused>> -    previewDeposit(assets: uint256): (shares: uint256) -    maxDeposit(caller: address): (maxAssets: uint256) -    mint(shares: uint256, receiver: address): (assets: uint256) <<whenNotPaused>> -    previewMint(shares: uint256): (assets: uint256) -    maxMint(owner: address): (maxShares: uint256) -    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) <<whenNotPaused>> -    previewWithdraw(assets: uint256): (shares: uint256) -    maxWithdraw(owner: address): (maxAssets: uint256) -    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) <<whenNotPaused>> -    previewRedeem(shares: uint256): (assets: uint256) -    maxRedeem(owner: address): (maxShares: uint256) -    asset(): (assetTokenAddress: address) -    convertToAssets(shares: uint256): (assets: uint256) -    convertToShares(assets: uint256): (shares: uint256) -Public: -    <<abstract>> totalAssets(): (totalManagedAssets: uint256) -    constructor(_assetArg: address) +26 + +<<Abstract>> +AbstractVault +../contracts/vault/AbstractVault.sol + +Internal: +   _asset: IERC20 + +Internal: +    _deposit(assets: uint256, receiver: address): (shares: uint256) +    _previewDeposit(assets: uint256): (shares: uint256) +    _maxDeposit(address): (maxAssets: uint256) +    _mint(shares: uint256, receiver: address): (assets: uint256) +    _previewMint(shares: uint256): (assets: uint256) +    _maxMint(address): (maxShares: uint256) +    _transferAndMint(assets: uint256, shares: uint256, receiver: address, fromDeposit: bool) +    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    _previewWithdraw(assets: uint256): (shares: uint256) +    _maxWithdraw(owner: address): (maxAssets: uint256) +    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    _previewRedeem(shares: uint256): (assets: uint256) +    _maxRedeem(owner: address): (maxShares: uint256) +    _burnTransfer(assets: uint256, shares: uint256, receiver: address, owner: address, fromRedeem: bool) +    _convertToAssets(shares: uint256): (assets: uint256) +    _convertToShares(assets: uint256): (shares: uint256) +    _afterDepositHook(assets: uint256, shares: uint256, receiver: address, fromDeposit: bool) +    _beforeWithdrawHook(assets: uint256, shares: uint256, owner: address, fromRedeem: bool) +External: +    deposit(assets: uint256, receiver: address): (shares: uint256) +    previewDeposit(assets: uint256): (shares: uint256) +    maxDeposit(caller: address): (maxAssets: uint256) +    mint(shares: uint256, receiver: address): (assets: uint256) +    previewMint(shares: uint256): (assets: uint256) +    maxMint(owner: address): (maxShares: uint256) +    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    previewWithdraw(assets: uint256): (shares: uint256) +    maxWithdraw(owner: address): (maxAssets: uint256) +    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    previewRedeem(shares: uint256): (assets: uint256) +    maxRedeem(owner: address): (maxShares: uint256) +    asset(): (assetTokenAddress: address) +    convertToAssets(shares: uint256): (assets: uint256) +    convertToShares(assets: uint256): (shares: uint256) +Public: +    <<abstract>> totalAssets(): (totalManagedAssets: uint256) +    constructor(_assetArg: address) - + -76 - -<<Abstract>> -AbstractSlippage -../contracts/vault/liquidity/AbstractSlippage.sol - -Public: -   BASIS_SCALE: uint256 -   redeemSlippage: uint256 -   depositSlippage: uint256 -   withdrawSlippage: uint256 -   mintSlippage: uint256 - -Internal: -    _initialize(_slippageData: SlippageData) -    _setRedeemSlippage(_slippage: uint256) -    _setDepositSlippage(_slippage: uint256) -    _setWithdrawSlippage(_slippage: uint256) -    _setMintSlippage(_slippage: uint256) -External: -    setRedeemSlippage(_slippage: uint256) <<onlyGovernor>> -    setDepositSlippage(_slippage: uint256) <<onlyGovernor>> -    setWithdrawSlippage(_slippage: uint256) <<onlyGovernor>> -    setMintSlippage(_slippage: uint256) <<onlyGovernor>> -Public: -    <<event>> RedeemSlippageChange(sender: address, slippage: uint256) -    <<event>> DepositSlippageChange(sender: address, slippage: uint256) -    <<event>> WithdrawSlippageChange(sender: address, slippage: uint256) -    <<event>> MintSlippageChange(sender: address, slippage: uint256) +68 + +<<Abstract>> +AbstractSlippage +../contracts/vault/liquidity/AbstractSlippage.sol + +Public: +   BASIS_SCALE: uint256 +   redeemSlippage: uint256 +   depositSlippage: uint256 +   withdrawSlippage: uint256 +   mintSlippage: uint256 + +Internal: +    _initialize(_slippageData: SlippageData) +    _setRedeemSlippage(_slippage: uint256) +    _setDepositSlippage(_slippage: uint256) +    _setWithdrawSlippage(_slippage: uint256) +    _setMintSlippage(_slippage: uint256) +External: +    setRedeemSlippage(_slippage: uint256) +    setDepositSlippage(_slippage: uint256) +    setWithdrawSlippage(_slippage: uint256) +    setMintSlippage(_slippage: uint256) +Public: +    <<event>> RedeemSlippageChange(sender: address, slippage: uint256) +    <<event>> DepositSlippageChange(sender: address, slippage: uint256) +    <<event>> WithdrawSlippageChange(sender: address, slippage: uint256) +    <<event>> MintSlippageChange(sender: address, slippage: uint256) - + -100 - -<<Abstract>> -Convex3CrvAbstractVault -../contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol - -Public: -   ASSET_SCALE: uint256 -   VIRTUAL_PRICE_SCALE: uint256 -   metapool: address -   metapoolToken: address -   metapoolTokenScale: uint256 -   basePool: ICurve3Pool -   booster: IConvexBooster -   convexPoolId: uint256 -   baseRewardPool: IConvexRewardsPool - -Internal: +93 + +<<Abstract>> +Convex3CrvAbstractVault +../contracts/vault/liquidity/convex/Convex3CrvAbstractVault.sol + +Public: +   ASSET_SCALE: uint256 +   VIRTUAL_PRICE_SCALE: uint256 +   metapool: address +   metapoolToken: address +   metapoolTokenScale: uint256 +   basePool: address +   booster: IConvexBooster +   convexPoolId: uint256 +   baseRewardPool: IConvexRewardsPool + +Internal: +    <<abstract>> _afterSharesMintedHook(newShares: uint256, newAssets: uint256)    _initialize()    _deposit(assets: uint256, receiver: address): (shares: uint256)    _depositInternal(_assets: uint256, _receiver: address, _slippage: uint256): (shares: uint256) @@ -168,31 +169,31 @@    _getMetapoolTokensFromShares(_shares: uint256, _totalMetapoolTokens: uint256, _totalShares: uint256): (metapoolTokens: uint256)    _resetAllowances() External: -    deposit(assets: uint256, receiver: address, customDepositSlippage: uint256): (shares: uint256) <<whenNotPaused>> -    redeem(shares: uint256, receiver: address, owner: address, customRedeemSlippage: uint256): (assets: uint256) <<whenNotPaused>> -    liquidateVault(minAssets: uint256) <<onlyGovernor>> -    resetAllowances() <<onlyGovernor>> +    deposit(assets: uint256, receiver: address, customDepositSlippage: uint256): (shares: uint256) +    redeem(shares: uint256, receiver: address, owner: address, customRedeemSlippage: uint256): (assets: uint256) +    liquidateVault(minAssets: uint256) +    resetAllowances() Public:    constructor(_data: ConstructorData)    totalAssets(): (totalManagedAssets: uint256) - + -100->45 - - +93->36 + + - + -100->30 - - +93->26 + + - + -100->76 - - +93->68 + + diff --git a/docs/Convex3CrvLiquidatorVault.svg b/docs/Convex3CrvLiquidatorVault.svg index de30775..4c0477c 100644 --- a/docs/Convex3CrvLiquidatorVault.svg +++ b/docs/Convex3CrvLiquidatorVault.svg @@ -4,94 +4,95 @@ - - + + UmlClassDiagram - - + + -41 - -<<Library>> -Curve3CrvMetapoolCalculatorLibrary -../contracts/peripheral/Curve/Curve3CrvMetapoolCalculatorLibrary.sol - -Public: -   BASE_POOL: address -   N_COINS: uint256 -   VIRTUAL_PRICE_SCALE: uint256 -   CURVE_FEE_SCALE: uint256 -   BASE_CACHE_EXPIRES: uint256 -   MINT_ADJUST: uint256 -   MINT_ADJUST_SCALE: uint256 - -Internal: -    _baseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) -    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) -    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) -External: -    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) -    getBaseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) -    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) -    getVirtualPrices(metapool: address, metapoolToken: address, cached: bool): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) -    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) -    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) -    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) -    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) -Public: -    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256, cached: bool): (baseLp_: uint256) -    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256, cached: bool): (metaLp_: uint256) +36 + +<<Library>> +Curve3CrvMetapoolCalculatorLibrary +../contracts/peripheral/Curve/Curve3CrvMetapoolCalculatorLibrary.sol + +Public: +   BASE_POOL: address +   N_COINS: uint256 +   VIRTUAL_PRICE_SCALE: uint256 +   CURVE_FEE_SCALE: uint256 +   BASE_CACHE_EXPIRES: uint256 +   MINT_ADJUST: uint256 +   MINT_ADJUST_SCALE: uint256 + +Internal: +    _baseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) +    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) +    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) +External: +    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) +    getBaseVirtualPrice(metapool: address, cached: bool): (baseVirtualPrice_: uint256) +    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) +    getVirtualPrices(metapool: address, metapoolToken: address, cached: bool): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) +    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) +    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) +    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) +    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) +Public: +    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256, cached: bool): (baseLp_: uint256) +    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256, cached: bool): (metaLp_: uint256) - + -99 - -Convex3CrvLiquidatorVault -../contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol - -Internal: -   donateToken_: address -Public: -   DAI: address -   USDC: address -   USDT: address - -Internal: -    _donateToken(address): (token: address) -    _beforeCollectRewards() -    _convertTokens(token: address, amount: uint256): (shares_: uint256, assets_: uint256) -    _previewDeposit(assets: uint256): (shares: uint256) -    _previewMint(shares: uint256): (assets: uint256) -    _previewRedeem(shares: uint256): (assets: uint256) -    _previewWithdraw(assets: uint256): (shares: uint256) -    _deposit(assets: uint256, receiver: address): (shares: uint256) -    _mint(shares: uint256, receiver: address): (assets: uint256) -    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) -    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) -    _convertToAssets(shares: uint256): (assets: uint256) -    _convertToShares(assets: uint256): (shares: uint256) -    _setDonateToken(__donateToken: address) -External: -    initialize(_name: string, _symbol: string, _vaultManager: address, _slippageData: SlippageData, _rewardTokens: address[], __donateToken: address, _feeReceiver: address, _donationFee: uint256) <<initializer>> -    deposit(assets: uint256, receiver: address): (shares: uint256) <<whenNotPaused, streamRewards>> -    mint(shares: uint256, receiver: address): (assets: uint256) <<whenNotPaused, streamRewards>> -    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) <<whenNotPaused, streamRewards>> -    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) <<whenNotPaused, streamRewards>> -    setDonateToken(__donateToken: address) <<onlyKeeperOrGovernor>> -Public: -    <<event>> DonateTokenUpdated(token: address) -    constructor(_nexus: address, _asset: address, _data: ConstructorData, _streamDuration: uint256) -    totalSupply(): (shares: uint256) +96 + +Convex3CrvLiquidatorVault +../contracts/vault/liquidity/convex/Convex3CrvLiquidatorVault.sol + +Internal: +   donateToken_: address +Public: +   DAI: address +   USDC: address +   USDT: address + +Internal: +    _donateToken(address): (token: address) +    _beforeCollectRewards() +    _convertTokens(token: address, amount: uint256): (shares_: uint256, assets_: uint256) +    _previewDeposit(assets: uint256): (shares: uint256) +    _previewMint(shares: uint256): (assets: uint256) +    _previewRedeem(shares: uint256): (assets: uint256) +    _previewWithdraw(assets: uint256): (shares: uint256) +    _deposit(assets: uint256, receiver: address): (shares: uint256) +    _mint(shares: uint256, receiver: address): (assets: uint256) +    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    _afterSharesMintedHook(newShares: uint256, newAssets: uint256) +    _convertToAssets(shares: uint256): (assets: uint256) +    _convertToShares(assets: uint256): (shares: uint256) +    _setDonateToken(__donateToken: address) +External: +    initialize(_name: string, _symbol: string, _vaultManager: address, _slippageData: SlippageData, _rewardTokens: address[], __donateToken: address, _feeReceiver: address, _donationFee: uint256) +    deposit(assets: uint256, receiver: address): (shares: uint256) +    mint(shares: uint256, receiver: address): (assets: uint256) +    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    setDonateToken(__donateToken: address) +Public: +    <<event>> DonateTokenUpdated(token: address) +    constructor(_nexus: address, _asset: address, _data: ConstructorData, _streamDuration: uint256) +    totalSupply(): (shares: uint256) - + -99->41 - - +96->36 + + diff --git a/docs/ConvexFraxBpAbstractVault.svg b/docs/ConvexFraxBpAbstractVault.svg index 5f85fa4..cd5a570 100644 --- a/docs/ConvexFraxBpAbstractVault.svg +++ b/docs/ConvexFraxBpAbstractVault.svg @@ -9,13 +9,13 @@ UmlClassDiagram - + -44 +39 <<Library>> CurveFraxBpMetapoolCalculatorLibrary -..contractsperipheralCurveCurveFraxBpMetapoolCalculatorLibrary.sol +../contracts/peripheral/Curve/CurveFraxBpMetapoolCalculatorLibrary.sol Public:   BASE_POOL: address @@ -46,7 +46,7 @@ <<Abstract>> AbstractVault -..contractsvaultAbstractVault.sol +../contracts/vault/AbstractVault.sol Internal:   _asset: IERC20 @@ -71,16 +71,16 @@    _afterDepositHook(assets: uint256, shares: uint256, receiver: address, fromDeposit: bool)    _beforeWithdrawHook(assets: uint256, shares: uint256, owner: address, fromRedeem: bool) External: -    deposit(assets: uint256, receiver: address): (shares: uint256) <<whenNotPaused>> +    deposit(assets: uint256, receiver: address): (shares: uint256)    previewDeposit(assets: uint256): (shares: uint256)    maxDeposit(caller: address): (maxAssets: uint256) -    mint(shares: uint256, receiver: address): (assets: uint256) <<whenNotPaused>> +    mint(shares: uint256, receiver: address): (assets: uint256)    previewMint(shares: uint256): (assets: uint256)    maxMint(owner: address): (maxShares: uint256) -    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) <<whenNotPaused>> +    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256)    previewWithdraw(assets: uint256): (shares: uint256)    maxWithdraw(owner: address): (maxAssets: uint256) -    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) <<whenNotPaused>> +    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256)    previewRedeem(shares: uint256): (assets: uint256)    maxRedeem(owner: address): (maxShares: uint256)    asset(): (assetTokenAddress: address) @@ -90,59 +90,58 @@    <<abstract>> totalAssets(): (totalManagedAssets: uint256)    constructor(_assetArg: address) - + -73 - -<<Abstract>> -AbstractSlippage -..contractsvault -iquidityAbstractSlippage.sol - -Public: -   BASIS_SCALE: uint256 -   redeemSlippage: uint256 -   depositSlippage: uint256 -   withdrawSlippage: uint256 -   mintSlippage: uint256 - -Internal: -    _initialize(_slippageData: SlippageData) -    _setRedeemSlippage(_slippage: uint256) -    _setDepositSlippage(_slippage: uint256) -    _setWithdrawSlippage(_slippage: uint256) -    _setMintSlippage(_slippage: uint256) -External: -    setRedeemSlippage(_slippage: uint256) <<onlyGovernor>> -    setDepositSlippage(_slippage: uint256) <<onlyGovernor>> -    setWithdrawSlippage(_slippage: uint256) <<onlyGovernor>> -    setMintSlippage(_slippage: uint256) <<onlyGovernor>> -Public: -    <<event>> RedeemSlippageChange(sender: address, slippage: uint256) -    <<event>> DepositSlippageChange(sender: address, slippage: uint256) -    <<event>> WithdrawSlippageChange(sender: address, slippage: uint256) -    <<event>> MintSlippageChange(sender: address, slippage: uint256) +68 + +<<Abstract>> +AbstractSlippage +../contracts/vault/liquidity/AbstractSlippage.sol + +Public: +   BASIS_SCALE: uint256 +   redeemSlippage: uint256 +   depositSlippage: uint256 +   withdrawSlippage: uint256 +   mintSlippage: uint256 + +Internal: +    _initialize(_slippageData: SlippageData) +    _setRedeemSlippage(_slippage: uint256) +    _setDepositSlippage(_slippage: uint256) +    _setWithdrawSlippage(_slippage: uint256) +    _setMintSlippage(_slippage: uint256) +External: +    setRedeemSlippage(_slippage: uint256) +    setDepositSlippage(_slippage: uint256) +    setWithdrawSlippage(_slippage: uint256) +    setMintSlippage(_slippage: uint256) +Public: +    <<event>> RedeemSlippageChange(sender: address, slippage: uint256) +    <<event>> DepositSlippageChange(sender: address, slippage: uint256) +    <<event>> WithdrawSlippageChange(sender: address, slippage: uint256) +    <<event>> MintSlippageChange(sender: address, slippage: uint256) - + -102 +97 <<Abstract>> ConvexFraxBpAbstractVault -..contractsvault -iquidityconvexConvexFraxBpAbstractVault.sol - -Public: -   ASSET_SCALE: uint256 -   metapool: address -   metapoolToken: address -   metapoolTokenScale: uint256 -   basePool: address -   booster: IConvexBooster -   convexPoolId: uint256 -   baseRewardPool: IConvexRewardsPool - -Internal: +../contracts/vault/liquidity/convex/ConvexFraxBpAbstractVault.sol + +Public: +   ASSET_SCALE: uint256 +   metapool: address +   metapoolToken: address +   metapoolTokenScale: uint256 +   basePool: address +   booster: IConvexBooster +   convexPoolId: uint256 +   baseRewardPool: IConvexRewardsPool + +Internal: +    <<abstract>> _afterSharesMintedHook(newShares: uint256, newAssets: uint256)    _initialize()    _deposit(assets: uint256, receiver: address): (shares: uint256)    _depositInternal(_assets: uint256, _receiver: address, _slippage: uint256): (shares: uint256) @@ -163,31 +162,31 @@    _getMetapoolTokensFromShares(_shares: uint256, _totalMetapoolTokens: uint256, _totalShares: uint256): (metapoolTokens: uint256)    _resetAllowances() External: -    deposit(assets: uint256, receiver: address, customDepositSlippage: uint256): (shares: uint256) <<whenNotPaused>> -    redeem(shares: uint256, receiver: address, owner: address, customRedeemSlippage: uint256): (assets: uint256) <<whenNotPaused>> -    liquidateVault(minAssets: uint256) <<onlyGovernor>> -    resetAllowances() <<onlyGovernor>> +    deposit(assets: uint256, receiver: address, customDepositSlippage: uint256): (shares: uint256) +    redeem(shares: uint256, receiver: address, owner: address, customRedeemSlippage: uint256): (assets: uint256) +    liquidateVault(minAssets: uint256) +    resetAllowances() Public:    constructor(_data: ConstructorData)    totalAssets(): (totalManagedAssets: uint256) - + -102->44 +97->39 - + -102->26 +97->26 - + -102->73 - - +97->68 + + diff --git a/docs/ConvexFraxBpLiquidatorVault.svg b/docs/ConvexFraxBpLiquidatorVault.svg index 57521ef..fb636d5 100644 --- a/docs/ConvexFraxBpLiquidatorVault.svg +++ b/docs/ConvexFraxBpLiquidatorVault.svg @@ -4,88 +4,88 @@ - + UmlClassDiagram - - + + -44 - -<<Library>> -CurveFraxBpMetapoolCalculatorLibrary -..contractsperipheralCurveCurveFraxBpMetapoolCalculatorLibrary.sol - -Public: -   BASE_POOL: address -   N_COINS: uint256 -   VIRTUAL_PRICE_SCALE: uint256 -   CURVE_FEE_SCALE: uint256 -   MINT_ADJUST: uint256 -   MINT_ADJUST_SCALE: uint256 - -Internal: -    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) -    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) -External: -    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) -    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) -    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) -    getVirtualPrices(metapool: address, metapoolToken: address): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) -    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) -    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) -    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) -    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) +39 + +<<Library>> +CurveFraxBpMetapoolCalculatorLibrary +../contracts/peripheral/Curve/CurveFraxBpMetapoolCalculatorLibrary.sol + +Public: +   BASE_POOL: address +   N_COINS: uint256 +   VIRTUAL_PRICE_SCALE: uint256 +   CURVE_FEE_SCALE: uint256 +   MINT_ADJUST: uint256 +   MINT_ADJUST_SCALE: uint256 + +Internal: +    _getD(xp: uint256[N_COINS], Ann: uint256): (D: uint256) +    _getY(xp: uint256[N_COINS], Ann: uint256, coinIndex: uint256, D: uint256): (y: uint256) +External: +    calcDeposit(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (mintAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcWithdraw(_metapool: address, _metapoolToken: address, _tokenAmount: uint256, _coinIndex: uint256): (burnAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcMint(_metapool: address, _metapoolToken: address, _mintAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256, baseVirtualPrice_: uint256) +    calcRedeem(_metapool: address, _metapoolToken: address, _burnAmount: uint256, _coinIndex: uint256): (tokenAmount_: uint256, invariant_: uint256, totalSupply_: uint256) +    getBaseVirtualPrice(): (baseVirtualPrice_: uint256) +    getVirtualPrices(metapool: address, metapoolToken: address): (metaVirtualPrice_: uint256, baseVirtualPrice_: uint256) +    convertUsdToBaseLp(usdAmount: uint256): (baseLp_: uint256) +    convertUsdToMetaLp(metapool: address, usdAmount: uint256): (metaLp_: uint256) +    convertToBaseLp(metapool: address, metapoolToken: address, metaLp: uint256): (baseLp_: uint256) +    convertToMetaLp(metapool: address, metapoolToken: address, baseLp: uint256): (metaLp_: uint256) - + -105 - -ConvexFraxBpLiquidatorVault -..contractsvault -iquidityconvexConvexFraxBpLiquidatorVault.sol - -Internal: -   donateToken_: address -Public: -   FRAX: address -   USDC: address - -Internal: -    _donateToken(address): (token: address) -    _beforeCollectRewards() -    _convertTokens(token: address, amount: uint256): (shares_: uint256, assets_: uint256) -    _previewDeposit(assets: uint256): (shares: uint256) -    _previewMint(shares: uint256): (assets: uint256) -    _previewRedeem(shares: uint256): (assets: uint256) -    _previewWithdraw(assets: uint256): (shares: uint256) -    _deposit(assets: uint256, receiver: address): (shares: uint256) <<streamRewards>> -    _mint(shares: uint256, receiver: address): (assets: uint256) <<streamRewards>> -    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) -    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) -    _convertToAssets(shares: uint256): (assets: uint256) -    _convertToShares(assets: uint256): (shares: uint256) -    _setDonateToken(__donateToken: address) -External: -    initialize(_name: string, _symbol: string, _vaultManager: address, _slippageData: SlippageData, _rewardTokens: address[], __donateToken: address, _feeReceiver: address, _donationFee: uint256) <<initializer>> -    deposit(assets: uint256, receiver: address): (shares: uint256) <<whenNotPaused, streamRewards>> -    mint(shares: uint256, receiver: address): (assets: uint256) <<whenNotPaused, streamRewards>> -    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) <<whenNotPaused, streamRewards>> -    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) <<whenNotPaused, streamRewards>> -    setDonateToken(__donateToken: address) <<onlyKeeperOrGovernor>> -Public: -    <<event>> DonateTokenUpdated(token: address) -    constructor(_nexus: address, _asset: address, _data: ConstructorData, _streamDuration: uint256) -    totalSupply(): uint256 +100 + +ConvexFraxBpLiquidatorVault +../contracts/vault/liquidity/convex/ConvexFraxBpLiquidatorVault.sol + +Internal: +   donateToken_: address +Public: +   FRAX: address +   USDC: address + +Internal: +    _donateToken(address): (token: address) +    _beforeCollectRewards() +    _convertTokens(token: address, amount: uint256): (shares_: uint256, assets_: uint256) +    _previewDeposit(assets: uint256): (shares: uint256) +    _previewMint(shares: uint256): (assets: uint256) +    _previewRedeem(shares: uint256): (assets: uint256) +    _previewWithdraw(assets: uint256): (shares: uint256) +    _deposit(assets: uint256, receiver: address): (shares: uint256) +    _mint(shares: uint256, receiver: address): (assets: uint256) +    _redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    _withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    _afterSharesMintedHook(newShares: uint256, newAssets: uint256) +    _convertToAssets(shares: uint256): (assets: uint256) +    _convertToShares(assets: uint256): (shares: uint256) +    _setDonateToken(__donateToken: address) +External: +    initialize(_name: string, _symbol: string, _vaultManager: address, _slippageData: SlippageData, _rewardTokens: address[], __donateToken: address, _feeReceiver: address, _donationFee: uint256) +    deposit(assets: uint256, receiver: address): (shares: uint256) +    mint(shares: uint256, receiver: address): (assets: uint256) +    redeem(shares: uint256, receiver: address, owner: address): (assets: uint256) +    withdraw(assets: uint256, receiver: address, owner: address): (shares: uint256) +    setDonateToken(__donateToken: address) +Public: +    <<event>> DonateTokenUpdated(token: address) +    constructor(_nexus: address, _asset: address, _data: ConstructorData, _streamDuration: uint256) +    totalSupply(): uint256 - + -105->44 - - +100->39 + + diff --git a/test-fork/vault/Convex3CrvLiquidatorVault.spec.ts b/test-fork/vault/Convex3CrvLiquidatorVault.spec.ts index 4da6fa8..db84598 100644 --- a/test-fork/vault/Convex3CrvLiquidatorVault.spec.ts +++ b/test-fork/vault/Convex3CrvLiquidatorVault.spec.ts @@ -289,60 +289,24 @@ describe("Convex 3Crv Liquidator Vault", async () => { await daiToken.connect(mockLiquidator.signer).approve(musdConvexVault.address, donateAmount) const tx = await musdConvexVault.connect(mockLiquidator.signer).donate(DAI.address, donateAmount) - // Deposit event for the fee - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs(getAddress(mockLiquidator.address), feeReceiver, BN.from("9794853641497136119"), BN.from("9833364392187925988")) - - // Deposit event for the streaming of shares - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs( - getAddress(mockLiquidator.address), - musdConvexVault.address, - BN.from("969690510508216475829"), - BN.from("973503074826604672871"), - ) + // Deposit events + await expect(tx).to.not.emit(musdConvexVault, "Deposit") }) it("donate USDC tokens back to vault", async () => { const donateAmount = simpleToExactAmount(2000, USDC.decimals) await usdcToken.connect(mockLiquidator.signer).approve(musdConvexVault.address, donateAmount) const tx = await musdConvexVault.connect(mockLiquidator.signer).donate(USDC.address, donateAmount) - // Deposit event for the fee - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs(getAddress(mockLiquidator.address), feeReceiver, BN.from("19589780279497850787"), BN.from("19666801263319303387")) - - // Deposit event for the streaming of shares - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs( - getAddress(mockLiquidator.address), - musdConvexVault.address, - BN.from("1939388247670287227957"), - BN.from("1947013325068611035339"), - ) + // Deposit events + await expect(tx).to.not.emit(musdConvexVault, "Deposit") }) it("donate USDT tokens back to vault", async () => { const donateAmount = simpleToExactAmount(3000, USDT.decimals) await usdtToken.connect(mockLiquidator.signer).approve(musdConvexVault.address, donateAmount) const tx = await musdConvexVault.connect(mockLiquidator.signer).donate(USDT.address, donateAmount) - // Deposit event for the fee - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs(getAddress(mockLiquidator.address), feeReceiver, BN.from("29387432952198505245"), BN.from("29502974082101049187")) - - // Deposit event for the streaming of shares - await expect(tx) - .to.emit(musdConvexVault, "Deposit") - .withArgs( - getAddress(mockLiquidator.address), - musdConvexVault.address, - BN.from("2909355862267652019290"), - BN.from("2920794434128003869611"), - ) + // Deposit events + await expect(tx).to.not.emit(musdConvexVault, "Deposit") }) it("should fail to donate CRV tokens back to vault", async () => { const donateAmount = simpleToExactAmount(1000, CRV.decimals) diff --git a/test-fork/vault/ConvexFraxBpLiquidatorVault.spec.ts b/test-fork/vault/ConvexFraxBpLiquidatorVault.spec.ts index bc9b28d..04b2e91 100644 --- a/test-fork/vault/ConvexFraxBpLiquidatorVault.spec.ts +++ b/test-fork/vault/ConvexFraxBpLiquidatorVault.spec.ts @@ -146,8 +146,12 @@ describe("Convex FraxBp Liquidator Vault", async () => { ) expect(await busdFraxConvexVault.nexus(), "nexus").eq(nexusAddress) - expect((await busdFraxConvexVault.metapool()).toLowerCase(), "curve Metapool").to.equal(config.convexFraxBpPools.busd.curveMetapool.toLowerCase()) - expect((await busdFraxConvexVault.metapoolToken()).toLowerCase(), "metapool token").to.equal(config.convexFraxBpPools.busd.curveMetapoolToken.toLowerCase()) + expect((await busdFraxConvexVault.metapool()).toLowerCase(), "curve Metapool").to.equal( + config.convexFraxBpPools.busd.curveMetapool.toLowerCase(), + ) + expect((await busdFraxConvexVault.metapoolToken()).toLowerCase(), "metapool token").to.equal( + config.convexFraxBpPools.busd.curveMetapoolToken.toLowerCase(), + ) expect(await busdFraxConvexVault.basePool(), "FraxBp pool").to.equal(resolveAddress("FraxBP")) expect(await busdFraxConvexVault.booster(), "booster").to.equal(booster) expect(await busdFraxConvexVault.convexPoolId(), "convex Pool Id").to.equal(config.convexFraxBpPools.busd.convexPoolId) @@ -268,7 +272,9 @@ describe("Convex FraxBp Liquidator Vault", async () => { it("donate USDC tokens back to vault", async () => { const usdcAmount = simpleToExactAmount(1000, USDC.decimals) await usdcToken.connect(mockLiquidator.signer).approve(busdFraxConvexVault.address, usdcAmount) - await busdFraxConvexVault.connect(mockLiquidator.signer).donate(USDC.address, usdcAmount) + const tx = await busdFraxConvexVault.connect(mockLiquidator.signer).donate(USDC.address, usdcAmount) + // Deposit events + await expect(tx).to.not.emit(busdFraxConvexVault, "Deposit") }) }) describe("set donate token", () => { diff --git a/test-fork/vault/shared/Convex3Crv.behaviour.ts b/test-fork/vault/shared/Convex3Crv.behaviour.ts index fb00423..08b03af 100644 --- a/test-fork/vault/shared/Convex3Crv.behaviour.ts +++ b/test-fork/vault/shared/Convex3Crv.behaviour.ts @@ -1,7 +1,7 @@ import { usdFormatter } from "@tasks/utils" import { logger } from "@tasks/utils/logger" import { ThreeCRV } from "@tasks/utils/tokens" -import { ONE_DAY, SAFE_INFINITY } from "@utils/constants" +import { ONE_DAY, SAFE_INFINITY, ZERO, ZERO_ADDRESS } from "@utils/constants" import { basisPointDiff, BN, simpleToExactAmount } from "@utils/math" import { increaseTime } from "@utils/time" import { expect } from "chai" @@ -22,6 +22,7 @@ import type { ICurveMetapool, IERC20, } from "types/generated" +import { assertBNClose } from "@utils/assertions" const log = logger("test:Convex3CrvVault") @@ -129,6 +130,8 @@ export interface Convex3CrvContext { redeem: BigNumber } } +const isConvex3CrvLiquidatorVault = (vault: Convex3CrvVault): boolean => "donate" in vault + export const behaveLikeConvex3CrvVault = (ctx: () => Convex3CrvContext): void => { const getAssetsFromTokens = async (tokens: BN): Promise => { const { threePool, metapool } = ctx() @@ -347,9 +350,20 @@ export const behaveLikeConvex3CrvVault = (ctx: () => Convex3CrvContext): void => it("user deposits 3Crv assets to vault", async () => { const { amounts, threeCrvToken, owner, vault } = ctx() + let feeReceiver = ZERO_ADDRESS + let streamedSharesBefore = ZERO + if (isConvex3CrvLiquidatorVault(vault)) { + const vaultL = vault as Convex3CrvLiquidatorVault + feeReceiver = await vaultL.feeReceiver() + streamedSharesBefore = await vaultL.streamedShares() + } + const receiver = Wallet.createRandom().address const ownerAssetsBefore = await threeCrvToken.balanceOf(owner.address) const totalAssetsBefore = await vault.totalAssets() + const receiverSharesBefore = await vault.balanceOf(receiver) + const feeReceiverSharesBefore = await vault.balanceOf(feeReceiver) + const donatedAssetsBefore = await threeCrvToken.balanceOf(vault.address) // Enough assets for deposit log(`owner's 3Crv balance ${usdFormatter(ownerAssetsBefore)}`) @@ -374,14 +388,46 @@ export const behaveLikeConvex3CrvVault = (ctx: () => Convex3CrvContext): void => expect(await threeCrvToken.balanceOf(owner.address), "owner assets").eq(ownerAssetsBefore.sub(amounts.initialDeposit)) // Shares const totalSharesAfter = await vault.totalSupply({ blockTag: txDeposit.blockNumber }) - const sharesMinted = totalSharesAfter.sub(totalSharesBefore) - expect(sharesMinted, "minted shares == preview shares").eq(previewShares) - expect(await vault.balanceOf(receiver), "receiver shares").eq(sharesMinted) + const receiverSharesAfter = await vault.balanceOf(receiver) + const receiverSharesMinted = receiverSharesAfter.sub(receiverSharesBefore) + expect(receiverSharesMinted, "minted shares == preview shares").eq(previewShares) + // Total assets const totalAssetsAfter = await vault.totalAssets() - const totalAssetsDiff = totalAssetsAfter.sub(totalAssetsBefore) + const totalAssetsDiff = totalAssetsAfter.sub(totalAssetsBefore).sub(donatedAssetsBefore) + const donatedAssetsAfter = await threeCrvToken.balanceOf(vault.address) + const assetsSlippage = basisPointDiff(amounts.initialDeposit, totalAssetsDiff) + expect(assetsSlippage, "total assets diff to deposit amount").lte(50).gte(-50) + + // Add checks for donations + if (isConvex3CrvLiquidatorVault(vault)) { + const vaultL = vault as Convex3CrvLiquidatorVault + + const feeReceiverSharesAfter = await vaultL.balanceOf(feeReceiver) + const streamedSharesAfter = await vaultL.streamedShares() + + const feeReceiverSharesMinted = feeReceiverSharesAfter.sub(feeReceiverSharesBefore) + const streamedSharesMinted = streamedSharesAfter.sub(streamedSharesBefore) + const sharesMinted = totalSharesAfter.sub(totalSharesBefore) + const donatedSharesMinted = sharesMinted.sub(receiverSharesMinted) + + const donationFee = await vaultL.donationFee() + const feeScale = await vaultL.FEE_SCALE() + const feeReceiverSharesExpected = donatedSharesMinted.mul(donationFee).div(feeScale) + const streamedSharesExpected = donatedSharesMinted.sub(feeReceiverSharesExpected) + + assertBNClose( + sharesMinted, + receiverSharesMinted.add(feeReceiverSharesMinted).add(streamedSharesMinted), + BN.from(10), + "total shares minted", + ) + assertBNClose(feeReceiverSharesMinted, feeReceiverSharesExpected, BN.from(10), "fee receiver shares minted") + assertBNClose(streamedSharesMinted, streamedSharesExpected, BN.from(10), "shares to streamed minted") + expect(donatedAssetsAfter, "donated assets after").eq(ZERO) + } }) it("user redeems some shares from vault", async () => { const { amounts, threeCrvToken, owner, vault } = ctx() diff --git a/test-fork/vault/shared/ConvexFraxBp.behaviour.ts b/test-fork/vault/shared/ConvexFraxBp.behaviour.ts index 2d0d3d0..3740441 100644 --- a/test-fork/vault/shared/ConvexFraxBp.behaviour.ts +++ b/test-fork/vault/shared/ConvexFraxBp.behaviour.ts @@ -1,7 +1,7 @@ import { usdFormatter } from "@tasks/utils" import { logger } from "@tasks/utils/logger" import { crvFRAX } from "@tasks/utils/tokens" -import { ONE_DAY, SAFE_INFINITY } from "@utils/constants" +import { ONE_DAY, SAFE_INFINITY, ZERO, ZERO_ADDRESS } from "@utils/constants" import { basisPointDiff, BN, simpleToExactAmount } from "@utils/math" import { increaseTime } from "@utils/time" import { expect } from "chai" @@ -20,10 +20,12 @@ import type { ICurveMetapool, IERC20, } from "types/generated" +import { assertBNClose } from "@utils/assertions" const log = logger("test:ConvexFraxBpVault") export type ConvexFraxBpVault = ConvexFraxBpBasicVault | ConvexFraxBpLiquidatorVault +const isConvexFraxBpLiquidatorVault = (vault: ConvexFraxBpVault): boolean => "donate" in vault export interface VaultData { address: string @@ -333,10 +335,20 @@ export const behaveLikeConvexFraxBpVault = (ctx: () => ConvexFraxBpContext): voi }) it("user deposits crvFrax assets to vault", async () => { const { amounts, crvFraxToken, owner, vault } = ctx() + let feeReceiver = ZERO_ADDRESS + let streamedSharesBefore = ZERO + if (isConvexFraxBpLiquidatorVault(vault)) { + const vaultL = vault as ConvexFraxBpLiquidatorVault + feeReceiver = await vaultL.feeReceiver() + streamedSharesBefore = await vaultL.streamedShares() + } const receiver = Wallet.createRandom().address const ownerAssetsBefore = await crvFraxToken.balanceOf(owner.address) const totalAssetsBefore = await vault.totalAssets() + const receiverSharesBefore = await vault.balanceOf(receiver) + const feeReceiverSharesBefore = await vault.balanceOf(feeReceiver) + const donatedAssetsBefore = await crvFraxToken.balanceOf(vault.address) // Enough assets for deposit log(`owner's crvFrax balance ${usdFormatter(ownerAssetsBefore)}`) @@ -361,14 +373,43 @@ export const behaveLikeConvexFraxBpVault = (ctx: () => ConvexFraxBpContext): voi expect(await crvFraxToken.balanceOf(owner.address), "owner assets").eq(ownerAssetsBefore.sub(amounts.initialDeposit)) // Shares const totalSharesAfter = await vault.totalSupply({ blockTag: txDeposit.blockNumber }) - const sharesMinted = totalSharesAfter.sub(totalSharesBefore) - expect(sharesMinted, "minted shares == preview shares").eq(previewShares) - expect(await vault.balanceOf(receiver), "receiver shares").eq(sharesMinted) + const receiverSharesAfter = await vault.balanceOf(receiver) + const receiverSharesMinted = receiverSharesAfter.sub(receiverSharesBefore) + expect(receiverSharesMinted, "minted shares == preview shares").eq(previewShares) + // Total assets const totalAssetsAfter = await vault.totalAssets() const totalAssetsDiff = totalAssetsAfter.sub(totalAssetsBefore) + const donatedAssetsAfter = await crvFraxToken.balanceOf(vault.address) const assetsSlippage = basisPointDiff(amounts.initialDeposit, totalAssetsDiff) expect(assetsSlippage, "total assets diff to deposit amount").lte(50).gte(-50) + // Add checks for donations + if (isConvexFraxBpLiquidatorVault(vault)) { + const vaultL = vault as ConvexFraxBpLiquidatorVault + + const feeReceiverSharesAfter = await vaultL.balanceOf(feeReceiver) + const streamedSharesAfter = await vaultL.streamedShares() + + const feeReceiverSharesMinted = feeReceiverSharesAfter.sub(feeReceiverSharesBefore) + const streamedSharesMinted = streamedSharesAfter.sub(streamedSharesBefore) + const sharesMinted = totalSharesAfter.sub(totalSharesBefore) + const donatedSharesMinted = sharesMinted.sub(receiverSharesMinted) + + const donationFee = await vaultL.donationFee() + const feeScale = await vaultL.FEE_SCALE() + const feeReceiverSharesExpected = donatedSharesMinted.mul(donationFee).div(feeScale) + const streamedSharesExpected = donatedSharesMinted.sub(feeReceiverSharesExpected) + + assertBNClose( + sharesMinted, + receiverSharesMinted.add(feeReceiverSharesMinted).add(streamedSharesMinted), + BN.from(10), + "total shares minted", + ) + assertBNClose(feeReceiverSharesMinted, feeReceiverSharesExpected, BN.from(10), "fee receiver shares minted") + assertBNClose(streamedSharesMinted, streamedSharesExpected, BN.from(10), "shares to streamed minted") + expect(donatedAssetsAfter, "donated assets after").eq(ZERO) + } }) it("user redeems some shares from vault", async () => { const { amounts, crvFraxToken, owner, vault } = ctx() diff --git a/test/vault/liquidator/LiquidatorStreamFeeVault.spec.ts b/test/vault/liquidator/LiquidatorStreamFeeVault.spec.ts index 4e2e097..79fd266 100644 --- a/test/vault/liquidator/LiquidatorStreamFeeVault.spec.ts +++ b/test/vault/liquidator/LiquidatorStreamFeeVault.spec.ts @@ -562,4 +562,4 @@ describe("Streamed Liquidator Fee Vault", async () => { }) }) }) -}) +}) \ No newline at end of file