diff --git a/.solhint.json b/.solhint.json index f6b03012..b057c9f6 100644 --- a/.solhint.json +++ b/.solhint.json @@ -16,6 +16,7 @@ "func-visibility": ["error", { "ignoreConstructors": true }], "private-vars-leading-underscore": "off", "no-empty-blocks": "off", - "not-rely-on-time": "off" + "not-rely-on-time": "off", + "no-console": "off" } } diff --git a/configs/arbitrum/deploy/strategy/IndexArbitrumMarketCap.json b/configs/arbitrum/deploy/strategy/IndexArbitrumMarketCap.json index cb4b1d8b..3315c192 100644 --- a/configs/arbitrum/deploy/strategy/IndexArbitrumMarketCap.json +++ b/configs/arbitrum/deploy/strategy/IndexArbitrumMarketCap.json @@ -36,6 +36,15 @@ } ], "swapRoutes": [ + { + "token": { "$ref": "../../../../constants/arbitrum/addresses/Tokens.json#/usdc" }, + "router": { "$ref": "../../../../constants/arbitrum/addresses/UniswapV3.json#/router" }, + "dex": 6, + "pairData": { + "pair": { "$ref": "../../../../constants/arbitrum/addresses/UniswapV3.json#/wETH_usdc" }, + "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000061fFE014bA17989E743c5F6cB21bF9697530B21e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000002710" + } + }, { "token": { "$ref": "../../../../constants/arbitrum/addresses/Tokens.json#/usdc" }, "router": { "$ref": "../../../../constants/arbitrum/addresses/TraderJoe.json#/router_v2_1" }, @@ -104,17 +113,17 @@ "topLevel": true }, { - "name": "IndexStrategyMint", + "name": "IndexStrategyManagement", "dependencies": ["IndexStrategyUtils"], "topLevel": true }, { - "name": "IndexStrategyBurn", + "name": "IndexStrategyMint", "dependencies": ["IndexStrategyUtils"], "topLevel": true }, { - "name": "IndexStrategyManagement", + "name": "IndexStrategyBurn", "dependencies": ["IndexStrategyUtils"], "topLevel": true } diff --git a/constants/arbitrum/addresses/UniswapV3.json b/constants/arbitrum/addresses/UniswapV3.json new file mode 100644 index 00000000..47808a9e --- /dev/null +++ b/constants/arbitrum/addresses/UniswapV3.json @@ -0,0 +1,5 @@ +{ + "router": "0xE592427A0AEce92De3Edee1F18E0157C05861564", + "quoterV2": "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + "wETH_usdc": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8" +} diff --git a/contracts/index/bases/IndexArbitrum.sol b/contracts/index/bases/IndexArbitrum.sol index 0d3efb72..558c2f0f 100644 --- a/contracts/index/bases/IndexArbitrum.sol +++ b/contracts/index/bases/IndexArbitrum.sol @@ -11,39 +11,6 @@ import { SwapAdapter } from "../libraries/SwapAdapter.sol"; * @dev Contract IndexArbitrum is an extension of IndexStrategyUpgradeable. */ contract IndexArbitrum is IndexStrategyUpgradeable { - /** - * @dev Calculates the equity valuation. - * @param maximize Boolean value to maximize. - * @param includeAmmPrice Boolean value to include AMM price. - * @return The equity valuation as a uint256. - */ - function equityValuation(bool maximize, bool includeAmmPrice) - public - view - override - returns (uint256) - { - uint256 totalSupply = indexToken.totalSupply(); - - if (totalSupply == 0) { - return 0; - } - - uint256 amountWNATIVEUnit = _getAmountWNATIVEFromExactIndex( - Constants.PRECISION - ); - - uint256 priceWNATIVE = oracle.getPrice( - wNATIVE, - maximize, - includeAmmPrice - ); - - return - (amountWNATIVEUnit * priceWNATIVE * totalSupply) / - (Constants.DECIMALS * Constants.PRECISION); - } - /** * @dev Adds a swap route. * @param token The token address. diff --git a/contracts/index/bases/IndexAvalanche.sol b/contracts/index/bases/IndexAvalanche.sol index 6a48ec5b..6cf9f5aa 100644 --- a/contracts/index/bases/IndexAvalanche.sol +++ b/contracts/index/bases/IndexAvalanche.sol @@ -11,39 +11,6 @@ import { SwapAdapter } from "../libraries/SwapAdapter.sol"; * @dev Contract IndexAvalanche is an extension of IndexStrategyUpgradeable. */ contract IndexAvalanche is IndexStrategyUpgradeable { - /** - * @dev Calculates the equity valuation. - * @param maximize Boolean value to maximize. - * @param includeAmmPrice Boolean value to include AMM price. - * @return The equity valuation as a uint256. - */ - function equityValuation(bool maximize, bool includeAmmPrice) - public - view - override - returns (uint256) - { - uint256 totalSupply = indexToken.totalSupply(); - - if (totalSupply == 0) { - return 0; - } - - uint256 amountWNATIVEUnit = _getAmountWNATIVEFromExactIndex( - Constants.PRECISION - ); - - uint256 priceWNATIVE = oracle.getPrice( - wNATIVE, - maximize, - includeAmmPrice - ); - - return - (amountWNATIVEUnit * priceWNATIVE * totalSupply) / - (Constants.DECIMALS * Constants.PRECISION); - } - /** * @dev Adds a swap route. * @param token The token address. diff --git a/contracts/index/bases/IndexStrategyUpgradeable.sol b/contracts/index/bases/IndexStrategyUpgradeable.sol index ffbef828..0574ecfa 100644 --- a/contracts/index/bases/IndexStrategyUpgradeable.sol +++ b/contracts/index/bases/IndexStrategyUpgradeable.sol @@ -88,6 +88,39 @@ abstract contract IndexStrategyUpgradeable is } } + /** + * @dev Calculates the equity valuation. + * @param maximize Boolean value to maximize. + * @param includeAmmPrice Boolean value to include AMM price. + * @return The equity valuation as a uint256. + */ + function equityValuation(bool maximize, bool includeAmmPrice) + public + view + override + returns (uint256) + { + uint256 totalSupply = indexToken.totalSupply(); + + if (totalSupply == 0) { + return 0; + } + + uint256 amountWNATIVEUnit = _getAmountWNATIVEFromExactIndexView( + Constants.PRECISION + ); + + uint256 priceWNATIVE = oracle.getPrice( + wNATIVE, + maximize, + includeAmmPrice + ); + + return + (amountWNATIVEUnit * priceWNATIVE * totalSupply) / + (Constants.DECIMALS * Constants.PRECISION); + } + /** * @dev Initializes the IndexStrategyUpgradeable contract. * @param initParams The parameters needed for initialization. @@ -368,7 +401,6 @@ abstract contract IndexStrategyUpgradeable is */ function getAmountIndexFromToken(address token, uint256 amountTokenMax) external - view onlyWhitelistedToken(token) returns (uint256 amountIndex, uint256 amountToken) { @@ -403,7 +435,6 @@ abstract contract IndexStrategyUpgradeable is */ function getAmountIndexFromNATIVE(uint256 amountNATIVEMax) external - view returns (uint256 amountIndex, uint256 amountNATIVE) { MintingData memory mintingData = IndexStrategyMint @@ -437,7 +468,6 @@ abstract contract IndexStrategyUpgradeable is */ function getAmountTokenFromExactIndex(address token, uint256 amountIndex) external - view onlyWhitelistedToken(token) returns (uint256 amountToken) { @@ -460,7 +490,6 @@ abstract contract IndexStrategyUpgradeable is */ function getAmountNATIVEFromExactIndex(uint256 amountIndex) external - view returns (uint256 amountNATIVE) { amountNATIVE = _getAmountWNATIVEFromExactIndex(amountIndex); @@ -613,18 +642,6 @@ abstract contract IndexStrategyUpgradeable is return whitelistedTokens; } - /** - * @dev Calculates the equity valuation of the index strategy. - * @param maximize A boolean indicating whether to maximize the valuation. - * @param includeAmmPrice A boolean indicating whether to include the AMM price in the valuation. - * @return The equity valuation of the index strategy. - */ - function equityValuation(bool maximize, bool includeAmmPrice) - public - view - virtual - returns (uint256); - /** * @dev Checks if a token is whitelisted. * @param token The address of the token to check. @@ -647,7 +664,6 @@ abstract contract IndexStrategyUpgradeable is */ function _getAmountWNATIVEFromExactIndex(uint256 amountIndex) internal - view returns (uint256 amountWNATIVE) { for (uint256 i = 0; i < components.length; i++) { @@ -671,6 +687,38 @@ abstract contract IndexStrategyUpgradeable is } } + /** + * @dev Calculates the amount of wNATIVE received from the exact index amount. + * @param amountIndex The exact index amount. + * @return amountWNATIVE The amount of wNATIVE received. + */ + function _getAmountWNATIVEFromExactIndexView(uint256 amountIndex) + internal + view + returns (uint256 amountWNATIVE) + { + for (uint256 i = 0; i < components.length; i++) { + if (weights[components[i]] == 0) { + continue; + } + + uint256 amountComponent = (amountIndex * weights[components[i]]) / + Constants.PRECISION; + + (uint256 amountWNATIVEOut, ) = IndexStrategyUtils + .getAmountOutMaxView( + routers[components[i]], + amountComponent, + components[i], + wNATIVE, + dexs, + pairData + ); + + amountWNATIVE += amountWNATIVEOut; + } + } + /** * @dev Sets the weight of a token. * @param token The token address. diff --git a/contracts/index/interfaces/IIndexStrategy.sol b/contracts/index/interfaces/IIndexStrategy.sol index 0e8f382a..90a26266 100644 --- a/contracts/index/interfaces/IIndexStrategy.sol +++ b/contracts/index/interfaces/IIndexStrategy.sol @@ -40,12 +40,10 @@ interface IIndexStrategy { function getAmountIndexFromToken(address token, uint256 amountTokenMax) external - view returns (uint256 amountIndex, uint256 amountToken); function getAmountTokenFromExactIndex(address token, uint256 amountIndex) external - view returns (uint256 amountToken); function setOracle(address oracle) external; diff --git a/contracts/index/libraries/Errors.sol b/contracts/index/libraries/Errors.sol index b7f48737..a12d5d7c 100644 --- a/contracts/index/libraries/Errors.sol +++ b/contracts/index/libraries/Errors.sol @@ -20,6 +20,7 @@ library Errors { // SwapAdapter errors. error SwapAdapter_WrongDEX(uint8 dex); error SwapAdapter_WrongPair(address tokenIn, address tokenOut); + error SwapAdapter_WrongPathLength(uint256 wrongLength); // IndexOracle errors. error Oracle_TokenNotSupported(address token); diff --git a/contracts/index/libraries/IndexStrategyMint.sol b/contracts/index/libraries/IndexStrategyMint.sol index a403e6eb..c935f7e1 100644 --- a/contracts/index/libraries/IndexStrategyMint.sol +++ b/contracts/index/libraries/IndexStrategyMint.sol @@ -192,7 +192,6 @@ library IndexStrategyMint { mapping(address => address[]) storage routers ) public - view returns ( uint256 amountToken, address bestRouter, @@ -285,7 +284,7 @@ library IndexStrategyMint { storage pairData, mapping(address => SwapAdapter.DEX) storage dexs, mapping(address => uint256) storage weights - ) public view returns (MintingData memory mintingData) { + ) public returns (MintingData memory mintingData) { MintingData memory mintingDataUnit = getMintingDataForExactIndex( Constants.PRECISION, dexs, @@ -358,7 +357,7 @@ library IndexStrategyMint { address[] memory components, mapping(address => address[]) storage routers, address wNATIVE - ) internal view returns (MintingData memory mintingData) { + ) internal returns (MintingData memory mintingData) { mintingData.amountIndex = amountIndex; mintingData.amountWNATIVEs = new uint256[](components.length); mintingData.bestRouters = new address[](components.length); diff --git a/contracts/index/libraries/IndexStrategyUtils.sol b/contracts/index/libraries/IndexStrategyUtils.sol index 9bed7668..2366a132 100644 --- a/contracts/index/libraries/IndexStrategyUtils.sol +++ b/contracts/index/libraries/IndexStrategyUtils.sol @@ -25,7 +25,7 @@ library IndexStrategyUtils { mapping(address => SwapAdapter.DEX) storage dexs, mapping(address => mapping(address => mapping(address => SwapAdapter.PairData))) storage pairData - ) external view returns (uint256 amountOutMax, address bestRouter) { + ) external returns (uint256 amountOutMax, address bestRouter) { if (tokenIn == tokenOut) { return (amountIn, address(0)); } @@ -54,6 +54,56 @@ library IndexStrategyUtils { } } + /** + * @dev Calculates the maximum amount of `tokenOut` tokens that can be received for a given `amountIn` of `tokenIn` tokens, + * and identifies the best router to use for the swap among a list of routers. + * @param routers The list of router addresses to consider for the swap. + * @param amountIn The amount of `tokenIn` tokens. + * @param tokenIn The address of the token to be swapped. + * @param tokenOut The address of the token to receive. + * @return amountOutMax The maximum amount of `tokenOut` tokens that can be received for the given `amountIn`. + * @return bestRouter The address of the best router to use for the swap. + */ + function getAmountOutMaxView( + address[] memory routers, + uint256 amountIn, + address tokenIn, + address tokenOut, + mapping(address => SwapAdapter.DEX) storage dexs, + mapping(address => mapping(address => mapping(address => SwapAdapter.PairData))) + storage pairData + ) external view returns (uint256 amountOutMax, address bestRouter) { + if (tokenIn == tokenOut) { + return (amountIn, address(0)); + } + + if (routers.length == 0) { + revert Errors.Index_WrongPair(tokenIn, tokenOut); + } + + amountOutMax = type(uint256).min; + + for (uint256 i = 0; i < routers.length; i++) { + address router = routers[i]; + + // UniswapV3 estimation functions are not view, so skipping them + if (dexs[router] == SwapAdapter.DEX.UniswapV3) continue; + + uint256 amountOut = SwapAdapter + .Setup( + dexs[router], + router, + pairData[router][tokenIn][tokenOut] + ) + .getAmountOutView(amountIn, tokenIn, tokenOut); + + if (amountOut > amountOutMax) { + amountOutMax = amountOut; + bestRouter = router; + } + } + } + /** * @dev Calculates the minimum amount of `tokenIn` tokens required to receive a given `amountOut` of `tokenOut` tokens, * and identifies the best router to use for the swap among a list of routers. @@ -72,7 +122,7 @@ library IndexStrategyUtils { mapping(address => SwapAdapter.DEX) storage dexs, mapping(address => mapping(address => mapping(address => SwapAdapter.PairData))) storage pairData - ) external view returns (uint256 amountInMin, address bestRouter) { + ) external returns (uint256 amountInMin, address bestRouter) { if (tokenIn == tokenOut) { return (amountOut, address(0)); } diff --git a/contracts/index/libraries/SwapAdapter.sol b/contracts/index/libraries/SwapAdapter.sol index 63847648..a36853ac 100644 --- a/contracts/index/libraries/SwapAdapter.sol +++ b/contracts/index/libraries/SwapAdapter.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; +import { Errors } from "./Errors.sol"; + import { ICamelotPair } from "../dependencies/ICamelotPair.sol"; import { ICamelotRouter } from "../dependencies/ICamelotRouter.sol"; import { IChronosFactory } from "../dependencies/IChronosFactory.sol"; @@ -17,8 +19,16 @@ import { ChronosLibrary } from "./ChronosLibrary.sol"; import { TraderJoeV2Library } from "./TraderJoeV2Library.sol"; import { TraderJoeV2Point1Library } from "./TraderJoeV2Point1Library.sol"; import { UniswapV2Library } from "./UniswapV2Library.sol"; +import { IQuoterV2 } from "@uniswap/v3-periphery/contracts/interfaces/IQuoterV2.sol"; +import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC20Upgradeable.sol"; -import { Errors } from "./Errors.sol"; +import "hardhat/console.sol"; + +struct UniswapV3PairData { + uint24[] fees; + IQuoterV2 quoter; +} library SwapAdapter { using CamelotLibrary for ICamelotRouter; @@ -33,7 +43,8 @@ library SwapAdapter { TraderJoeV2, Camelot, Chronos, - TraderJoeV2_1 + TraderJoeV2_1, + UniswapV3 } struct PairData { @@ -110,6 +121,33 @@ library SwapAdapter { ); } + if (setup.dex == DEX.UniswapV3) { + if (path.length != 2) { + revert Errors.SwapAdapter_WrongPathLength(path.length); + } + + UniswapV3PairData memory uniswapV3PairData = abi.decode( + setup.pairData.data, + (UniswapV3PairData) + ); + + IERC20Upgradeable(path[0]).approve(address(setup.router), amountIn); + + return + ISwapRouter(setup.router).exactInputSingle( + ISwapRouter.ExactInputSingleParams( + path[0], + path[1], + uniswapV3PairData.fees[0], + address(this), + block.timestamp, + amountIn, + amountOutMin, + 0 + ) + ); + } + revert Errors.SwapAdapter_WrongDEX(uint8(setup.dex)); } @@ -176,15 +214,45 @@ library SwapAdapter { ); } + if (setup.dex == DEX.UniswapV3) { + if (path.length != 2) { + revert Errors.SwapAdapter_WrongPathLength(path.length); + } + + UniswapV3PairData memory uniswapV3PairData = abi.decode( + setup.pairData.data, + (UniswapV3PairData) + ); + + IERC20Upgradeable(path[0]).approve( + address(setup.router), + amountInMax + ); + + return + ISwapRouter(setup.router).exactOutputSingle( + ISwapRouter.ExactOutputSingleParams( + path[0], + path[1], + uniswapV3PairData.fees[0], + address(this), + block.timestamp, + amountOut, + amountInMax, + 0 + ) + ); + } + revert Errors.SwapAdapter_WrongDEX(uint8(setup.dex)); } - function getAmountOut( + function getAmountOutView( Setup memory setup, uint256 amountIn, address tokenIn, address tokenOut - ) external view returns (uint256 amountOut) { + ) public view returns (uint256 amountOut) { if (tokenIn == tokenOut) { return amountIn; } @@ -240,12 +308,44 @@ library SwapAdapter { revert Errors.SwapAdapter_WrongDEX(uint8(setup.dex)); } + function getAmountOut( + Setup memory setup, + uint256 amountIn, + address tokenIn, + address tokenOut + ) external returns (uint256 amountOut) { + if (tokenIn == tokenOut) { + return amountIn; + } + + if (setup.dex == DEX.UniswapV3) { + UniswapV3PairData memory uniswapV3PairData = abi.decode( + setup.pairData.data, + (UniswapV3PairData) + ); + + (amountOut, , , ) = IQuoterV2(uniswapV3PairData.quoter) + .quoteExactInputSingle( + IQuoterV2.QuoteExactInputSingleParams( + tokenIn, + tokenOut, + amountIn, + uniswapV3PairData.fees[0], + 0 + ) + ); + return amountOut; + } + + return getAmountOutView(setup, amountIn, tokenIn, tokenOut); + } + function getAmountIn( Setup memory setup, uint256 amountOut, address tokenIn, address tokenOut - ) external view returns (uint256 amountIn) { + ) external returns (uint256 amountIn) { if (tokenIn == tokenOut) { return amountOut; } @@ -301,6 +401,25 @@ library SwapAdapter { ); } + if (setup.dex == DEX.UniswapV3) { + UniswapV3PairData memory uniswapV3PairData = abi.decode( + setup.pairData.data, + (UniswapV3PairData) + ); + + (amountIn, , , ) = IQuoterV2(uniswapV3PairData.quoter) + .quoteExactOutputSingle( + IQuoterV2.QuoteExactOutputSingleParams( + tokenIn, + tokenOut, + amountOut, + uniswapV3PairData.fees[0], + 0 + ) + ); + return amountIn; + } + revert Errors.SwapAdapter_WrongDEX(uint8(setup.dex)); } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 5a949b28..e01ddbd7 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -2,7 +2,7 @@ import "@mangrovedao/hardhat-test-solidity" import "@nomicfoundation/hardhat-chai-matchers" import "@nomicfoundation/hardhat-network-helpers" import "@nomiclabs/hardhat-ethers" -import "@nomiclabs/hardhat-etherscan" +import "@nomicfoundation/hardhat-verify" import "@openzeppelin/hardhat-defender" import "@openzeppelin/hardhat-upgrades" import "@typechain/hardhat" diff --git a/package.json b/package.json index 1e685514..71ba6199 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "@mangrovedao/hardhat-test-solidity": "^0.0.17", "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", "@nomicfoundation/hardhat-network-helpers": "^1.0.4", - "@nomiclabs/hardhat-ethers": "^2.1.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@nomiclabs/hardhat-ethers": "^2.1.0", + "@nomicfoundation/hardhat-verify": "1.1.1", "@nomiclabs/hardhat-solpp": "^2.0.1", "@openzeppelin/contracts": "^4.6.0", "@openzeppelin/contracts-upgradeable": "^4.6.0", @@ -53,7 +54,7 @@ "pinst": "^3.0.0", "prettier": "^2.3.2", "prettier-plugin-solidity": "^1.0.0-beta.13", - "solhint": "^3.4.1", + "solhint": "^3.6.2", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.8.2", "ts-node": "^10.1.0", diff --git a/scripts/contracts/execution/deploy.ts b/scripts/contracts/execution/deploy.ts index f8efc760..e52fcaf8 100644 --- a/scripts/contracts/execution/deploy.ts +++ b/scripts/contracts/execution/deploy.ts @@ -5,7 +5,7 @@ import { getLiveConfigPath } from "../../files/paths" import { DeployConfig, LiveConfig } from "../../interfaces/configs" import { Investable } from "../../interfaces/investable" import { DeployOptions } from "../../interfaces/options" -import { defaultAffiliatorAddress } from "../../../test/helper/constants.ts" +import { defaultAffiliatorAddress } from "../../../test/helper/constants" import { IndexArgs, IndexExtraArgs, @@ -362,7 +362,7 @@ async function investOneDollarToIndex( if (depositTokenAddr === NativeToken) { const depositAmount = ethers.utils.parseEther("2", 18) - const [amountIndex] = await strategy.connect(deployer).getAmountIndexFromNATIVE(depositAmount) + const [amountIndex] = await strategy.callStatic.getAmountIndexFromNATIVE(depositAmount) const amountIndexWithSlippage = amountIndex.mul(995).div(1000) await strategy @@ -381,7 +381,7 @@ async function investOneDollarToIndex( DepositTokenAmounts.get(investable.network)!.get(depositTokenAddr)!, depositTokenDecimals ) - const [amountIndex] = await strategy.connect(deployer).getAmountIndexFromToken(depositTokenAddr, depositAmount) + const [amountIndex] = await strategy.callStatic.getAmountIndexFromToken(depositTokenAddr, depositAmount) const amountIndexWithSlippage = amountIndex.mul(995).div(1000) await depositToken.connect(deployer).approve(strategy.address, depositAmount) @@ -411,13 +411,13 @@ async function investOneDollarToIndex( const withdrawAmount = indexTokenBalance.div(2) if (depositTokenAddr === NativeToken) { - const amountNative = await strategy.connect(deployer).getAmountNATIVEFromExactIndex(withdrawAmount) + const amountNative = await strategy.callStatic.getAmountNATIVEFromExactIndex(withdrawAmount) const amountNativeMin = amountNative.mul(BigNumber.from(1e2).sub(1)).div(1e2) await indexToken.connect(deployer).approve(strategy.address, withdrawAmount) await strategy.connect(deployer).burnExactIndexForNATIVE(amountNativeMin, withdrawAmount, deployer.address) } else { - const amountToken = await strategy.connect(deployer).getAmountTokenFromExactIndex(depositTokenAddr, withdrawAmount) + const amountToken = await strategy.callStatic.getAmountTokenFromExactIndex(depositTokenAddr, withdrawAmount) const amountTokenMin = amountToken.mul(BigNumber.from(1e2).sub(1)).div(1e2) await indexToken.connect(deployer).approve(strategy.address, withdrawAmount) diff --git a/test/index/StrategyLimit.test.ts b/test/index/StrategyLimit.test.ts index e56507de..c1a76cdf 100644 --- a/test/index/StrategyLimit.test.ts +++ b/test/index/StrategyLimit.test.ts @@ -21,11 +21,15 @@ export function testStrategyLimit() { // Deposit large enough amount so that equity valuation increment exceed equity valuation limit. const _depositAmount = exceedingAmount - const [_amountIndex] = await this.strategy - .connect(this.whale) - .getAmountIndexFromToken(this.depositTokenAddress, _depositAmount) - - const amountToken = await this.strategy.getAmountTokenFromExactIndex(this.depositTokenAddress, _amountIndex) + const [_amountIndex] = await this.strategy.callStatic.getAmountIndexFromToken( + this.depositTokenAddress, + _depositAmount + ) + + const amountToken = await this.strategy.callStatic.getAmountTokenFromExactIndex( + this.depositTokenAddress, + _amountIndex + ) // TODO: This only holds when the price of depositToken equals to 1 USD. if (amountToken.div(1e6) >= equityValuationLimit) { diff --git a/test/index/StrategyWithdraw.test.ts b/test/index/StrategyWithdraw.test.ts index 5895dc6c..f39d0a38 100644 --- a/test/index/StrategyWithdraw.test.ts +++ b/test/index/StrategyWithdraw.test.ts @@ -269,7 +269,7 @@ export function testStrategyWithdraw() { const indexTokenBalance = await this.indexToken.balanceOf(this.user0.address) if (this.depositTokenAddress === NativeToken) { - const amountNative = await this.strategy.connect(this.user0).getAmountNATIVEFromExactIndex(indexTokenBalance) + const amountNative = await this.strategy.callStatic.getAmountNATIVEFromExactIndex(indexTokenBalance) await this.indexToken.connect(this.user0).approve(this.strategy.address, indexTokenBalance) await expect( @@ -278,9 +278,10 @@ export function testStrategyWithdraw() { .burnExactIndexForNATIVE(amountNative.add(1), indexTokenBalance, this.user0.address) ).to.be.reverted } else { - const amountToken = await this.strategy - .connect(this.user0) - .getAmountTokenFromExactIndex(this.depositTokenAddress, indexTokenBalance) + const amountToken = await this.strategy.callStatic.getAmountTokenFromExactIndex( + this.depositTokenAddress, + indexTokenBalance + ) await this.indexToken.connect(this.user0).approve(this.strategy.address, indexTokenBalance) diff --git a/test/index/helper/InvestHelper.ts b/test/index/helper/InvestHelper.ts index e1165c65..9edd8deb 100644 --- a/test/index/helper/InvestHelper.ts +++ b/test/index/helper/InvestHelper.ts @@ -18,7 +18,7 @@ export async function mint( let amountIndex: BigNumber if (token === undefined) { - ;[amountIndex] = await indexStrategy.connect(spender).getAmountIndexFromNATIVE(tokenAmount) + ;[amountIndex] = await indexStrategy.callStatic.getAmountIndexFromNATIVE(tokenAmount) if (reverted) { await expect( @@ -34,7 +34,7 @@ export async function mint( ).to.emit(indexStrategy, "Mint") } } else { - ;[amountIndex] = await indexStrategy.connect(spender).getAmountIndexFromToken(token.address, tokenAmount) + ;[amountIndex] = await indexStrategy.callStatic.getAmountIndexFromToken(token.address, tokenAmount) await token.connect(spender).approve(indexStrategy.address, tokenAmount) @@ -75,7 +75,7 @@ export async function burn( if (token === undefined) { const nativeBalanceBefore = await ethers.provider.getBalance(recipient.address) - const amountNative = await indexStrategy.connect(spender).getAmountNATIVEFromExactIndex(indexAmount) + const amountNative = await indexStrategy.callStatic.getAmountNATIVEFromExactIndex(indexAmount) const amountNativeMin = amountNative.mul(BigNumber.from(1e2).sub(slippageTolerance)).div(1e2) await indexToken.connect(spender).approve(indexStrategy.address, indexAmount) @@ -98,7 +98,7 @@ export async function burn( } else { const tokenBalanceBefore = await token.balanceOf(recipient.address) - const amountToken = await indexStrategy.connect(spender).getAmountTokenFromExactIndex(token.address, indexAmount) + const amountToken = await indexStrategy.callStatic.getAmountTokenFromExactIndex(token.address, indexAmount) const amountTokenMin = amountToken.mul(BigNumber.from(1e2).sub(slippageTolerance)).div(1e2) await indexToken.connect(spender).approve(indexStrategy.address, indexAmount) diff --git a/yarn.lock b/yarn.lock index 464d6001..0b606424 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1123,6 +1123,21 @@ dependencies: ethereumjs-util "^7.1.4" +"@nomicfoundation/hardhat-verify@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-1.1.1.tgz#6a433d777ce0172d1f0edf7f2d3e1df14b3ecfc1" + integrity sha512-9QsTYD7pcZaQFEA3tBb/D/oCStYDiEVDN7Dxeo/4SCyHRSm86APypxxdOMEPlGmXsAvd+p1j/dTODcpxb8aztA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + chalk "^2.4.2" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" @@ -3001,9 +3016,9 @@ cbor@^5.0.2, cbor@^5.1.0: bignumber.js "^9.0.1" nofilter "^1.0.4" -cbor@^8.0.0: +cbor@^8.0.0, cbor@^8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== dependencies: nofilter "^3.1.0" @@ -6355,6 +6370,11 @@ lodash-es@^4.2.1: resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" @@ -8415,6 +8435,13 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" +semver@^7.5.2: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -8620,10 +8647,10 @@ solhint-plugin-prettier@^0.0.5: dependencies: prettier-linter-helpers "^1.0.0" -solhint@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.4.1.tgz#8ea15b21c13d1be0b53fd46d605a24d0b36a0c46" - integrity sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg== +solhint@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" + integrity sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== dependencies: "@solidity-parser/parser" "^0.16.0" ajv "^6.12.6" @@ -8638,7 +8665,7 @@ solhint@^3.4.1: js-yaml "^4.1.0" lodash "^4.17.21" pluralize "^8.0.0" - semver "^6.3.0" + semver "^7.5.2" strip-ansi "^6.0.1" table "^6.8.1" text-table "^0.2.0"