diff --git a/Makefile b/Makefile index eb039b607..e73772b85 100644 --- a/Makefile +++ b/Makefile @@ -464,6 +464,10 @@ zksync-bytecode-hashes: redeploy-market: make SCRIPT_PATH=./scripts/dev/15.redeploy-market.ts run +.PHONY: fix-shortfalls +fix-shortfalls: + make SCRIPT_PATH=./scripts/dev/16.fix-shortfalls.ts run + .PHONY: transfer-tokens transfer-tokens: make SCRIPT_PATH=./scripts/dev/2.transfer-tokens.ts run diff --git a/contracts/interfaces/IPoolParameters.sol b/contracts/interfaces/IPoolParameters.sol index aa8691ee3..0745ed144 100644 --- a/contracts/interfaces/IPoolParameters.sol +++ b/contracts/interfaces/IPoolParameters.sol @@ -102,6 +102,17 @@ interface IPoolParameters { **/ function mintToTreasury(address[] calldata assets) external; + /** + * @notice Fix shortfalls by sending reserves to xTokens + * @param assets The list of reserves for which the minting needs to be executed + **/ + function fixShortfalls( + address[] calldata assets, + address[] calldata shortfallUsers, + address[] calldata shortfallAssets, + uint256[] calldata shortfallAmounts + ) external; + /** * @notice Rescue and transfer tokens locked in this contract * @param assetType The asset type of the token diff --git a/contracts/interfaces/IWstETH.sol b/contracts/interfaces/IWstETH.sol new file mode 100644 index 000000000..ae08f9ed5 --- /dev/null +++ b/contracts/interfaces/IWstETH.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.0; + +interface IWstETH { + function wrap(uint256 _stETHAmount) external returns (uint256); + + function unwrap(uint256 _wstETHAmount) external returns (uint256); +} diff --git a/contracts/protocol/libraries/logic/SupplyLogic.sol b/contracts/protocol/libraries/logic/SupplyLogic.sol index 50d7f1c52..447cdb1a6 100644 --- a/contracts/protocol/libraries/logic/SupplyLogic.sol +++ b/contracts/protocol/libraries/logic/SupplyLogic.sol @@ -318,7 +318,7 @@ library SupplyLogic { reserve.updateState(reserveCache); uint256 userBalance = IPToken(reserveCache.xTokenAddress) - .scaledBalanceOf(msg.sender) + .scaledBalanceOf(params.from) .rayMul(reserveCache.nextLiquidityIndex); uint256 amountToWithdraw = params.amount; @@ -340,8 +340,9 @@ library SupplyLogic { amountToWithdraw ); - DataTypes.TimeLockParams memory timeLockParams = GenericLogic - .calculateTimeLockParams( + DataTypes.TimeLockParams memory timeLockParams; + if (!params.immediate) { + timeLockParams = GenericLogic.calculateTimeLockParams( reserve, DataTypes.TimeLockFactorParams({ assetType: DataTypes.AssetType.ERC20, @@ -349,10 +350,11 @@ library SupplyLogic { amount: amountToWithdraw }) ); - timeLockParams.actionType = DataTypes.TimeLockActionType.WITHDRAW; + timeLockParams.actionType = DataTypes.TimeLockActionType.WITHDRAW; + } IPToken(reserveCache.xTokenAddress).burn( - msg.sender, + params.from, params.to, amountToWithdraw, reserveCache.nextLiquidityIndex, @@ -366,7 +368,7 @@ library SupplyLogic { reservesList, userConfig, params.asset, - msg.sender, + params.from, params.reservesCount, params.oracle ); @@ -374,11 +376,11 @@ library SupplyLogic { if (amountToWithdraw == userBalance) { userConfig.setUsingAsCollateral(reserve.id, false); - emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender); + emit ReserveUsedAsCollateralDisabled(params.asset, params.from); } } - emit Withdraw(params.asset, msg.sender, params.to, amountToWithdraw); + emit Withdraw(params.asset, params.from, params.to, amountToWithdraw); return amountToWithdraw; } diff --git a/contracts/protocol/libraries/types/DataTypes.sol b/contracts/protocol/libraries/types/DataTypes.sol index 0da8daba0..7514d1879 100644 --- a/contracts/protocol/libraries/types/DataTypes.sol +++ b/contracts/protocol/libraries/types/DataTypes.sol @@ -183,9 +183,11 @@ library DataTypes { struct ExecuteWithdrawParams { address asset; uint256 amount; + address from; address to; uint256 reservesCount; address oracle; + bool immediate; } struct ExecuteWithdrawERC721Params { diff --git a/contracts/protocol/pool/PoolCore.sol b/contracts/protocol/pool/PoolCore.sol index c664e09ab..a42d18788 100644 --- a/contracts/protocol/pool/PoolCore.sol +++ b/contracts/protocol/pool/PoolCore.sol @@ -206,9 +206,11 @@ contract PoolCore is DataTypes.ExecuteWithdrawParams({ asset: asset, amount: amount, + from: msg.sender, to: to, reservesCount: ps._reservesCount, - oracle: ADDRESSES_PROVIDER.getPriceOracle() + oracle: ADDRESSES_PROVIDER.getPriceOracle(), + immediate: false }) ); } diff --git a/contracts/protocol/pool/PoolParameters.sol b/contracts/protocol/pool/PoolParameters.sol index 4a8d53cbd..6dc9bb28e 100644 --- a/contracts/protocol/pool/PoolParameters.sol +++ b/contracts/protocol/pool/PoolParameters.sol @@ -12,22 +12,32 @@ import {BorrowLogic} from "../libraries/logic/BorrowLogic.sol"; import {LiquidationLogic} from "../libraries/logic/LiquidationLogic.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; import {IERC20WithPermit} from "../../interfaces/IERC20WithPermit.sol"; +import {IERC20Detailed} from "../../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; import {IPoolParameters} from "../../interfaces/IPoolParameters.sol"; +import {IAutoCompoundApe} from "../../interfaces/IAutoCompoundApe.sol"; +import {IWstETH} from "../../interfaces/IWstETH.sol"; import {INToken} from "../../interfaces/INToken.sol"; import {IACLManager} from "../../interfaces/IACLManager.sol"; +import {ISwapRouter} from "../../dependencies/uniswapv3-periphery/interfaces/ISwapRouter.sol"; +import {IPriceOracleGetter} from "../../interfaces/IPriceOracleGetter.sol"; import {PoolStorage} from "./PoolStorage.sol"; import {FlashClaimLogic} from "../libraries/logic/FlashClaimLogic.sol"; import {Address} from "../../dependencies/openzeppelin/contracts/Address.sol"; import {SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; import {IERC721Receiver} from "../../dependencies/openzeppelin/contracts/IERC721Receiver.sol"; import {IMarketplace} from "../../interfaces/IMarketplace.sol"; +import {PercentageMath} from "../libraries/math/PercentageMath.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {ParaReentrancyGuard} from "../libraries/paraspace-upgradeability/ParaReentrancyGuard.sol"; import {IAuctionableERC721} from "../../interfaces/IAuctionableERC721.sol"; import {IReserveAuctionStrategy} from "../../interfaces/IReserveAuctionStrategy.sol"; import {PercentageMath} from "../libraries/math/PercentageMath.sol"; import "../../dependencies/openzeppelin/contracts/IERC20.sol"; +import {IPToken} from "../../interfaces/IPToken.sol"; +import {IVariableDebtToken} from "../../interfaces/IVariableDebtToken.sol"; +import {ReserveConfiguration} from "../libraries/configuration/ReserveConfiguration.sol"; +import {WadRayMath} from "../libraries/math/WadRayMath.sol"; /** * @title Pool Parameters contract @@ -47,6 +57,9 @@ contract PoolParameters is IPoolParameters { using ReserveLogic for DataTypes.ReserveData; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using WadRayMath for uint256; + using PercentageMath for uint256; IPoolAddressesProvider internal immutable ADDRESSES_PROVIDER; uint256 internal constant POOL_REVISION = 200; @@ -54,6 +67,65 @@ contract PoolParameters is uint256 internal constant MIN_AUCTION_HEALTH_FACTOR = 1e18; using SafeERC20 for IERC20; + address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address internal constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; + address internal constant APE = 0x4d224452801ACEd8B2F0aebE155379bb5D594381; + address internal constant cAPE = 0xC5c9fB6223A989208Df27dCEE33fC59ff5c26fFF; + address internal constant stETH = + 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; + address internal constant wstETH = + 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + address internal constant BLUR = 0x5283D291DBCF85356A21bA090E6db59121208b44; + address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + + // treasury + // USDC 36332.400416844017842702 + // USDT 25589.910495216331539289 + // WETH 58.789391688101992366 + // APE 7037.045327108643146337 + // DAI 282.197432234440448224 + // cAPE 19559.598786628743644699 + // stETH 5.411339509592198291 + // BLUR 2327.337115360498087797 + // WBTC 0.021642026967485478 + + // shortfalls + // -- 0xbc737139dd8c8d192f4b9aa713ad99036f004007 17 ETH. 28288.1 + // -- 0xa5683dda11c1f1f0143471e0741b5be6d4cb9323 12 ETH 19781 + // -- 0x650915fcd9f4d7c186affba606ca5bae1d05f4a5 11.6 ETH 19189.7 + // -- 0x70a93e4d958bf023bf1e2cb7efcfc935e5b2c29d 11.3 ETH 18596 + // -- 0xe541529b40f00a081fcea9be3e3dc00919e6ce1a 10.6 ETH 17505.5 + // -- 0x7f08a7924d7f09d603cdefa061c3e8914147ead7 8.76 ETH 14420.5 + // -- 0x9caa3c46a0635a1eb79033a22aaa72c82fba9cfe 7.4 ETH 12308.3 + // -- 0x82bbcac5a8b81368a4a96f0265cb40e46020a1e1 2.54 ETH 4176.8 + // -- 0xa38232df0d62f6a36d7761680c9e2106d049bd3d 2.43 ETH 4007.6 + // -- 0xb9a292ca3856b64d1b69503e7a8f78bb03cdc4e5 1.45 ETH 2382.9 + // -- 0x5f27e1a81965c8a91f7ec287f0a62067c173045d 18693 USDT 18686.5 + // -- 0xefbd0604d91919dda0a3d64a50e0659de93d417c 303 USDC 301.9 + // -- 0x10cda82ea4cd56d32c5a5e6dfcaa7af51d2ba350 0.82 WBTC 21223.6 + // -- 0x0981f0e2b61575ff55074c76a539108bdc354148 0.6 WBTC 15892.3 + // + // 85.08 ETH + // 1.42 WBTC + // 18693 USDT + // 303 USDC + uint256 internal constant USDC_SHORTFALL = 303100000; + uint256 internal constant USDT_SHORTFALL = 18693100000; + uint256 internal constant WBTC_SHORTFALL = 142100000; + uint256 internal constant WETH_SHORTFALL = 85081000000000000000; + uint256 internal constant DEFAULT_MAX_SLIPPAGE = 500; // 5% + uint24 internal constant USDC_WETH_FEE = 500; + uint24 internal constant WETH_WBTC_FEE = 500; + uint24 internal constant USDT_USDC_FEE = 100; + uint24 internal constant APE_WETH_FEE = 3000; + uint24 internal constant DAI_WETH_FEE = 500; + uint24 internal constant BLUR_WETH_FEE = 3000; + uint24 internal constant WSTETH_WETH_FEE = 100; + ISwapRouter internal constant SWAP_ROUTER = + ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); + /** * @dev Only pool configurator can call functions marked by this modifier. **/ @@ -107,6 +179,246 @@ contract PoolParameters is PoolLogic.executeMintToTreasury(ps._reserves, assets); } + /// @inheritdoc IPoolParameters + function fixShortfalls( + address[] calldata assets, + address[] calldata shortfallUsers, + address[] calldata shortfallAssets, + uint256[] calldata shortfallAmounts + ) external virtual override nonReentrant onlyPoolAdmin { + require( + shortfallUsers.length == shortfallAssets.length && + shortfallAssets.length == shortfallAmounts.length, + "invalid params" + ); + DataTypes.PoolStorage storage ps = poolStorage(); + + for (uint256 i = 0; i < assets.length; i++) { + address assetAddress = assets[i]; + + DataTypes.ReserveData storage reserve = ps._reserves[assetAddress]; + + DataTypes.ReserveConfigurationMap + memory reserveConfiguration = reserve.configuration; + + // this cover both inactive reserves and invalid reserves since the flag will be 0 for both + if ( + !reserveConfiguration.getActive() || + reserveConfiguration.getAssetType() != DataTypes.AssetType.ERC20 + ) { + continue; + } + + uint256 accruedToTreasury = reserve.accruedToTreasury; + + if (accruedToTreasury != 0) { + reserve.accruedToTreasury = 0; + uint256 normalizedIncome = reserve.getNormalizedIncome(); + uint256 amountToMint = accruedToTreasury.rayMul( + normalizedIncome + ); + IPToken(reserve.xTokenAddress).mint( + address(this), + address(this), + amountToMint, + normalizedIncome + ); + SupplyLogic.executeWithdraw( + ps._reserves, + ps._reservesList, + ps._usersConfig[address(this)], + DataTypes.ExecuteWithdrawParams({ + asset: assetAddress, + amount: amountToMint, + from: address(this), + to: address(this), + reservesCount: ps._reservesCount, + oracle: ADDRESSES_PROVIDER.getPriceOracle(), + immediate: true + }) + ); + + if (assetAddress == cAPE) { + IAutoCompoundApe(assetAddress).withdraw(amountToMint); + assetAddress = APE; + amountToMint = IERC20(assetAddress).balanceOf( + address(this) + ); + } + if (assetAddress == stETH) { + if ( + IERC20(assetAddress).allowance(address(this), wstETH) == + 0 + ) { + IERC20(assetAddress).safeApprove( + wstETH, + type(uint256).max + ); + } + amountToMint = IWstETH(wstETH).wrap(amountToMint); + assetAddress = wstETH; + } + + if ( + IERC20(assetAddress).allowance( + address(this), + address(SWAP_ROUTER) + ) == 0 + ) { + IERC20(assetAddress).safeApprove( + address(SWAP_ROUTER), + type(uint256).max + ); + } + + if (assetAddress == USDC) { + _swap( + amountToMint - USDC_SHORTFALL, + _getSwapPath(USDC, WBTC), + ps._reserves[WBTC].xTokenAddress, + _getRelativePrice(USDC, WBTC) + ); + IERC20(USDC).safeTransfer( + ps._reserves[USDC].xTokenAddress, + USDC_SHORTFALL + ); + } else if (assetAddress == USDT) { + _swap( + amountToMint - USDT_SHORTFALL, + _getSwapPath(USDT, WETH), + ps._reserves[WETH].xTokenAddress, + _getRelativePrice(USDT, WETH) + ); + IERC20(USDT).safeTransfer( + ps._reserves[USDT].xTokenAddress, + USDT_SHORTFALL + ); + } else if (assetAddress == WBTC || assetAddress == WETH) { + IERC20(assetAddress).safeTransfer( + ps._reserves[assetAddress].xTokenAddress, + amountToMint + ); + } else { + _swap( + amountToMint, + _getSwapPath(assetAddress, WETH), + ps._reserves[WETH].xTokenAddress, + _getRelativePrice(assetAddress, WETH) + ); + } + } + } + + for (uint256 i = 0; i < shortfallUsers.length; i++) { + DataTypes.ReserveData storage reserve = ps._reserves[ + shortfallAssets[i] + ]; + + DataTypes.ReserveConfigurationMap + memory reserveConfiguration = reserve.configuration; + + // this cover both inactive reserves and invalid reserves since the flag will be 0 for both + if ( + !reserveConfiguration.getActive() || + reserveConfiguration.getAssetType() != DataTypes.AssetType.ERC20 + ) { + continue; + } + + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + reserve.updateState(reserveCache); + IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( + shortfallUsers[i], + shortfallAmounts[i], + reserveCache.nextVariableBorrowIndex + ); + } + } + + function _getRelativePrice( + address tokenIn, + address tokenOut + ) internal view returns (uint256) { + IPriceOracleGetter oracle = IPriceOracleGetter( + ADDRESSES_PROVIDER.getPriceOracle() + ); + uint256 tokenInPrice = oracle.getAssetPrice(tokenIn); + uint256 tokenOutPrice = oracle.getAssetPrice(tokenOut); + + return + ( + (tokenInPrice * (10 ** IERC20Detailed(tokenOut).decimals())) + .wadDiv( + tokenOutPrice * + (10 ** IERC20Detailed(tokenIn).decimals()) + ) + ).percentMul( + PercentageMath.PERCENTAGE_FACTOR - DEFAULT_MAX_SLIPPAGE + ); + } + + function _getSwapPath( + address tokenIn, + address tokenOut + ) internal pure returns (bytes memory) { + // USDC -> WETH -> WBTC + if (tokenIn == USDC && tokenOut == WBTC) { + return + abi.encodePacked( + USDC, + USDC_WETH_FEE, + WETH, + WETH_WBTC_FEE, + WBTC + ); + // USDT -> USDC -> WETH + } else if (tokenIn == USDT && tokenOut == WETH) { + return + abi.encodePacked( + USDT, + USDT_USDC_FEE, + USDC, + USDC_WETH_FEE, + WETH + ); + // APE -> WETH, BLUR -> WETH + } else if ((tokenIn == APE || tokenIn == BLUR) && tokenOut == WETH) { + return abi.encodePacked(tokenIn, APE_WETH_FEE, tokenOut); + // USDC -> WETH, DAI -> WETH + } else if ((tokenIn == USDC || tokenIn == DAI) && tokenOut == WETH) { + return abi.encodePacked(tokenIn, USDC_WETH_FEE, tokenOut); + // WSTETH -> WETH + } else if (tokenIn == wstETH && tokenOut == WETH) { + return abi.encodePacked(tokenIn, WSTETH_WETH_FEE, tokenOut); + } else { + revert("No route available"); + } + } + + function _swap( + uint256 amountIn, + bytes memory swapPath, + address recipient, + uint256 price + ) internal { + if (amountIn == 0) { + return; + } + if (recipient == address(0)) { + revert("zero address"); + } + SWAP_ROUTER.exactInput( + ISwapRouter.ExactInputParams({ + path: swapPath, + recipient: recipient, + deadline: block.timestamp, + amountIn: amountIn, + amountOutMinimum: amountIn.wadMul(price) + }) + ); + } + /// @inheritdoc IPoolParameters function initReserve( address asset, diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 16cb563ae..9f63e3fa9 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -622,11 +622,14 @@ export const deployPoolParameters = async ( verify?: boolean ) => { const poolLogic = await deployPoolLogic(verify); + const supplyLogic = await deploySupplyLogic(verify); const {poolParametersSelectors} = await getPoolSignatures(); const parametersLibraries = { "contracts/protocol/libraries/logic/PoolLogic.sol:PoolLogic": poolLogic.address, + "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic": + supplyLogic.address, }; const poolParameters = (await withSaveAndVerify( diff --git a/market-config/index.ts b/market-config/index.ts index 69bb652ac..9aa777b7c 100644 --- a/market-config/index.ts +++ b/market-config/index.ts @@ -839,7 +839,7 @@ export const LineaConfig: IParaSpaceConfiguration = { export const MainnetConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, - ParaSpaceAdmin: "0x19293FBec52F94165f903708a74513Dd6dFedd0a", + ParaSpaceAdmin: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", EmergencyAdmins: [ "0x17816E9A858b161c3E37016D139cf618056CaCD4", "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", @@ -847,10 +847,10 @@ export const MainnetConfig: IParaSpaceConfiguration = { "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", "0x4AC3fD073786a971e1B8dE5a526959c9B3B2B407", ], - RiskAdmin: "0x19293FBec52F94165f903708a74513Dd6dFedd0a", - GatewayAdmin: "0x19293FBec52F94165f903708a74513Dd6dFedd0a", - ParaSpaceTeam: "0x19293FBec52F94165f903708a74513Dd6dFedd0a", - Treasury: "0x19293FBec52F94165f903708a74513Dd6dFedd0a", + RiskAdmin: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", + GatewayAdmin: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", + ParaSpaceTeam: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", + Treasury: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", Tokens: { WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", stETH: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", @@ -992,7 +992,7 @@ export const MainnetConfig: IParaSpaceConfiguration = { DelegationRegistry: "0x00000000000076A84feF008CDAbe6409d2FE638B", Governance: { Multisend: MULTI_SEND || "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", - Multisig: MULTI_SIG || "0x19293FBec52F94165f903708a74513Dd6dFedd0a", + Multisig: MULTI_SIG || "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", }, ParaSpaceV1: { PoolV1: "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee", diff --git a/scripts/dev/16.fix-shortfalls.ts b/scripts/dev/16.fix-shortfalls.ts new file mode 100644 index 000000000..48e3bc3ec --- /dev/null +++ b/scripts/dev/16.fix-shortfalls.ts @@ -0,0 +1,89 @@ +import rawBRE from "hardhat"; +import {getPoolProxy} from "../../helpers/contracts-getters"; +import {dryRunEncodedData} from "../../helpers/contracts-helpers"; +import {upgradePoolParameters} from "../upgrade/pool"; +import {parseEther, parseUnits} from "ethers/lib/utils"; + +const fixShortfalls = async () => { + console.time("fix-shortfalls"); + await upgradePoolParameters( + "0x64d0680889A1f6cFF8De6632e2C4B93957169E28", + false + ); + const pool = await getPoolProxy(); + const encodedData = pool.interface.encodeFunctionData("fixShortfalls", [ + [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "0x4d224452801ACEd8B2F0aebE155379bb5D594381", + "0xC5c9fB6223A989208Df27dCEE33fC59ff5c26fFF", + "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "0x5283D291DBCF85356A21bA090E6db59121208b44", + "0x6B175474E89094C44Da98b954EedeAC495271d0F", + ], + [ + "0xbc737139dd8c8d192f4b9aa713ad99036f004007", + "0xa5683dda11c1f1f0143471e0741b5be6d4cb9323", + "0x650915fcd9f4d7c186affba606ca5bae1d05f4a5", + "0x70a93e4d958bf023bf1e2cb7efcfc935e5b2c29d", + "0xe541529b40f00a081fcea9be3e3dc00919e6ce1a", + "0x7f08a7924d7f09d603cdefa061c3e8914147ead7", + "0x9caa3c46a0635a1eb79033a22aaa72c82fba9cfe", + "0x82bbcac5a8b81368a4a96f0265cb40e46020a1e1", + "0xa38232df0d62f6a36d7761680c9e2106d049bd3d", + "0xb9a292ca3856b64d1b69503e7a8f78bb03cdc4e5", + "0x5f27e1a81965c8a91f7ec287f0a62067c173045d", + "0xefbd0604d91919dda0a3d64a50e0659de93d417c", + "0x10cda82ea4cd56d32c5a5e6dfcaa7af51d2ba350", + "0x0981f0e2b61575ff55074c76a539108bdc354148", + ], + [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + ], + [ + parseEther("17"), + parseEther("12"), + parseEther("11.6"), + parseEther("11.3"), + parseEther("10.6"), + parseEther("8.76"), + parseEther("7.4"), + parseEther("2.54"), + parseEther("2.43"), + parseEther("1.45"), + parseUnits("18693", 6), + parseUnits("303", 6), + parseUnits("0.82", 8), + parseUnits("0.6", 8), + ], + ]); + await dryRunEncodedData(pool.address, encodedData); + console.timeEnd("fix-shortfalls"); +}; + +async function main() { + await rawBRE.run("set-DRE"); + await fixShortfalls(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + });