From 242826ded60c7a2cbe5bb0abe704735f7acf5c60 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 18 Mar 2021 15:44:52 +0000 Subject: [PATCH 01/62] ParaSwap adapter for collateral swaps Complete with unit tests (using a mock AugustusSwapper contract). Has similar functionality/tests as for existing Uniswap adapter. Fixed a couple bugs in tests for Uniswap adapters. --- contracts/adapters/BaseParaSwapAdapter.sol | 124 + .../adapters/BaseParaSwapSellAdapter.sol | 92 + .../adapters/ParaSwapLiquiditySwapAdapter.sol | 191 ++ contracts/interfaces/IParaSwapAugustus.sol | 7 + contracts/mocks/swap/MockParaSwapAugustus.sol | 59 + .../swap/MockParaSwapTokenTransferProxy.sol | 17 + helpers/contracts-deployments.ts | 21 + helpers/contracts-getters.ts | 18 + helpers/contracts-helpers.ts | 32 + helpers/types.ts | 2 + package.json | 1 + test/__setup.spec.ts | 6 + test/helpers/make-suite.ts | 6 + test/paraswapAdapters.liquiditySwap.spec.ts | 2332 +++++++++++++++++ test/uniswapAdapters.flashLiquidation.spec.ts | 2 +- test/uniswapAdapters.liquiditySwap.spec.ts | 7 +- test/uniswapAdapters.repay.spec.ts | 2 +- 17 files changed, 2916 insertions(+), 3 deletions(-) create mode 100644 contracts/adapters/BaseParaSwapAdapter.sol create mode 100644 contracts/adapters/BaseParaSwapSellAdapter.sol create mode 100644 contracts/adapters/ParaSwapLiquiditySwapAdapter.sol create mode 100644 contracts/interfaces/IParaSwapAugustus.sol create mode 100644 contracts/mocks/swap/MockParaSwapAugustus.sol create mode 100644 contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol create mode 100644 test/paraswapAdapters.liquiditySwap.spec.ts diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol new file mode 100644 index 00000000..72ce55fd --- /dev/null +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {SafeMath} from '../dependencies/openzeppelin/contracts/SafeMath.sol'; +import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; +import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; +import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; +import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; +import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; +import {DataTypes} from '../protocol/libraries/types/DataTypes.sol'; +import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; +import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol'; +import {FlashLoanReceiverBase} from '../flashloan/base/FlashLoanReceiverBase.sol'; + +/** + * @title BaseParaSwapAdapter + * @notice Utility functions for adapters using ParaSwap + * @author Jason Raymond Bell + */ +abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + struct PermitSignature { + uint256 amount; + uint256 deadline; + uint8 v; + bytes32 r; + bytes32 s; + } + + // Max slippage percent allowed + uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30% + + IPriceOracleGetter public immutable ORACLE; + + event Swapped(address indexed fromAsset, address indexed toAsset, uint256 fromAmount, uint256 receivedAmount); + + constructor( + ILendingPoolAddressesProvider addressesProvider + ) public FlashLoanReceiverBase(addressesProvider) { + ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle()); + } + + /** + * @dev Get the price of the asset from the oracle denominated in eth + * @param asset address + * @return eth price for the asset + */ + function _getPrice(address asset) internal view returns (uint256) { + return ORACLE.getAssetPrice(asset); + } + + /** + * @dev Get the decimals of an asset + * @return number of decimals of the asset + */ + function _getDecimals(address asset) internal view returns (uint256) { + return IERC20Detailed(asset).decimals(); + } + + /** + * @dev Get the aToken associated to the asset + * @return address of the aToken + */ + function _getReserveData(address asset) internal view returns (DataTypes.ReserveData memory) { + return LENDING_POOL.getReserveData(asset); + } + + /** + * @dev Pull the ATokens from the user + * @param reserve address of the asset + * @param reserveAToken address of the aToken of the reserve + * @param user address + * @param amount of tokens to be transferred to the contract + * @param permitSignature struct containing the permit signature + */ + function _pullAToken( + address reserve, + address reserveAToken, + address user, + uint256 amount, + PermitSignature memory permitSignature + ) internal { + if (_usePermit(permitSignature)) { + IERC20WithPermit(reserveAToken).permit( + user, + address(this), + permitSignature.amount, + permitSignature.deadline, + permitSignature.v, + permitSignature.r, + permitSignature.s + ); + } + + // transfer from user to adapter + IERC20(reserveAToken).safeTransferFrom(user, address(this), amount); + + // withdraw reserve + LENDING_POOL.withdraw(reserve, amount, address(this)); + } + + /** + * @dev Tells if the permit method should be called by inspecting if there is a valid signature. + * If signature params are set to 0, then permit won't be called. + * @param signature struct containing the permit signature + * @return whether or not permit should be called + */ + function _usePermit(PermitSignature memory signature) internal pure returns (bool) { + return + !(uint256(signature.deadline) == uint256(signature.v) && uint256(signature.deadline) == 0); + } + + /** + * @dev Emergency rescue for token stucked on this contract, as failsafe mechanism + * - Funds should never remain in this contract more time than during transactions + * - Only callable by the owner + */ + function rescueTokens(IERC20 token) external onlyOwner { + token.transfer(owner(), token.balanceOf(address(this))); + } +} diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol new file mode 100644 index 00000000..909ca2d3 --- /dev/null +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {BaseParaSwapAdapter} from './BaseParaSwapAdapter.sol'; +import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol'; +import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; +import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; +import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; + +/** + * @title BaseParaSwapSellAdapter + * @notice Implements the logic for selling tokens on ParaSwap + * @author Jason Raymond Bell + */ +abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { + using PercentageMath for uint256; + + constructor( + ILendingPoolAddressesProvider addressesProvider + ) public BaseParaSwapAdapter(addressesProvider) { + } + + /** + * @dev Swaps a token for another using ParaSwap + * @param fromAmountOffset Offset of fromAmount in Augustus calldata if it should be overwritten, otherwise 0 + * @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract + * @param augustus Address of ParaSwap's AugustusSwapper contract + * @param assetToSwapFrom Address of the asset to be swapped from + * @param assetToSwapTo Address of the asset to be swapped to + * @param amountToSwap Amount to be swapped + * @param minAmountToReceive Minimum amount to be received from the swap + * @return amountReceived The amount received from the swap + */ + function _sellOnParaSwap( + uint256 fromAmountOffset, + bytes memory swapCalldata, + address augustus, + address assetToSwapFrom, + address assetToSwapTo, + uint256 amountToSwap, + uint256 minAmountToReceive + ) internal returns (uint256 amountReceived) { + { + uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom); + uint256 toAssetDecimals = _getDecimals(assetToSwapTo); + + uint256 fromAssetPrice = _getPrice(assetToSwapFrom); + uint256 toAssetPrice = _getPrice(assetToSwapTo); + + uint256 expectedMinAmountOut = + amountToSwap + .mul(fromAssetPrice.mul(10**toAssetDecimals)) + .div(toAssetPrice.mul(10**fromAssetDecimals)) + .percentMul(PercentageMath.PERCENTAGE_FACTOR - MAX_SLIPPAGE_PERCENT); + + require(expectedMinAmountOut <= minAmountToReceive, 'MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); + } + + uint256 balanceBeforeAssetFrom = IERC20(assetToSwapFrom).balanceOf(address(this)); + require(balanceBeforeAssetFrom >= amountToSwap, 'INSUFFICIENT_BALANCE_BEFORE_SWAP'); + uint256 balanceBeforeAssetTo = IERC20(assetToSwapTo).balanceOf(address(this)); + + address tokenTransferProxy = IParaSwapAugustus(augustus).getTokenTransferProxy(); + IERC20(assetToSwapFrom).safeApprove(tokenTransferProxy, 0); + IERC20(assetToSwapFrom).safeApprove(tokenTransferProxy, amountToSwap); + + if (fromAmountOffset != 0) { + require(fromAmountOffset >= 4 && + fromAmountOffset <= swapCalldata.length.sub(32), + 'FROM_AMOUNT_OFFSET_OUT_OF_RANGE'); + assembly { + mstore(add(swapCalldata, add(fromAmountOffset, 32)), amountToSwap) + } + } + (bool success,) = augustus.call(swapCalldata); + if (!success) { + // Copy revert reason from call + assembly { + let ptr := mload(0x40) + let size := returndatasize() + returndatacopy(ptr, 0, size) + revert(ptr, size) + } + } + require(IERC20(assetToSwapFrom).balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP'); + amountReceived = IERC20(assetToSwapTo).balanceOf(address(this)).sub(balanceBeforeAssetTo); + require(amountReceived >= minAmountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED'); + + emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, amountReceived); + } +} diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol new file mode 100644 index 00000000..4e6ef962 --- /dev/null +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {BaseParaSwapSellAdapter} from './BaseParaSwapSellAdapter.sol'; +import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; +import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; + +/** + * @title ParaSwapLiquiditySwapAdapter + * @notice Adapter to swap liquidity using ParaSwap. + * @author Jason Raymond Bell + */ +contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { + constructor( + ILendingPoolAddressesProvider addressesProvider + ) public BaseParaSwapSellAdapter(addressesProvider) {} + + /** + * @dev Swaps the received reserve amount from the flash loan into the asset specified in the params. + * The received funds from the swap are then deposited into the protocol on behalf of the user. + * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and repay the flash loan. + * @param assets Address of the underlying asset to be swapped from + * @param amounts Amount of the flash loan i.e. maximum amount to swap + * @param premiums Fee of the flash loan + * @param initiator Account that initiated the flash loan + * @param params Additional variadic field to include extra params. Expected parameters: + * address assetToSwapTo Address of the underlying asset to be swapped to and deposited + * uint256 minAmountToReceive Min amount to be received from the swap + * uint256 swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0 + * bytes swapCalldata Calldata for ParaSwap's AugustusSwapper contract + * address augustus Address of ParaSwap's AugustusSwapper contract + * PermitSignature permitParams Struct containing the permit signatures, set to all zeroes if not used + */ + function executeOperation( + address[] calldata assets, + uint256[] calldata amounts, + uint256[] calldata premiums, + address initiator, + bytes calldata params + ) external override returns (bool) { + require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL'); + require(assets.length == 1, 'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED'); + + uint256 flashLoanAmount = amounts[0]; + uint256 premium = premiums[0]; + address initiatorLocal = initiator; + address assetToSwapFrom = assets[0]; + ( + address assetToSwapTo, + uint256 minAmountToReceive, + uint256 swapAllBalanceOffset, + bytes memory swapCalldata, + address augustus, + PermitSignature memory permitParams + ) = abi.decode(params, (address, uint256, uint256, bytes, address, PermitSignature)); + + _swapLiquidity( + swapAllBalanceOffset, + swapCalldata, + augustus, + permitParams, + flashLoanAmount, + premium, + initiatorLocal, + assetToSwapFrom, + assetToSwapTo, + minAmountToReceive + ); + + return true; + } + + /** + * @dev Swaps an amount of an asset to another and deposits the new asset amount on behalf of the user without using a flash loan. + * This method can be used when the temporary transfer of the collateral asset to this contract does not affect the user position. + * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and perform the swap. + * @param assetToSwapFrom Address of the underlying asset to be swapped from + * @param assetToSwapTo Address of the underlying asset to be swapped to and deposited + * @param amountToSwap Amount to be swapped, or maximum amount when swapping all balance + * @param minAmountToReceive Minimum amount to be received from the swap + * @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0 + * @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract + * @param augustus Address of ParaSwap's AugustusSwapper contract + * @param permitParams Struct containing the permit signatures, set to all zeroes if not used + */ + function swapAndDeposit( + address assetToSwapFrom, + address assetToSwapTo, + uint256 amountToSwap, + uint256 minAmountToReceive, + uint256 swapAllBalanceOffset, + bytes calldata swapCalldata, + address augustus, + PermitSignature calldata permitParams + ) external { + address aToken = _getReserveData(assetToSwapFrom).aTokenAddress; + + if (swapAllBalanceOffset != 0) { + uint256 balance = IERC20(aToken).balanceOf(msg.sender); + require(balance <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP'); + amountToSwap = balance; + } + + _pullAToken( + assetToSwapFrom, + aToken, + msg.sender, + amountToSwap, + permitParams + ); + + uint256 amountReceived = _sellOnParaSwap( + swapAllBalanceOffset, + swapCalldata, + augustus, + assetToSwapFrom, + assetToSwapTo, + amountToSwap, + minAmountToReceive + ); + + IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), 0); + IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), amountReceived); + LENDING_POOL.deposit(assetToSwapTo, amountReceived, msg.sender, 0); + } + + /** + * @dev Swaps an amount of an asset to another and deposits the funds on behalf of the initiator. + * @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0 + * @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract + * @param augustus Address of ParaSwap's AugustusSwapper contract + * @param permitParams Struct containing the permit signatures, set to all zeroes if not used + * @param flashLoanAmount Amount of the flash loan i.e. maximum amount to swap + * @param premium Fee of the flash loan + * @param initiator Account that initiated the flash loan + * @param assetToSwapFrom Address of the underyling asset to be swapped from + * @param assetToSwapTo Address of the underlying asset to be swapped to and deposited + * @param minAmountToReceive Min amount to be received from the swap + */ + function _swapLiquidity ( + uint256 swapAllBalanceOffset, + bytes memory swapCalldata, + address augustus, + PermitSignature memory permitParams, + uint256 flashLoanAmount, + uint256 premium, + address initiator, + address assetToSwapFrom, + address assetToSwapTo, + uint256 minAmountToReceive + ) internal { + address aToken = _getReserveData(assetToSwapFrom).aTokenAddress; + uint256 amountToSwap = flashLoanAmount; + + uint256 balance = IERC20(aToken).balanceOf(initiator); + if (swapAllBalanceOffset != 0) { + uint256 balanceToSwap = balance.sub(premium); + require(balanceToSwap <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP'); + amountToSwap = balanceToSwap; + } else { + require(balance >= amountToSwap.add(premium), 'INSUFFICIENT_ATOKEN_BALANCE'); + } + + uint256 amountReceived = _sellOnParaSwap( + swapAllBalanceOffset, + swapCalldata, + augustus, + assetToSwapFrom, + assetToSwapTo, + amountToSwap, + minAmountToReceive + ); + + IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), 0); + IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), amountReceived); + LENDING_POOL.deposit(assetToSwapTo, amountReceived, initiator, 0); + + _pullAToken( + assetToSwapFrom, + aToken, + initiator, + amountToSwap.add(premium), + permitParams + ); + + // Repay flash loan + IERC20(assetToSwapFrom).safeApprove(address(LENDING_POOL), 0); + IERC20(assetToSwapFrom).safeApprove(address(LENDING_POOL), flashLoanAmount.add(premium)); + } +} diff --git a/contracts/interfaces/IParaSwapAugustus.sol b/contracts/interfaces/IParaSwapAugustus.sol new file mode 100644 index 00000000..bd0714d0 --- /dev/null +++ b/contracts/interfaces/IParaSwapAugustus.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +interface IParaSwapAugustus { + function getTokenTransferProxy() external view returns (address); +} diff --git a/contracts/mocks/swap/MockParaSwapAugustus.sol b/contracts/mocks/swap/MockParaSwapAugustus.sol new file mode 100644 index 00000000..8a6874c6 --- /dev/null +++ b/contracts/mocks/swap/MockParaSwapAugustus.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {IParaSwapAugustus} from '../../interfaces/IParaSwapAugustus.sol'; +import {MockParaSwapTokenTransferProxy} from './MockParaSwapTokenTransferProxy.sol'; +import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; +import {MintableERC20} from '../tokens/MintableERC20.sol'; + +contract MockParaSwapAugustus is IParaSwapAugustus { + MockParaSwapTokenTransferProxy _tokenTransferProxy; + bool _expectingSwap; + address _expectedFromToken; + address _expectedToToken; + uint256 _expectedFromAmountMin; + uint256 _expectedFromAmountMax; + uint256 _receivedAmount; + + constructor() public { + _tokenTransferProxy = new MockParaSwapTokenTransferProxy(); + } + + function getTokenTransferProxy() external view override returns (address) { + return address(_tokenTransferProxy); + } + + function expectSwap( + address fromToken, + address toToken, + uint256 fromAmountMin, + uint256 fromAmountMax, + uint256 receivedAmount + ) external { + _expectingSwap = true; + _expectedFromToken = fromToken; + _expectedToToken = toToken; + _expectedFromAmountMin = fromAmountMin; + _expectedFromAmountMax = fromAmountMax; + _receivedAmount = receivedAmount; + } + + function swap( + address fromToken, + address toToken, + uint256 fromAmount, + uint256 toAmount + ) external returns (uint256) { + require(_expectingSwap, 'Not expecting swap'); + require(fromToken == _expectedFromToken, 'Unexpected from token'); + require(toToken == _expectedToToken, 'Unexpected to token'); + require(fromAmount >= _expectedFromAmountMin && fromAmount <= _expectedFromAmountMax, 'From amount out of range'); + require(_receivedAmount >= toAmount, 'Received amount of tokens are less than expected'); + _tokenTransferProxy.transferFrom(fromToken, msg.sender, address(this), fromAmount); + MintableERC20(toToken).mint(_receivedAmount); + IERC20(toToken).transfer(msg.sender, _receivedAmount); + _expectingSwap = false; + return _receivedAmount; + } +} diff --git a/contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol b/contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol new file mode 100644 index 00000000..a405cec3 --- /dev/null +++ b/contracts/mocks/swap/MockParaSwapTokenTransferProxy.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {Ownable} from '../../dependencies/openzeppelin/contracts/Ownable.sol'; +import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; + +contract MockParaSwapTokenTransferProxy is Ownable { + function transferFrom( + address token, + address from, + address to, + uint256 amount + ) external onlyOwner { + IERC20(token).transferFrom(from, to, amount); + } +} diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index fb284b35..eba11e27 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -36,9 +36,11 @@ import { MockAggregatorFactory, MockATokenFactory, MockFlashLoanReceiverFactory, + MockParaSwapAugustusFactory, MockStableDebtTokenFactory, MockVariableDebtTokenFactory, MockUniswapV2Router02Factory, + ParaSwapLiquiditySwapAdapterFactory, PriceOracleFactory, ReserveLogicFactory, SelfdestructTransferFactory, @@ -537,3 +539,22 @@ export const deployFlashLiquidationAdapter = async ( args, verify ); + +export const deployMockParaSwapAugustus = async (verify?: boolean) => + withSaveAndVerify( + await new MockParaSwapAugustusFactory(await getFirstSigner()).deploy(), + eContractid.MockParaSwapAugustus, + [], + verify + ); + +export const deployParaSwapLiquiditySwapAdapter = async ( + args: [tEthereumAddress], + verify?: boolean +) => + withSaveAndVerify( + await new ParaSwapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args), + eContractid.ParaSwapLiquiditySwapAdapter, + args, + verify + ); diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index 6504cceb..cd1aa792 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -18,6 +18,8 @@ import { MockStableDebtTokenFactory, MockVariableDebtTokenFactory, MockUniswapV2Router02Factory, + MockParaSwapAugustusFactory, + ParaSwapLiquiditySwapAdapterFactory, PriceOracleFactory, ReserveLogicFactory, SelfdestructTransferFactory, @@ -363,3 +365,19 @@ export const getFlashLiquidationAdapter = async (address?: tEthereumAddress) => .address, await getFirstSigner() ); + +export const getMockParaSwapAugustus = async (address?: tEthereumAddress) => + await MockParaSwapAugustusFactory.connect( + address || + (await getDb().get(`${eContractid.MockParaSwapAugustus}.${DRE.network.name}`).value()) + .address, + await getFirstSigner() + ); + +export const getParaSwapLiquiditySwapAdapter = async (address?: tEthereumAddress) => + await ParaSwapLiquiditySwapAdapterFactory.connect( + address || + (await getDb().get(`${eContractid.ParaSwapLiquiditySwapAdapter}.${DRE.network.name}`).value()) + .address, + await getFirstSigner() + ); diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index 6fce99b6..50fd77aa 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -301,3 +301,35 @@ export const buildFlashLiquidationAdapterParams = ( [collateralAsset, debtAsset, user, debtToCover, useEthPath] ); }; + +export const buildParaSwapLiquiditySwapParams = ( + assetToSwapTo: tEthereumAddress, + minAmountToReceive: BigNumberish, + swapAllBalanceOffset: BigNumberish, + swapCalldata: string | Buffer, + augustus: tEthereumAddress, + permitAmount: BigNumberish, + deadline: BigNumberish, + v: BigNumberish, + r: string | Buffer, + s: string | Buffer +) => { + return ethers.utils.defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'uint256', + 'bytes', + 'address', + 'tuple(uint256,uint256,uint8,bytes32,bytes32)', + ], + [ + assetToSwapTo, + minAmountToReceive, + swapAllBalanceOffset, + swapCalldata, + augustus, + [permitAmount, deadline, v, r, s], + ] + ); +}; diff --git a/helpers/types.ts b/helpers/types.ts index bc1e31e6..07dff857 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -71,6 +71,8 @@ export enum eContractid { UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter', UniswapRepayAdapter = 'UniswapRepayAdapter', FlashLiquidationAdapter = 'FlashLiquidationAdapter', + MockParaSwapAugustus = 'MockParaSwapAugustus', + ParaSwapLiquiditySwapAdapter = 'ParaSwapLiquiditySwapAdapter', } /* diff --git a/package.json b/package.json index 1f8d3043..b57a10dd 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "test-subgraph:scenarios": "hardhat --network hardhatevm_docker test test/__setup.spec.ts test/subgraph-scenarios.spec.ts", "test-weth": "hardhat test test/__setup.spec.ts test/weth-gateway.spec.ts", "test-uniswap": "hardhat test test/__setup.spec.ts test/uniswapAdapters*.spec.ts", + "test-paraswap": "hardhat test test/__setup.spec.ts test/paraswapAdapters*.spec.ts", "test:main:check-list": "MAINNET_FORK=true TS_NODE_TRANSPILE_ONLY=1 hardhat test test/__setup.spec.ts test/mainnet/check-list.spec.ts", "dev:coverage": "buidler compile --force && buidler coverage --network coverage", "aave:evm:dev:migration": "npm run compile && hardhat aave:dev", diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index 37ff9cfc..20a4f02c 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -26,6 +26,8 @@ import { deployUniswapLiquiditySwapAdapter, deployUniswapRepayAdapter, deployFlashLiquidationAdapter, + deployMockParaSwapAugustus, + deployParaSwapLiquiditySwapAdapter, } from '../helpers/contracts-deployments'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../helpers/types'; @@ -247,6 +249,10 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { await deployUniswapRepayAdapter(adapterParams); await deployFlashLiquidationAdapter(adapterParams); + await deployMockParaSwapAugustus(); + + await deployParaSwapLiquiditySwapAdapter([addressesProvider.address]); + await deployWalletBalancerProvider(); await deployWETHGateway([mockTokens.WETH.address, lendingPoolAddress]); diff --git a/test/helpers/make-suite.ts b/test/helpers/make-suite.ts index 4a75e54d..f6641a79 100644 --- a/test/helpers/make-suite.ts +++ b/test/helpers/make-suite.ts @@ -14,6 +14,7 @@ import { getUniswapLiquiditySwapAdapter, getUniswapRepayAdapter, getFlashLiquidationAdapter, + getParaSwapLiquiditySwapAdapter, } from '../../helpers/contracts-getters'; import { eEthereumNetwork, tEthereumAddress } from '../../helpers/types'; import { LendingPool } from '../../types/LendingPool'; @@ -32,6 +33,7 @@ import { LendingPoolAddressesProviderRegistry } from '../../types/LendingPoolAdd import { getEthersSigners } from '../../helpers/contracts-helpers'; import { UniswapLiquiditySwapAdapter } from '../../types/UniswapLiquiditySwapAdapter'; import { UniswapRepayAdapter } from '../../types/UniswapRepayAdapter'; +import { ParaSwapLiquiditySwapAdapter } from '../../types/ParaSwapLiquiditySwapAdapter'; import { getParamPerNetwork } from '../../helpers/contracts-helpers'; import { WETH9Mocked } from '../../types/WETH9Mocked'; import { WETHGateway } from '../../types/WETHGateway'; @@ -68,6 +70,7 @@ export interface TestEnv { registry: LendingPoolAddressesProviderRegistry; wethGateway: WETHGateway; flashLiquidationAdapter: FlashLiquidationAdapter; + paraswapLiquiditySwapAdapter: ParaSwapLiquiditySwapAdapter; } let buidlerevmSnapshotId: string = '0x1'; @@ -92,6 +95,7 @@ const testEnv: TestEnv = { uniswapLiquiditySwapAdapter: {} as UniswapLiquiditySwapAdapter, uniswapRepayAdapter: {} as UniswapRepayAdapter, flashLiquidationAdapter: {} as FlashLiquidationAdapter, + paraswapLiquiditySwapAdapter: {} as ParaSwapLiquiditySwapAdapter, registry: {} as LendingPoolAddressesProviderRegistry, wethGateway: {} as WETHGateway, } as TestEnv; @@ -158,6 +162,8 @@ export async function initializeMakeSuite() { testEnv.uniswapLiquiditySwapAdapter = await getUniswapLiquiditySwapAdapter(); testEnv.uniswapRepayAdapter = await getUniswapRepayAdapter(); testEnv.flashLiquidationAdapter = await getFlashLiquidationAdapter(); + + testEnv.paraswapLiquiditySwapAdapter = await getParaSwapLiquiditySwapAdapter(); } const setSnapshot = async () => { diff --git a/test/paraswapAdapters.liquiditySwap.spec.ts b/test/paraswapAdapters.liquiditySwap.spec.ts new file mode 100644 index 00000000..9561f7df --- /dev/null +++ b/test/paraswapAdapters.liquiditySwap.spec.ts @@ -0,0 +1,2332 @@ +import { makeSuite, TestEnv } from './helpers/make-suite'; +import { + convertToCurrencyDecimals, + getContract, + buildPermitParams, + getSignatureFromTypedData, + buildParaSwapLiquiditySwapParams, +} from '../helpers/contracts-helpers'; +import { getMockParaSwapAugustus } from '../helpers/contracts-getters'; +import { deployParaSwapLiquiditySwapAdapter } from '../helpers/contracts-deployments'; +import { MockParaSwapAugustus } from '../types/MockParaSwapAugustus'; +import { Zero } from '@ethersproject/constants'; +import BigNumber from 'bignumber.js'; +import { DRE, evmRevert, evmSnapshot } from '../helpers/misc-utils'; +import { ethers } from 'ethers'; +import { eContractid } from '../helpers/types'; +import { AToken } from '../types/AToken'; +import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants'; +import { MAX_UINT_AMOUNT } from '../helpers/constants'; +const { parseEther } = ethers.utils; + +const { expect } = require('chai'); + +makeSuite('ParaSwap adapters', (testEnv: TestEnv) => { + let mockAugustus: MockParaSwapAugustus; + let evmSnapshotId: string; + + before(async () => { + mockAugustus = await getMockParaSwapAugustus(); + }); + + beforeEach(async () => { + evmSnapshotId = await evmSnapshot(); + }); + + afterEach(async () => { + await evmRevert(evmSnapshotId); + }); + + describe('ParaSwapLiquiditySwapAdapter', () => { + describe('constructor', () => { + it('should deploy with correct parameters', async () => { + const { addressesProvider } = testEnv; + await deployParaSwapLiquiditySwapAdapter([ + addressesProvider.address, + ]); + }); + + it('should revert if not valid addresses provider', async () => { + await expect( + deployParaSwapLiquiditySwapAdapter([ + mockAugustus.address, + ]) + ).to.be.reverted; + }); + }); + + describe('executeOperation', () => { + beforeEach(async () => { + const { users, weth, dai, pool, deployer } = testEnv; + const userAddress = users[0].address; + + // Provide liquidity + await dai.mint(parseEther('20000')); + await dai.approve(pool.address, parseEther('20000')); + await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); + + await weth.mint(parseEther('10000')); + await weth.approve(pool.address, parseEther('10000')); + await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0); + + // Make a deposit for user + await weth.mint(parseEther('100')); + await weth.approve(pool.address, parseEther('100')); + await pool.deposit(weth.address, parseEther('100'), userAddress, 0); + }); + + it('should correctly swap tokens and deposit the out tokens in the pool', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal)); + expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + + it('should correctly swap tokens using permit', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + flashloanTotal.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + flashloanTotal, + deadline, + v, + r, + s + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal)); + expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + + it('should revert if caller not lending pool', async () => { + const { + users, + weth, + oracle, + dai, + aWETH, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + paraswapLiquiditySwapAdapter + .connect(user) + .executeOperation( + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params + ) + ).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL'); + }); + + it('should work correctly with tokens of different decimals', async () => { + const { + users, + usdc, + oracle, + dai, + aDai, + paraswapLiquiditySwapAdapter, + pool, + deployer, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); + const liquidity = await convertToCurrencyDecimals(usdc.address, '20000'); + + const flashloanPremium = amountUSDCtoSwap.mul(9).div(10000); + const flashloanTotal = amountUSDCtoSwap.add(flashloanPremium); + + // Provider liquidity + await usdc.mint(liquidity); + await usdc.approve(pool.address, liquidity); + await pool.deposit(usdc.address, liquidity, deployer.address, 0); + + // Make a deposit for user + await usdc.connect(user).mint(flashloanTotal); + await usdc.connect(user).approve(pool.address, flashloanTotal); + await pool.connect(user).deposit(usdc.address, flashloanTotal, userAddress, 0); + + const usdcPrice = await oracle.getAssetPrice(usdc.address); + const daiPrice = await oracle.getAssetPrice(dai.address); + + const collateralDecimals = (await usdc.decimals()).toString(); + const principalDecimals = (await dai.decimals()).toString(); + + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountUSDCtoSwap.toString()) + .times( + new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) + ) + .div( + new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) + ) + .div(new BigNumber(10).pow(principalDecimals)) + .toFixed(0) + ); + + await mockAugustus.expectSwap(usdc.address, dai.address, amountUSDCtoSwap, amountUSDCtoSwap, expectedDaiAmount); + + const aUsdcData = await pool.getReserveData(usdc.address); + const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); + + // User will swap liquidity aUsdc to aDai + const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress); + await aUsdc.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [usdc.address], + [amountUSDCtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount); + + const adapterUsdcBalance = await usdc.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAUsdcBalance = await aUsdc.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterUsdcBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(flashloanTotal)); + expect(userAUsdcBalance).to.be.lte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap)); + }); + + it('should revert when min amount to receive exceeds the max slippage amount', async () => { + const { + users, + weth, + oracle, + dai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const smallExpectedDaiAmount = expectedDaiAmount.div(2); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + smallExpectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); + }); + + it('should revert when min amount to receive exceeds the max slippage amount (with tokens of different decimals)', async () => { + const { + users, + usdc, + oracle, + dai, + paraswapLiquiditySwapAdapter, + pool, + deployer, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); + const liquidity = await convertToCurrencyDecimals(usdc.address, '20000'); + + const flashloanPremium = amountUSDCtoSwap.mul(9).div(10000); + const flashloanTotal = amountUSDCtoSwap.add(flashloanPremium); + + // Provider liquidity + await usdc.mint(liquidity); + await usdc.approve(pool.address, liquidity); + await pool.deposit(usdc.address, liquidity, deployer.address, 0); + + // Make a deposit for user + await usdc.connect(user).mint(flashloanTotal); + await usdc.connect(user).approve(pool.address, flashloanTotal); + await pool.connect(user).deposit(usdc.address, flashloanTotal, userAddress, 0); + + const usdcPrice = await oracle.getAssetPrice(usdc.address); + const daiPrice = await oracle.getAssetPrice(dai.address); + + const collateralDecimals = (await usdc.decimals()).toString(); + const principalDecimals = (await dai.decimals()).toString(); + + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountUSDCtoSwap.toString()) + .times( + new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) + ) + .div( + new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) + ) + .div(new BigNumber(10).pow(principalDecimals)) + .toFixed(0) + ); + + await mockAugustus.expectSwap(usdc.address, dai.address, amountUSDCtoSwap, amountUSDCtoSwap, expectedDaiAmount); + + const smallExpectedDaiAmount = expectedDaiAmount.div(2); + + const aUsdcData = await pool.getReserveData(usdc.address); + const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); + + // User will swap liquidity aUsdc to aDai + await aUsdc.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + smallExpectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [usdc.address], + [amountUSDCtoSwap], + [0], + userAddress, + params, + 0 + ) + ).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); + }); + + it('should correctly swap tokens all the balance', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const bigAmountToSwap = parseEther('11'); + const flashloanPremium = bigAmountToSwap.mul(9).div(10000); + const flashloanTotal = bigAmountToSwap.add(flashloanPremium); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium)); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium)); + + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [bigAmountToSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should correctly swap tokens all the balance using permit', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const bigAmountToSwap = parseEther('11'); + const flashloanPremium = bigAmountToSwap.mul(9).div(10000); + const flashloanTotal = bigAmountToSwap.add(flashloanPremium); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium)); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium)); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + flashloanTotal.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + flashloanTotal, + deadline, + v, + r, + s + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [bigAmountToSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should revert trying to swap all the balance with insufficient amount', async () => { + const { + users, + weth, + oracle, + dai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const smallAmountToSwap = parseEther('9'); + const flashloanPremium = smallAmountToSwap.mul(9).div(10000); + const flashloanTotal = smallAmountToSwap.add(flashloanPremium); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium)); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium)); + + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, smallAmountToSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [smallAmountToSwap], + [0], + userAddress, + params, + 0 + ) + ).to.be.revertedWith('INSUFFICIENT_AMOUNT_TO_SWAP'); + }); + + it('should revert trying to swap more than balance', async () => { + const { + users, + weth, + oracle, + dai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '101'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ).to.be.revertedWith('INSUFFICIENT_ATOKEN_BALANCE'); + }); + + it('should not touch any token balance already in the adapter', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + // Put token balances in the adapter + const adapterWethBalanceBefore = parseEther('123'); + await weth.mint(adapterWethBalanceBefore); + await weth.transfer(paraswapLiquiditySwapAdapter.address, adapterWethBalanceBefore); + const adapterDaiBalanceBefore = parseEther('234'); + await dai.mint(adapterDaiBalanceBefore); + await dai.transfer(paraswapLiquiditySwapAdapter.address, adapterDaiBalanceBefore); + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterWethBalance).to.be.eq(adapterWethBalanceBefore); + expect(adapterDaiBalance).to.be.eq(adapterDaiBalanceBefore); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal)); + expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + }); + + describe('executeOperation with borrowing', () => { + beforeEach(async () => { + const { users, weth, dai, pool, deployer } = testEnv; + const userAddress = users[0].address; + const borrower = users[1].signer; + const borrowerAddress = users[1].address; + + // Provide liquidity + await dai.mint(parseEther('20000')); + await dai.approve(pool.address, parseEther('20000')); + await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); + + await weth.mint(parseEther('10000')); + await weth.approve(pool.address, parseEther('10000')); + await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0); + + // Make a deposit for user + await weth.mint(parseEther('100')); + await weth.approve(pool.address, parseEther('100')); + await pool.deposit(weth.address, parseEther('100'), userAddress, 0); + + // Add borrowing + const collateralAmount = parseEther('10000000'); + await dai.mint(collateralAmount); + await dai.approve(pool.address, collateralAmount); + await pool.deposit(dai.address, collateralAmount, borrowerAddress, 0); + await pool.connect(borrower).borrow(weth.address, parseEther('5000'), 2, 0, borrowerAddress); + }); + + it('should correctly swap tokens and deposit the out tokens in the pool', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(flashloanTotal)); + expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap)); + }); + + it('should correctly swap tokens using permit', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const flashloanPremium = amountWETHtoSwap.mul(9).div(10000); + const flashloanTotal = amountWETHtoSwap.add(flashloanPremium); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + flashloanTotal.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + flashloanTotal, + deadline, + v, + r, + s + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [amountWETHtoSwap], + [0], + userAddress, + params, + 0 + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + // N.B. will get some portion of flashloan premium back from the pool + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(flashloanTotal)); + expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap)); + }); + + it('should correctly swap tokens all the balance', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount); + + const bigAmountToSwap = parseEther('11'); + const flashloanPremium = bigAmountToSwap.mul(9).div(10000); + const flashloanTotal = bigAmountToSwap.add(flashloanPremium); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium)); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + 0, + 0, + 0, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [bigAmountToSwap], + [0], + userAddress, + params, + 0 + ) + ).to.emit(paraswapLiquiditySwapAdapter, 'Swapped'); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should correctly swap tokens all the balance using permit', async () => { + const { + users, + weth, + oracle, + dai, + aDai, + aWETH, + pool, + paraswapLiquiditySwapAdapter, + } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount); + + const bigAmountToSwap = parseEther('11'); + const flashloanPremium = bigAmountToSwap.mul(9).div(10000); + const flashloanTotal = bigAmountToSwap.add(flashloanPremium); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium)); + + // User will swap liquidity aEth to aDai + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + flashloanTotal.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + const params = buildParaSwapLiquiditySwapParams( + dai.address, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + flashloanTotal, + deadline, + v, + r, + s + ); + + await expect( + pool + .connect(user) + .flashLoan( + paraswapLiquiditySwapAdapter.address, + [weth.address], + [bigAmountToSwap], + [0], + userAddress, + params, + 0 + ) + ).to.emit(paraswapLiquiditySwapAdapter, 'Swapped'); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + }); + + describe('swapAndDeposit', () => { + beforeEach(async () => { + const { users, weth, dai, pool, deployer } = testEnv; + const userAddress = users[0].address; + + // Provide liquidity + await dai.mint(parseEther('20000')); + await dai.approve(pool.address, parseEther('20000')); + await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); + + await weth.mint(parseEther('10000')); + await weth.approve(pool.address, parseEther('10000')); + await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0); + + // Make a deposit for user + await weth.mint(parseEther('100')); + await weth.approve(pool.address, parseEther('100')); + await pool.deposit(weth.address, parseEther('100'), userAddress, 0); + }); + + it('should correctly swap tokens and deposit the out tokens in the pool', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + + it('should correctly swap tokens using permit', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + amountWETHtoSwap.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: amountWETHtoSwap, + deadline, + v, + r, + s, + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + + it('should revert when trying to swap more than balance', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = (await convertToCurrencyDecimals(weth.address, '100')).add(1); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('SafeERC20: low-level call failed'); + }); + + it('should revert when trying to swap more than allowance', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap.sub(1)); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('SafeERC20: low-level call failed'); + }); + + it('should revert when min amount to receive exceeds the max slippage amount', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + const smallExpectedDaiAmount = expectedDaiAmount.div(2); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + smallExpectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); + }); + + it('should bubble up errors from Augustus', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + // Add 1 to expected amount so it will fail + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount.add(1)] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('Received amount of tokens are less than expected'); + }); + + it('should revert if Augustus swaps for less than minimum to receive', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + const actualDaiAmount = expectedDaiAmount.sub(1); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, actualDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, actualDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('INSUFFICIENT_AMOUNT_RECEIVED'); + }); + + it("should revert if Augustus doesn't swap correct amount", async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + const augustusSwapAmount = amountWETHtoSwap.sub(1); + + await mockAugustus.expectSwap(weth.address, dai.address, augustusSwapAmount, augustusSwapAmount, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, augustusSwapAmount, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('WRONG_BALANCE_AFTER_SWAP'); + }); + + it('should correctly swap all the balance when using a bigger amount', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90')); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap); + + const bigAmountToSwap = parseEther('11'); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, bigAmountToSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + bigAmountToSwap, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should correctly swap all the balance when using permit', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90')); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap); + + const bigAmountToSwap = parseEther('11'); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + bigAmountToSwap.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + bigAmountToSwap, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + { + amount: bigAmountToSwap, + deadline, + v, + r, + s, + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should revert trying to swap all the balance when using a smaller amount', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90')); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap); + + const smallAmountToSwap = parseEther('10').sub(1); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, smallAmountToSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, smallAmountToSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + smallAmountToSwap, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('INSUFFICIENT_AMOUNT_TO_SWAP'); + }); + + it('should not touch any token balance already in the adapter', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + // Put token balances in the adapter + const adapterWethBalanceBefore = parseEther('123'); + await weth.mint(adapterWethBalanceBefore); + await weth.transfer(paraswapLiquiditySwapAdapter.address, adapterWethBalanceBefore); + const adapterDaiBalanceBefore = parseEther('234'); + await dai.mint(adapterDaiBalanceBefore); + await dai.transfer(paraswapLiquiditySwapAdapter.address, adapterDaiBalanceBefore); + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(adapterWethBalanceBefore); + expect(adapterDaiBalance).to.be.eq(adapterDaiBalanceBefore); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap)); + }); + }); + + describe('swapAndDeposit with borrowing', () => { + beforeEach(async () => { + const { users, weth, dai, pool, deployer } = testEnv; + const userAddress = users[0].address; + const borrower = users[1].signer; + const borrowerAddress = users[1].address; + + // Provide liquidity + await dai.mint(parseEther('20000')); + await dai.approve(pool.address, parseEther('20000')); + await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); + + await weth.mint(parseEther('10000')); + await weth.approve(pool.address, parseEther('10000')); + await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0); + + // Make a deposit for user + await weth.mint(parseEther('100')); + await weth.approve(pool.address, parseEther('100')); + await pool.deposit(weth.address, parseEther('100'), userAddress, 0); + + // Add borrowing + const collateralAmount = parseEther('10000000'); + await dai.mint(collateralAmount); + await dai.approve(pool.address, collateralAmount); + await pool.deposit(dai.address, collateralAmount, borrowerAddress, 0); + await pool.connect(borrower).borrow(weth.address, parseEther('5000'), 2, 0, borrowerAddress); + }); + + it('should correctly swap tokens and deposit the out tokens in the pool', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(amountWETHtoSwap)); + expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap)); + }); + + it('should correctly swap tokens using permit', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + amountWETHtoSwap.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + mockAugustus.address, + { + amount: amountWETHtoSwap, + deadline, + v, + r, + s, + } + ) + ) + .to.emit(paraswapLiquiditySwapAdapter, 'Swapped') + .withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(amountWETHtoSwap)); + expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap)); + }); + + it('should correctly swap all the balance when using a bigger amount', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90')); + + // User will swap liquidity aEth to aDai + const bigAmountToSwap = parseEther('11'); + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, bigAmountToSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + bigAmountToSwap, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.emit(paraswapLiquiditySwapAdapter, 'Swapped'); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + + it('should correctly swap all the balance when using permit', async () => { + const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount); + + // Remove other balance + await aWETH.connect(user).transfer(users[1].address, parseEther('90')); + + // User will swap liquidity aEth to aDai + const bigAmountToSwap = parseEther('11'); + + const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; + const deadline = MAX_UINT_AMOUNT; + const nonce = (await aWETH._nonces(userAddress)).toNumber(); + const msgParams = buildPermitParams( + chainId, + aWETH.address, + '1', + await aWETH.name(), + userAddress, + paraswapLiquiditySwapAdapter.address, + nonce, + deadline, + bigAmountToSwap.toString() + ); + + const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; + if (!ownerPrivateKey) { + throw new Error('INVALID_OWNER_PK'); + } + + const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, bigAmountToSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + bigAmountToSwap, + expectedDaiAmount, + 4 + 2*32, + mockAugustusCalldata, + mockAugustus.address, + { + amount: bigAmountToSwap, + deadline, + v, + r, + s, + } + ) + ).to.emit(paraswapLiquiditySwapAdapter, 'Swapped'); + + const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address); + const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address); + const userADaiBalance = await aDai.balanceOf(userAddress); + const userAEthBalance = await aWETH.balanceOf(userAddress); + + expect(adapterWethBalance).to.be.eq(Zero); + expect(adapterDaiBalance).to.be.eq(Zero); + expect(userADaiBalance).to.be.eq(expectedDaiAmount); + expect(userAEthBalance).to.be.eq(Zero); + }); + }); + }); +}); diff --git a/test/uniswapAdapters.flashLiquidation.spec.ts b/test/uniswapAdapters.flashLiquidation.spec.ts index 063c6930..800a1b2c 100644 --- a/test/uniswapAdapters.flashLiquidation.spec.ts +++ b/test/uniswapAdapters.flashLiquidation.spec.ts @@ -198,7 +198,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { it('should revert if not valid addresses provider', async () => { const { weth } = testEnv; - expect( + await expect( deployFlashLiquidationAdapter([ mockUniswapRouter.address, mockUniswapRouter.address, diff --git a/test/uniswapAdapters.liquiditySwap.spec.ts b/test/uniswapAdapters.liquiditySwap.spec.ts index 1e30b2b3..bc8467e6 100644 --- a/test/uniswapAdapters.liquiditySwap.spec.ts +++ b/test/uniswapAdapters.liquiditySwap.spec.ts @@ -50,7 +50,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { it('should revert if not valid addresses provider', async () => { const { weth } = testEnv; - expect( + await expect( deployUniswapLiquiditySwapAdapter([ mockUniswapRouter.address, mockUniswapRouter.address, @@ -196,6 +196,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .div( new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) ) + .div(new BigNumber(10).pow(principalDecimals)) .toFixed(0) ); @@ -318,6 +319,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .div( new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) ) + .div(new BigNumber(10).pow(principalDecimals)) .toFixed(0) ); @@ -871,6 +873,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .div( new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) ) + .div(new BigNumber(10).pow(principalDecimals)) .toFixed(0) ); @@ -1493,6 +1496,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .div( new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) ) + .div(new BigNumber(10).pow(principalDecimals)) .toFixed(0) ); @@ -1601,6 +1605,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .div( new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) ) + .div(new BigNumber(10).pow(principalDecimals)) .toFixed(0) ); diff --git a/test/uniswapAdapters.repay.spec.ts b/test/uniswapAdapters.repay.spec.ts index c271917e..cd5450d3 100644 --- a/test/uniswapAdapters.repay.spec.ts +++ b/test/uniswapAdapters.repay.spec.ts @@ -87,7 +87,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { it('should revert if not valid addresses provider', async () => { const { weth } = testEnv; - expect( + await expect( deployUniswapRepayAdapter([ mockUniswapRouter.address, mockUniswapRouter.address, From 29772961ac28698f74e0cdeccb566ea5ba3e5df7 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Fri, 19 Mar 2021 00:16:39 +0000 Subject: [PATCH 02/62] Simplify ASM for copying revert reason --- contracts/adapters/BaseParaSwapSellAdapter.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol index 909ca2d3..ec50f4b7 100644 --- a/contracts/adapters/BaseParaSwapSellAdapter.sol +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -77,10 +77,8 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { if (!success) { // Copy revert reason from call assembly { - let ptr := mload(0x40) - let size := returndatasize() - returndatacopy(ptr, 0, size) - revert(ptr, size) + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) } } require(IERC20(assetToSwapFrom).balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP'); From 14e2ab47d95f42ec5ee486f367067e78a7588878 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Mon, 29 Mar 2021 17:19:26 +0100 Subject: [PATCH 03/62] Add task to deploy ParaSwapLiquiditySwapAdapter Note that it didn't actually work as written since gasPrice was set too low and also the verifyContract didn't work (so I had to verify it manually). Deployed to mainnet at 0xC91864A5A1E2F52aDdfb69e31b89a3b7783733c3. --- package.json | 1 + .../deploy-ParaSwapLiquiditySwapAdapter.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts diff --git a/package.json b/package.json index 1746c5a3..1105b4b7 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c", "main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "main:UniswapLiquiditySwapAdapter": "hardhat --network main deploy-UniswapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5", "kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave", "ropsten:verify": "npm run hardhat:ropsten verify:general -- --all --pool Aave", "mainnet:verify": "npm run hardhat:main verify:general -- --all --pool Aave", diff --git a/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts b/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts new file mode 100644 index 00000000..1ee0720f --- /dev/null +++ b/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts @@ -0,0 +1,28 @@ +import { task } from 'hardhat/config'; + +import { ParaSwapLiquiditySwapAdapterFactory } from '../../types'; +import { verifyContract } from '../../helpers/etherscan-verification'; +import { getFirstSigner } from '../../helpers/contracts-getters'; + +const CONTRACT_NAME = 'ParaSwapLiquiditySwapAdapter'; + +task(`deploy-${CONTRACT_NAME}`, `Deploys the ${CONTRACT_NAME} contract`) + .addParam('provider', 'Address of the LendingPoolAddressesProvider') + .addFlag('verify', `Verify ${CONTRACT_NAME} contract via Etherscan API.`) + .setAction(async ({ provider, verify }, localBRE) => { + await localBRE.run('set-DRE'); + + if (!localBRE.network.config.chainId) { + throw new Error('INVALID_CHAIN_ID'); + } + + console.log(`\n- ${CONTRACT_NAME} deployment`); + const adapter = await new ParaSwapLiquiditySwapAdapterFactory( + await getFirstSigner() + ).deploy(provider); + await adapter.deployTransaction.wait(); + console.log(`${CONTRACT_NAME}.address`, adapter.address); + await verifyContract(adapter.address, [provider]); + + console.log(`\tFinished ${CONTRACT_NAME} deployment`); + }); From fe05ceccd63e4bfe1e1f59cae9fa7af64ffc873b Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 13:40:55 +0100 Subject: [PATCH 04/62] Use safeTransfer for rescueTokens Fixes MixBytes Warning 3. --- contracts/adapters/BaseParaSwapAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index 72ce55fd..0b9488aa 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -119,6 +119,6 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { * - Only callable by the owner */ function rescueTokens(IERC20 token) external onlyOwner { - token.transfer(owner(), token.balanceOf(address(this))); + token.safeTransfer(owner(), token.balanceOf(address(this))); } } From b13a01d8b897ec5ac8b2c80b18ecff40c2adaf96 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 13:45:50 +0100 Subject: [PATCH 05/62] Rename _pullAToken function Fixes MixBytes Comment 4. --- contracts/adapters/BaseParaSwapAdapter.sol | 2 +- contracts/adapters/ParaSwapLiquiditySwapAdapter.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index 0b9488aa..70947d92 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -76,7 +76,7 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { * @param amount of tokens to be transferred to the contract * @param permitSignature struct containing the permit signature */ - function _pullAToken( + function _pullATokenAndWithdraw( address reserve, address reserveAToken, address user, diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index 4e6ef962..9053ad50 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -102,7 +102,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { amountToSwap = balance; } - _pullAToken( + _pullATokenAndWithdraw( assetToSwapFrom, aToken, msg.sender, @@ -176,7 +176,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), amountReceived); LENDING_POOL.deposit(assetToSwapTo, amountReceived, initiator, 0); - _pullAToken( + _pullATokenAndWithdraw( assetToSwapFrom, aToken, initiator, From 11d0367d3c3c8a16cffc9d7c0d48c9462e0b1a00 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 14:00:34 +0100 Subject: [PATCH 06/62] Explain code to overwrite fromAmount in comment Fixes MixBytes Comment 1. --- contracts/adapters/BaseParaSwapSellAdapter.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol index ec50f4b7..0e15f0e1 100644 --- a/contracts/adapters/BaseParaSwapSellAdapter.sol +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -66,9 +66,14 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { IERC20(assetToSwapFrom).safeApprove(tokenTransferProxy, amountToSwap); if (fromAmountOffset != 0) { + // Ensure 256 bit (32 bytes) fromAmount value is within bounds of the + // calldata, not overlapping with the first 4 bytes (function selector). require(fromAmountOffset >= 4 && fromAmountOffset <= swapCalldata.length.sub(32), 'FROM_AMOUNT_OFFSET_OUT_OF_RANGE'); + // Overwrite the fromAmount with the correct amount for the swap. + // In memory, swapCalldata consists of a 256 bit length field, followed by + // the actual bytes data, that is why 32 is added to the byte offset. assembly { mstore(add(swapCalldata, add(fromAmountOffset, 32)), amountToSwap) } From d26b1beb68e086e77ffda7aa429c05ee085e24d5 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 14:14:51 +0100 Subject: [PATCH 07/62] Fix _getDecimals function Added a limit on number of decimals and changed return type to uint8. Fixes MixBytes Warning 5 and ABDK CVF-30. --- contracts/adapters/BaseParaSwapAdapter.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index 70947d92..2ef5314a 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -56,8 +56,11 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { * @dev Get the decimals of an asset * @return number of decimals of the asset */ - function _getDecimals(address asset) internal view returns (uint256) { - return IERC20Detailed(asset).decimals(); + function _getDecimals(address asset) internal view returns (uint8) { + uint8 decimals = IERC20Detailed(asset).decimals(); + // Ensure 10**decimals won't overflow a uint256 + require(decimals <= 77, 'TOO_MANY_DECIMALS_ON_TOKEN'); + return decimals; } /** From 5b45be6a44181db110035d8c96bda743dc338be2 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 14:38:24 +0100 Subject: [PATCH 08/62] Don't ignore return value of withdraw Fixes MixBytes Warning 4. --- contracts/adapters/BaseParaSwapAdapter.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index 2ef5314a..849e1f1e 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -102,7 +102,10 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { IERC20(reserveAToken).safeTransferFrom(user, address(this), amount); // withdraw reserve - LENDING_POOL.withdraw(reserve, amount, address(this)); + require( + LENDING_POOL.withdraw(reserve, amount, address(this)) == amount, + 'UNEXPECTED_AMOUNT_WITHDRAWN' + ); } /** From afeb5fb996d693e69b8d3da1b74950c9aeb66797 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 14:47:10 +0100 Subject: [PATCH 09/62] Remove _usePermit function Just use a simple check if deadline is set or not. Fixes ABDK CVF-34 and CVF-35. --- contracts/adapters/BaseParaSwapAdapter.sol | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index 849e1f1e..d06e9ec5 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -86,7 +86,8 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { uint256 amount, PermitSignature memory permitSignature ) internal { - if (_usePermit(permitSignature)) { + // If deadline is set to zero, assume there is no signature for permit + if (permitSignature.deadline != 0) { IERC20WithPermit(reserveAToken).permit( user, address(this), @@ -108,17 +109,6 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { ); } - /** - * @dev Tells if the permit method should be called by inspecting if there is a valid signature. - * If signature params are set to 0, then permit won't be called. - * @param signature struct containing the permit signature - * @return whether or not permit should be called - */ - function _usePermit(PermitSignature memory signature) internal pure returns (bool) { - return - !(uint256(signature.deadline) == uint256(signature.v) && uint256(signature.deadline) == 0); - } - /** * @dev Emergency rescue for token stucked on this contract, as failsafe mechanism * - Funds should never remain in this contract more time than during transactions From 38bec942da636c2dc6120dfa3d9290bad1c4e73f Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 15:00:22 +0100 Subject: [PATCH 10/62] Check lengths of all the arrays Fixes ABDK CVF-5. --- contracts/adapters/ParaSwapLiquiditySwapAdapter.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index 9053ad50..edc7f745 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -40,7 +40,10 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { bytes calldata params ) external override returns (bool) { require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL'); - require(assets.length == 1, 'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED'); + require( + assets.length == 1 && amounts.length == 1 && premiums.length == 1, + 'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED' + ); uint256 flashLoanAmount = amounts[0]; uint256 premium = premiums[0]; From bf7b19a1815e434347e8d8ec4a1215069943437c Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 15:41:59 +0100 Subject: [PATCH 11/62] Add comments to empty constructor bodies Fixes ABDK CVF-4 and CVF-15. --- contracts/adapters/BaseParaSwapSellAdapter.sol | 1 + contracts/adapters/ParaSwapLiquiditySwapAdapter.sol | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol index 0e15f0e1..c433f3f7 100644 --- a/contracts/adapters/BaseParaSwapSellAdapter.sol +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -19,6 +19,7 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { constructor( ILendingPoolAddressesProvider addressesProvider ) public BaseParaSwapAdapter(addressesProvider) { + // This is only required to initialize BaseParaSwapAdapter } /** diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index edc7f745..a80c9df9 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -14,7 +14,9 @@ import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { constructor( ILendingPoolAddressesProvider addressesProvider - ) public BaseParaSwapSellAdapter(addressesProvider) {} + ) public BaseParaSwapSellAdapter(addressesProvider) { + // This is only required to initialize BaseParaSwapSellAdapter + } /** * @dev Swaps the received reserve amount from the flash loan into the asset specified in the params. From d8b8d50de82485144012e4dd34b849fb0cf4c686 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 16:50:20 +0100 Subject: [PATCH 12/62] Use better types than address Fixes ABDK CVF-6, CVF-7, CVF-16, CVF-17, CVF-31 and CVF-32. --- contracts/adapters/BaseParaSwapAdapter.sol | 12 ++-- .../adapters/BaseParaSwapSellAdapter.sol | 35 ++++++----- .../adapters/ParaSwapLiquiditySwapAdapter.sol | 61 +++++++++++-------- 3 files changed, 63 insertions(+), 45 deletions(-) diff --git a/contracts/adapters/BaseParaSwapAdapter.sol b/contracts/adapters/BaseParaSwapAdapter.sol index d06e9ec5..9b84dd93 100644 --- a/contracts/adapters/BaseParaSwapAdapter.sol +++ b/contracts/adapters/BaseParaSwapAdapter.sol @@ -21,6 +21,8 @@ import {FlashLoanReceiverBase} from '../flashloan/base/FlashLoanReceiverBase.sol abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; + using SafeERC20 for IERC20Detailed; + using SafeERC20 for IERC20WithPermit; struct PermitSignature { uint256 amount; @@ -56,8 +58,8 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { * @dev Get the decimals of an asset * @return number of decimals of the asset */ - function _getDecimals(address asset) internal view returns (uint8) { - uint8 decimals = IERC20Detailed(asset).decimals(); + function _getDecimals(IERC20Detailed asset) internal view returns (uint8) { + uint8 decimals = asset.decimals(); // Ensure 10**decimals won't overflow a uint256 require(decimals <= 77, 'TOO_MANY_DECIMALS_ON_TOKEN'); return decimals; @@ -81,14 +83,14 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { */ function _pullATokenAndWithdraw( address reserve, - address reserveAToken, + IERC20WithPermit reserveAToken, address user, uint256 amount, PermitSignature memory permitSignature ) internal { // If deadline is set to zero, assume there is no signature for permit if (permitSignature.deadline != 0) { - IERC20WithPermit(reserveAToken).permit( + reserveAToken.permit( user, address(this), permitSignature.amount, @@ -100,7 +102,7 @@ abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable { } // transfer from user to adapter - IERC20(reserveAToken).safeTransferFrom(user, address(this), amount); + reserveAToken.safeTransferFrom(user, address(this), amount); // withdraw reserve require( diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol index c433f3f7..5b750287 100644 --- a/contracts/adapters/BaseParaSwapSellAdapter.sol +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -6,7 +6,7 @@ import {BaseParaSwapAdapter} from './BaseParaSwapAdapter.sol'; import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol'; import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; -import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; +import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; /** * @title BaseParaSwapSellAdapter @@ -36,9 +36,9 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { function _sellOnParaSwap( uint256 fromAmountOffset, bytes memory swapCalldata, - address augustus, - address assetToSwapFrom, - address assetToSwapTo, + IParaSwapAugustus augustus, + IERC20Detailed assetToSwapFrom, + IERC20Detailed assetToSwapTo, uint256 amountToSwap, uint256 minAmountToReceive ) internal returns (uint256 amountReceived) { @@ -46,8 +46,8 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom); uint256 toAssetDecimals = _getDecimals(assetToSwapTo); - uint256 fromAssetPrice = _getPrice(assetToSwapFrom); - uint256 toAssetPrice = _getPrice(assetToSwapTo); + uint256 fromAssetPrice = _getPrice(address(assetToSwapFrom)); + uint256 toAssetPrice = _getPrice(address(assetToSwapTo)); uint256 expectedMinAmountOut = amountToSwap @@ -58,13 +58,13 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { require(expectedMinAmountOut <= minAmountToReceive, 'MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); } - uint256 balanceBeforeAssetFrom = IERC20(assetToSwapFrom).balanceOf(address(this)); + uint256 balanceBeforeAssetFrom = assetToSwapFrom.balanceOf(address(this)); require(balanceBeforeAssetFrom >= amountToSwap, 'INSUFFICIENT_BALANCE_BEFORE_SWAP'); - uint256 balanceBeforeAssetTo = IERC20(assetToSwapTo).balanceOf(address(this)); + uint256 balanceBeforeAssetTo = assetToSwapTo.balanceOf(address(this)); - address tokenTransferProxy = IParaSwapAugustus(augustus).getTokenTransferProxy(); - IERC20(assetToSwapFrom).safeApprove(tokenTransferProxy, 0); - IERC20(assetToSwapFrom).safeApprove(tokenTransferProxy, amountToSwap); + address tokenTransferProxy = augustus.getTokenTransferProxy(); + assetToSwapFrom.safeApprove(tokenTransferProxy, 0); + assetToSwapFrom.safeApprove(tokenTransferProxy, amountToSwap); if (fromAmountOffset != 0) { // Ensure 256 bit (32 bytes) fromAmount value is within bounds of the @@ -79,7 +79,7 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { mstore(add(swapCalldata, add(fromAmountOffset, 32)), amountToSwap) } } - (bool success,) = augustus.call(swapCalldata); + (bool success,) = address(augustus).call(swapCalldata); if (!success) { // Copy revert reason from call assembly { @@ -87,10 +87,15 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { revert(0, returndatasize()) } } - require(IERC20(assetToSwapFrom).balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP'); - amountReceived = IERC20(assetToSwapTo).balanceOf(address(this)).sub(balanceBeforeAssetTo); + require(assetToSwapFrom.balanceOf(address(this)) == balanceBeforeAssetFrom - amountToSwap, 'WRONG_BALANCE_AFTER_SWAP'); + amountReceived = assetToSwapTo.balanceOf(address(this)).sub(balanceBeforeAssetTo); require(amountReceived >= minAmountToReceive, 'INSUFFICIENT_AMOUNT_RECEIVED'); - emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, amountReceived); + emit Swapped( + address(assetToSwapFrom), + address(assetToSwapTo), + amountToSwap, + amountReceived + ); } } diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index a80c9df9..338fa09e 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -4,7 +4,9 @@ pragma experimental ABIEncoderV2; import {BaseParaSwapSellAdapter} from './BaseParaSwapSellAdapter.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; -import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; +import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; +import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol'; +import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; /** * @title ParaSwapLiquiditySwapAdapter @@ -50,15 +52,22 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { uint256 flashLoanAmount = amounts[0]; uint256 premium = premiums[0]; address initiatorLocal = initiator; - address assetToSwapFrom = assets[0]; + IERC20Detailed assetToSwapFrom = IERC20Detailed(assets[0]); ( - address assetToSwapTo, + IERC20Detailed assetToSwapTo, uint256 minAmountToReceive, uint256 swapAllBalanceOffset, bytes memory swapCalldata, - address augustus, + IParaSwapAugustus augustus, PermitSignature memory permitParams - ) = abi.decode(params, (address, uint256, uint256, bytes, address, PermitSignature)); + ) = abi.decode(params, ( + IERC20Detailed, + uint256, + uint256, + bytes, + IParaSwapAugustus, + PermitSignature + )); _swapLiquidity( swapAllBalanceOffset, @@ -90,25 +99,26 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { * @param permitParams Struct containing the permit signatures, set to all zeroes if not used */ function swapAndDeposit( - address assetToSwapFrom, - address assetToSwapTo, + IERC20Detailed assetToSwapFrom, + IERC20Detailed assetToSwapTo, uint256 amountToSwap, uint256 minAmountToReceive, uint256 swapAllBalanceOffset, bytes calldata swapCalldata, - address augustus, + IParaSwapAugustus augustus, PermitSignature calldata permitParams ) external { - address aToken = _getReserveData(assetToSwapFrom).aTokenAddress; + IERC20WithPermit aToken = + IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress); if (swapAllBalanceOffset != 0) { - uint256 balance = IERC20(aToken).balanceOf(msg.sender); + uint256 balance = aToken.balanceOf(msg.sender); require(balance <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP'); amountToSwap = balance; } _pullATokenAndWithdraw( - assetToSwapFrom, + address(assetToSwapFrom), aToken, msg.sender, amountToSwap, @@ -125,9 +135,9 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { minAmountToReceive ); - IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), 0); - IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), amountReceived); - LENDING_POOL.deposit(assetToSwapTo, amountReceived, msg.sender, 0); + assetToSwapTo.safeApprove(address(LENDING_POOL), 0); + assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived); + LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, msg.sender, 0); } /** @@ -146,19 +156,20 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { function _swapLiquidity ( uint256 swapAllBalanceOffset, bytes memory swapCalldata, - address augustus, + IParaSwapAugustus augustus, PermitSignature memory permitParams, uint256 flashLoanAmount, uint256 premium, address initiator, - address assetToSwapFrom, - address assetToSwapTo, + IERC20Detailed assetToSwapFrom, + IERC20Detailed assetToSwapTo, uint256 minAmountToReceive ) internal { - address aToken = _getReserveData(assetToSwapFrom).aTokenAddress; + IERC20WithPermit aToken = + IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress); uint256 amountToSwap = flashLoanAmount; - uint256 balance = IERC20(aToken).balanceOf(initiator); + uint256 balance = aToken.balanceOf(initiator); if (swapAllBalanceOffset != 0) { uint256 balanceToSwap = balance.sub(premium); require(balanceToSwap <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP'); @@ -177,12 +188,12 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { minAmountToReceive ); - IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), 0); - IERC20(assetToSwapTo).safeApprove(address(LENDING_POOL), amountReceived); - LENDING_POOL.deposit(assetToSwapTo, amountReceived, initiator, 0); + assetToSwapTo.safeApprove(address(LENDING_POOL), 0); + assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived); + LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, initiator, 0); _pullATokenAndWithdraw( - assetToSwapFrom, + address(assetToSwapFrom), aToken, initiator, amountToSwap.add(premium), @@ -190,7 +201,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { ); // Repay flash loan - IERC20(assetToSwapFrom).safeApprove(address(LENDING_POOL), 0); - IERC20(assetToSwapFrom).safeApprove(address(LENDING_POOL), flashLoanAmount.add(premium)); + assetToSwapFrom.safeApprove(address(LENDING_POOL), 0); + assetToSwapFrom.safeApprove(address(LENDING_POOL), flashLoanAmount.add(premium)); } } From 9d1cb50d769adb2b584f18d1c82aa2bf7bf76668 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 17:36:41 +0100 Subject: [PATCH 13/62] Add reentrancy guard to adapter Fixes MixBytes Warning 2. --- .../adapters/ParaSwapLiquiditySwapAdapter.sol | 7 ++- .../contracts/ReentrancyGuard.sol | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index 338fa09e..c5ff6305 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -7,13 +7,14 @@ import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddresses import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol'; import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; +import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/ReentrancyGuard.sol'; /** * @title ParaSwapLiquiditySwapAdapter * @notice Adapter to swap liquidity using ParaSwap. * @author Jason Raymond Bell */ -contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { +contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter, ReentrancyGuard { constructor( ILendingPoolAddressesProvider addressesProvider ) public BaseParaSwapSellAdapter(addressesProvider) { @@ -42,7 +43,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { uint256[] calldata premiums, address initiator, bytes calldata params - ) external override returns (bool) { + ) external override nonReentrant returns (bool) { require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL'); require( assets.length == 1 && amounts.length == 1 && premiums.length == 1, @@ -107,7 +108,7 @@ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter { bytes calldata swapCalldata, IParaSwapAugustus augustus, PermitSignature calldata permitParams - ) external { + ) external nonReentrant { IERC20WithPermit aToken = IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress); diff --git a/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol new file mode 100644 index 00000000..24c90c32 --- /dev/null +++ b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () internal { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} From 4fe36c8fa4c470e2553a4e6632a7d4cc544e5e4c Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Thu, 20 May 2021 23:25:51 +0100 Subject: [PATCH 14/62] Introduce registry of valid Augustus addresses Set in constructor of BaseParaSwapSellAdapter and validates before swap. Created mock registry that only validates one address. Changed the test fixtures to accomodate registry and added two new tests. Updated deployment script. Registry address left as a placeholder in package.json since not known yet. Fixes MixBytes Warning 1. --- .../adapters/BaseParaSwapSellAdapter.sol | 12 +++- .../adapters/ParaSwapLiquiditySwapAdapter.sol | 6 +- .../interfaces/IParaSwapAugustusRegistry.sol | 7 ++ contracts/mocks/swap/MockParaSwapAugustus.sol | 8 +-- .../swap/MockParaSwapAugustusRegistry.sol | 17 +++++ helpers/contracts-deployments.ts | 14 +++- helpers/contracts-getters.ts | 9 +++ helpers/types.ts | 1 + package.json | 2 +- .../deploy-ParaSwapLiquiditySwapAdapter.ts | 7 +- test-suites/test-aave/__setup.spec.ts | 7 +- .../paraswapAdapters.liquiditySwap.spec.ts | 65 ++++++++++++++++++- 12 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 contracts/interfaces/IParaSwapAugustusRegistry.sol create mode 100644 contracts/mocks/swap/MockParaSwapAugustusRegistry.sol diff --git a/contracts/adapters/BaseParaSwapSellAdapter.sol b/contracts/adapters/BaseParaSwapSellAdapter.sol index 5b750287..93d3cc5b 100644 --- a/contracts/adapters/BaseParaSwapSellAdapter.sol +++ b/contracts/adapters/BaseParaSwapSellAdapter.sol @@ -5,6 +5,7 @@ pragma experimental ABIEncoderV2; import {BaseParaSwapAdapter} from './BaseParaSwapAdapter.sol'; import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol'; import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; +import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; @@ -16,10 +17,15 @@ import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detai abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { using PercentageMath for uint256; + IParaSwapAugustusRegistry public immutable AUGUSTUS_REGISTRY; + constructor( - ILendingPoolAddressesProvider addressesProvider + ILendingPoolAddressesProvider addressesProvider, + IParaSwapAugustusRegistry augustusRegistry ) public BaseParaSwapAdapter(addressesProvider) { - // This is only required to initialize BaseParaSwapAdapter + // Do something on Augustus registry to check the right contract was passed + require(!augustusRegistry.isValidAugustus(address(0))); + AUGUSTUS_REGISTRY = augustusRegistry; } /** @@ -42,6 +48,8 @@ abstract contract BaseParaSwapSellAdapter is BaseParaSwapAdapter { uint256 amountToSwap, uint256 minAmountToReceive ) internal returns (uint256 amountReceived) { + require(AUGUSTUS_REGISTRY.isValidAugustus(address(augustus)), 'INVALID_AUGUSTUS'); + { uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom); uint256 toAssetDecimals = _getDecimals(assetToSwapTo); diff --git a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol index c5ff6305..7cc1105d 100644 --- a/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol +++ b/contracts/adapters/ParaSwapLiquiditySwapAdapter.sol @@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2; import {BaseParaSwapSellAdapter} from './BaseParaSwapSellAdapter.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; +import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol'; import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol'; import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol'; @@ -16,8 +17,9 @@ import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/Reentrancy */ contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter, ReentrancyGuard { constructor( - ILendingPoolAddressesProvider addressesProvider - ) public BaseParaSwapSellAdapter(addressesProvider) { + ILendingPoolAddressesProvider addressesProvider, + IParaSwapAugustusRegistry augustusRegistry + ) public BaseParaSwapSellAdapter(addressesProvider, augustusRegistry) { // This is only required to initialize BaseParaSwapSellAdapter } diff --git a/contracts/interfaces/IParaSwapAugustusRegistry.sol b/contracts/interfaces/IParaSwapAugustusRegistry.sol new file mode 100644 index 00000000..f10e13dd --- /dev/null +++ b/contracts/interfaces/IParaSwapAugustusRegistry.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +interface IParaSwapAugustusRegistry { + function isValidAugustus(address augustus) external view returns (bool); +} diff --git a/contracts/mocks/swap/MockParaSwapAugustus.sol b/contracts/mocks/swap/MockParaSwapAugustus.sol index 8a6874c6..1cf32171 100644 --- a/contracts/mocks/swap/MockParaSwapAugustus.sol +++ b/contracts/mocks/swap/MockParaSwapAugustus.sol @@ -8,7 +8,7 @@ import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; import {MintableERC20} from '../tokens/MintableERC20.sol'; contract MockParaSwapAugustus is IParaSwapAugustus { - MockParaSwapTokenTransferProxy _tokenTransferProxy; + MockParaSwapTokenTransferProxy immutable TOKEN_TRANSFER_PROXY; bool _expectingSwap; address _expectedFromToken; address _expectedToToken; @@ -17,11 +17,11 @@ contract MockParaSwapAugustus is IParaSwapAugustus { uint256 _receivedAmount; constructor() public { - _tokenTransferProxy = new MockParaSwapTokenTransferProxy(); + TOKEN_TRANSFER_PROXY = new MockParaSwapTokenTransferProxy(); } function getTokenTransferProxy() external view override returns (address) { - return address(_tokenTransferProxy); + return address(TOKEN_TRANSFER_PROXY); } function expectSwap( @@ -50,7 +50,7 @@ contract MockParaSwapAugustus is IParaSwapAugustus { require(toToken == _expectedToToken, 'Unexpected to token'); require(fromAmount >= _expectedFromAmountMin && fromAmount <= _expectedFromAmountMax, 'From amount out of range'); require(_receivedAmount >= toAmount, 'Received amount of tokens are less than expected'); - _tokenTransferProxy.transferFrom(fromToken, msg.sender, address(this), fromAmount); + TOKEN_TRANSFER_PROXY.transferFrom(fromToken, msg.sender, address(this), fromAmount); MintableERC20(toToken).mint(_receivedAmount); IERC20(toToken).transfer(msg.sender, _receivedAmount); _expectingSwap = false; diff --git a/contracts/mocks/swap/MockParaSwapAugustusRegistry.sol b/contracts/mocks/swap/MockParaSwapAugustusRegistry.sol new file mode 100644 index 00000000..c8998ec1 --- /dev/null +++ b/contracts/mocks/swap/MockParaSwapAugustusRegistry.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {IParaSwapAugustusRegistry} from '../../interfaces/IParaSwapAugustusRegistry.sol'; + +contract MockParaSwapAugustusRegistry is IParaSwapAugustusRegistry { + address immutable AUGUSTUS; + + constructor(address augustus) public { + AUGUSTUS = augustus; + } + + function isValidAugustus(address augustus) external view override returns (bool) { + return augustus == AUGUSTUS; + } +} diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 9f5e4eee..97331547 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -36,6 +36,7 @@ import { MockATokenFactory, MockFlashLoanReceiverFactory, MockParaSwapAugustusFactory, + MockParaSwapAugustusRegistryFactory, MockStableDebtTokenFactory, MockVariableDebtTokenFactory, MockUniswapV2Router02Factory, @@ -620,9 +621,20 @@ export const deployMockParaSwapAugustus = async (verify?: boolean) => verify ); -export const deployParaSwapLiquiditySwapAdapter = async ( +export const deployMockParaSwapAugustusRegistry = async ( args: [tEthereumAddress], verify?: boolean +) => + withSaveAndVerify( + await new MockParaSwapAugustusRegistryFactory(await getFirstSigner()).deploy(...args), + eContractid.MockParaSwapAugustusRegistry, + args, + verify + ); + +export const deployParaSwapLiquiditySwapAdapter = async ( + args: [tEthereumAddress, tEthereumAddress], + verify?: boolean ) => withSaveAndVerify( await new ParaSwapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args), diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index d7281291..82b3df5b 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -19,6 +19,7 @@ import { MockVariableDebtTokenFactory, MockUniswapV2Router02Factory, MockParaSwapAugustusFactory, + MockParaSwapAugustusRegistryFactory, ParaSwapLiquiditySwapAdapterFactory, PriceOracleFactory, ReserveLogicFactory, @@ -374,6 +375,14 @@ export const getMockParaSwapAugustus = async (address?: tEthereumAddress) => await getFirstSigner() ); +export const getMockParaSwapAugustusRegistry = async (address?: tEthereumAddress) => + await MockParaSwapAugustusRegistryFactory.connect( + address || + (await getDb().get(`${eContractid.MockParaSwapAugustusRegistry}.${DRE.network.name}`).value()) + .address, + await getFirstSigner() + ); + export const getParaSwapLiquiditySwapAdapter = async (address?: tEthereumAddress) => await ParaSwapLiquiditySwapAdapterFactory.connect( address || diff --git a/helpers/types.ts b/helpers/types.ts index 38bcebd0..1feac1ed 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -88,6 +88,7 @@ export enum eContractid { UniswapRepayAdapter = 'UniswapRepayAdapter', FlashLiquidationAdapter = 'FlashLiquidationAdapter', MockParaSwapAugustus = 'MockParaSwapAugustus', + MockParaSwapAugustusRegistry = 'MockParaSwapAugustusRegistry', ParaSwapLiquiditySwapAdapter = 'ParaSwapLiquiditySwapAdapter', } diff --git a/package.json b/package.json index 1105b4b7..46c04270 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c", "main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "main:UniswapLiquiditySwapAdapter": "hardhat --network main deploy-UniswapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - "main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5", + "main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --augustusRegistry 0x0000000000000000000000000000000000000000", "kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave", "ropsten:verify": "npm run hardhat:ropsten verify:general -- --all --pool Aave", "mainnet:verify": "npm run hardhat:main verify:general -- --all --pool Aave", diff --git a/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts b/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts index 1ee0720f..1322645b 100644 --- a/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts +++ b/tasks/deployments/deploy-ParaSwapLiquiditySwapAdapter.ts @@ -8,8 +8,9 @@ const CONTRACT_NAME = 'ParaSwapLiquiditySwapAdapter'; task(`deploy-${CONTRACT_NAME}`, `Deploys the ${CONTRACT_NAME} contract`) .addParam('provider', 'Address of the LendingPoolAddressesProvider') + .addParam('augustusRegistry', 'Address of ParaSwap AugustusRegistry') .addFlag('verify', `Verify ${CONTRACT_NAME} contract via Etherscan API.`) - .setAction(async ({ provider, verify }, localBRE) => { + .setAction(async ({ provider, augustusRegistry, verify }, localBRE) => { await localBRE.run('set-DRE'); if (!localBRE.network.config.chainId) { @@ -19,10 +20,10 @@ task(`deploy-${CONTRACT_NAME}`, `Deploys the ${CONTRACT_NAME} contract`) console.log(`\n- ${CONTRACT_NAME} deployment`); const adapter = await new ParaSwapLiquiditySwapAdapterFactory( await getFirstSigner() - ).deploy(provider); + ).deploy(provider, augustusRegistry); await adapter.deployTransaction.wait(); console.log(`${CONTRACT_NAME}.address`, adapter.address); - await verifyContract(adapter.address, [provider]); + await verifyContract(adapter.address, [provider, augustusRegistry]); console.log(`\tFinished ${CONTRACT_NAME} deployment`); }); diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index 9e4422ca..7dd73c15 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -27,6 +27,7 @@ import { deployUniswapRepayAdapter, deployFlashLiquidationAdapter, deployMockParaSwapAugustus, + deployMockParaSwapAugustusRegistry, deployParaSwapLiquiditySwapAdapter, authorizeWETHGateway, } from '../../helpers/contracts-deployments'; @@ -286,9 +287,11 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { await deployUniswapRepayAdapter(adapterParams); await deployFlashLiquidationAdapter(adapterParams); - await deployMockParaSwapAugustus(); + const augustus = await deployMockParaSwapAugustus(); - await deployParaSwapLiquiditySwapAdapter([addressesProvider.address]); + const augustusRegistry = await deployMockParaSwapAugustusRegistry([augustus.address]); + + await deployParaSwapLiquiditySwapAdapter([addressesProvider.address, augustusRegistry.address]); await deployWalletBalancerProvider(); diff --git a/test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts b/test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts index 415bb474..1a4a424b 100644 --- a/test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts +++ b/test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts @@ -6,9 +6,13 @@ import { getSignatureFromTypedData, buildParaSwapLiquiditySwapParams, } from '../../helpers/contracts-helpers'; -import { getMockParaSwapAugustus } from '../../helpers/contracts-getters'; +import { + getMockParaSwapAugustus, + getMockParaSwapAugustusRegistry, +} from '../../helpers/contracts-getters'; import { deployParaSwapLiquiditySwapAdapter } from '../../helpers/contracts-deployments'; import { MockParaSwapAugustus } from '../../types/MockParaSwapAugustus'; +import { MockParaSwapAugustusRegistry } from '../../types/MockParaSwapAugustusRegistry'; import { Zero } from '@ethersproject/constants'; import BigNumber from 'bignumber.js'; import { DRE, evmRevert, evmSnapshot } from '../../helpers/misc-utils'; @@ -23,10 +27,12 @@ const { expect } = require('chai'); makeSuite('ParaSwap adapters', (testEnv: TestEnv) => { let mockAugustus: MockParaSwapAugustus; + let mockAugustusRegistry: MockParaSwapAugustusRegistry; let evmSnapshotId: string; before(async () => { mockAugustus = await getMockParaSwapAugustus(); + mockAugustusRegistry = await getMockParaSwapAugustusRegistry(); }); beforeEach(async () => { @@ -43,13 +49,25 @@ makeSuite('ParaSwap adapters', (testEnv: TestEnv) => { const { addressesProvider } = testEnv; await deployParaSwapLiquiditySwapAdapter([ addressesProvider.address, + mockAugustusRegistry.address, ]); }); it('should revert if not valid addresses provider', async () => { await expect( deployParaSwapLiquiditySwapAdapter([ - mockAugustus.address, + mockAugustus.address, // any invalid contract can be used here + mockAugustusRegistry.address, + ]) + ).to.be.reverted; + }); + + it('should revert if not valid augustus registry', async () => { + const { addressesProvider } = testEnv; + await expect( + deployParaSwapLiquiditySwapAdapter([ + addressesProvider.address, + mockAugustus.address, // any invalid contract can be used here ]) ).to.be.reverted; }); @@ -1637,6 +1655,49 @@ makeSuite('ParaSwap adapters', (testEnv: TestEnv) => { ).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE'); }); + it('should revert if wrong address used for Augustus', async () => { + const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; + const user = users[0].signer; + const userAddress = users[0].address; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount); + + // User will swap liquidity aEth to aDai + await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap); + + const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData( + 'swap', + [weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount] + ); + + await expect( + paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + weth.address, + dai.address, + amountWETHtoSwap, + expectedDaiAmount, + 0, + mockAugustusCalldata, + oracle.address, // using arbitrary contract instead of mock Augustus + { + amount: 0, + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + } + ) + ).to.be.revertedWith('INVALID_AUGUSTUS'); + }); + it('should bubble up errors from Augustus', async () => { const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv; const user = users[0].signer; From 0ec5e213efc0276cccfafc29ab36a166d6f863f7 Mon Sep 17 00:00:00 2001 From: Jason Raymond Bell Date: Tue, 15 Jun 2021 15:56:25 +0100 Subject: [PATCH 15/62] Add AugustusRegistry address --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46c04270..d2f4ed73 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c", "main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "main:UniswapLiquiditySwapAdapter": "hardhat --network main deploy-UniswapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - "main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --augustusRegistry 0x0000000000000000000000000000000000000000", + "main:ParaSwapLiquiditySwapAdapter": "hardhat --network main deploy-ParaSwapLiquiditySwapAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --augustusRegistry 0xa68bEA62Dc4034A689AA0F58A76681433caCa663", "kovan:verify": "npm run hardhat:kovan verify:general -- --all --pool Aave", "ropsten:verify": "npm run hardhat:ropsten verify:general -- --all --pool Aave", "mainnet:verify": "npm run hardhat:main verify:general -- --all --pool Aave", From 12896ff4125379d28684bd4fa55978f1c63356c7 Mon Sep 17 00:00:00 2001 From: andyk Date: Thu, 17 Jun 2021 16:53:59 +0300 Subject: [PATCH 16/62] add more functions to the UI data provider --- contracts/misc/UiPoolDataProvider.sol | 183 +++++++++++++++++- .../misc/interfaces/IUiPoolDataProvider.sol | 22 +++ 2 files changed, 203 insertions(+), 2 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index f06d0183..8eff3e4e 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -51,6 +51,185 @@ contract UiPoolDataProvider is IUiPoolDataProvider { ); } + function getReservesList(ILendingPoolAddressesProvider provider) + public + view + override + returns (address[] memory) + { + ILendingPool lendingPool = ILendingPool(provider.getLendingPool()); + return lendingPool.getReservesList(); + } + + function getSimpleReservesData(ILendingPoolAddressesProvider provider) + public + view + override + returns ( + AggregatedReserveData[] memory, + uint256, + uint256 + ) + { + ILendingPool lendingPool = ILendingPool(provider.getLendingPool()); + address[] memory reserves = lendingPool.getReservesList(); + AggregatedReserveData[] memory reservesData = new AggregatedReserveData[](reserves.length); + + for (uint256 i = 0; i < reserves.length; i++) { + AggregatedReserveData memory reserveData = reservesData[i]; + reserveData.underlyingAsset = reserves[i]; + + // reserve current state + DataTypes.ReserveData memory baseData = + lendingPool.getReserveData(reserveData.underlyingAsset); + reserveData.liquidityIndex = baseData.liquidityIndex; + reserveData.variableBorrowIndex = baseData.variableBorrowIndex; + reserveData.liquidityRate = baseData.currentLiquidityRate; + reserveData.variableBorrowRate = baseData.currentVariableBorrowRate; + reserveData.stableBorrowRate = baseData.currentStableBorrowRate; + reserveData.lastUpdateTimestamp = baseData.lastUpdateTimestamp; + reserveData.aTokenAddress = baseData.aTokenAddress; + reserveData.stableDebtTokenAddress = baseData.stableDebtTokenAddress; + reserveData.variableDebtTokenAddress = baseData.variableDebtTokenAddress; + reserveData.interestRateStrategyAddress = baseData.interestRateStrategyAddress; + reserveData.priceInEth = oracle.getAssetPrice(reserveData.underlyingAsset); + + reserveData.availableLiquidity = IERC20Detailed(reserveData.underlyingAsset).balanceOf( + reserveData.aTokenAddress + ); + ( + reserveData.totalPrincipalStableDebt, + , + reserveData.averageStableRate, + reserveData.stableDebtLastUpdateTimestamp + ) = IStableDebtToken(reserveData.stableDebtTokenAddress).getSupplyData(); + reserveData.totalScaledVariableDebt = IVariableDebtToken(reserveData.variableDebtTokenAddress) + .scaledTotalSupply(); + + // reserve configuration + + // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed + reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); + reserveData.name = ''; + + ( + reserveData.baseLTVasCollateral, + reserveData.reserveLiquidationThreshold, + reserveData.reserveLiquidationBonus, + reserveData.decimals, + reserveData.reserveFactor + ) = baseData.configuration.getParamsMemory(); + ( + reserveData.isActive, + reserveData.isFrozen, + reserveData.borrowingEnabled, + reserveData.stableBorrowRateEnabled + ) = baseData.configuration.getFlagsMemory(); + reserveData.usageAsCollateralEnabled = reserveData.baseLTVasCollateral != 0; + ( + reserveData.variableRateSlope1, + reserveData.variableRateSlope2, + reserveData.stableRateSlope1, + reserveData.stableRateSlope2 + ) = getInterestRateStrategySlopes( + DefaultReserveInterestRateStrategy(reserveData.interestRateStrategyAddress) + ); + + // incentives + if (address(0) != address(incentivesController)) { + ( + reserveData.aEmissionPerSecond, + reserveData.aIncentivesLastUpdateTimestamp, + reserveData.aTokenIncentivesIndex + ) = incentivesController.getAssetData(reserveData.aTokenAddress); + + ( + reserveData.sEmissionPerSecond, + reserveData.sIncentivesLastUpdateTimestamp, + reserveData.sTokenIncentivesIndex + ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); + + ( + reserveData.vEmissionPerSecond, + reserveData.vIncentivesLastUpdateTimestamp, + reserveData.vTokenIncentivesIndex + ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); + } + } + + uint256 emissionEndTimestamp; + if (address(0) != address(incentivesController)) { + emissionEndTimestamp = incentivesController.DISTRIBUTION_END(); + } + + return (reservesData, oracle.getAssetPrice(MOCK_USD_ADDRESS), emissionEndTimestamp); + } + + function getUserReservesData(ILendingPoolAddressesProvider provider, address user) + external + view + override + returns (UserReserveData[] memory, uint256) + { + ILendingPool lendingPool = ILendingPool(provider.getLendingPool()); + address[] memory reserves = lendingPool.getReservesList(); + DataTypes.UserConfigurationMap memory userConfig = lendingPool.getUserConfiguration(user); + + UserReserveData[] memory userReservesData = + new UserReserveData[](user != address(0) ? reserves.length : 0); + + for (uint256 i = 0; i < reserves.length; i++) { + DataTypes.ReserveData memory baseData = lendingPool.getReserveData(reserves[i]); + // incentives + if (address(0) != address(incentivesController)) { + userReservesData[i].aTokenincentivesUserIndex = incentivesController.getUserAssetData( + user, + baseData.aTokenAddress + ); + userReservesData[i].vTokenincentivesUserIndex = incentivesController.getUserAssetData( + user, + baseData.variableDebtTokenAddress + ); + userReservesData[i].sTokenincentivesUserIndex = incentivesController.getUserAssetData( + user, + baseData.stableDebtTokenAddress + ); + } + // user reserve data + userReservesData[i].underlyingAsset = reserves[i]; + userReservesData[i].scaledATokenBalance = IAToken(baseData.aTokenAddress).scaledBalanceOf( + user + ); + userReservesData[i].usageAsCollateralEnabledOnUser = userConfig.isUsingAsCollateral(i); + + if (userConfig.isBorrowing(i)) { + userReservesData[i].scaledVariableDebt = IVariableDebtToken( + baseData + .variableDebtTokenAddress + ) + .scaledBalanceOf(user); + userReservesData[i].principalStableDebt = IStableDebtToken(baseData.stableDebtTokenAddress) + .principalBalanceOf(user); + if (userReservesData[i].principalStableDebt != 0) { + userReservesData[i].stableBorrowRate = IStableDebtToken(baseData.stableDebtTokenAddress) + .getUserStableRate(user); + userReservesData[i].stableBorrowLastUpdateTimestamp = IStableDebtToken( + baseData + .stableDebtTokenAddress + ) + .getUserLastUpdated(user); + } + } + } + + uint256 userUnclaimedRewards; + if (address(0) != address(incentivesController)) { + userUnclaimedRewards = incentivesController.getUserUnclaimedRewards(user); + } + + return (userReservesData, userUnclaimedRewards); + } + function getReservesData(ILendingPoolAddressesProvider provider, address user) external view @@ -200,12 +379,12 @@ contract UiPoolDataProvider is IUiPoolDataProvider { } } - IncentivesControllerData memory incentivesControllerData; if (address(0) != address(incentivesController)) { if (user != address(0)) { - incentivesControllerData.userUnclaimedRewards = incentivesController.getUserUnclaimedRewards(user); + incentivesControllerData.userUnclaimedRewards = incentivesController + .getUserUnclaimedRewards(user); } incentivesControllerData.emissionEndTimestamp = incentivesController.DISTRIBUTION_END(); } diff --git a/contracts/misc/interfaces/IUiPoolDataProvider.sol b/contracts/misc/interfaces/IUiPoolDataProvider.sol index 15c9bd07..998e79ed 100644 --- a/contracts/misc/interfaces/IUiPoolDataProvider.sol +++ b/contracts/misc/interfaces/IUiPoolDataProvider.sol @@ -73,7 +73,29 @@ interface IUiPoolDataProvider { uint256 emissionEndTimestamp; } + function getReservesList(ILendingPoolAddressesProvider provider) + external + view + returns (address[] memory); + function getSimpleReservesData(ILendingPoolAddressesProvider provider) + external + view + returns ( + AggregatedReserveData[] memory, + uint256, // usd price eth + uint256 // emission end timestamp + ); + + function getUserReservesData(ILendingPoolAddressesProvider provider, address user) + external + view + returns ( + UserReserveData[] memory, + uint256 // user unclaimed rewards + ); + + // generic method with full data function getReservesData(ILendingPoolAddressesProvider provider, address user) external view From 7849be11f5d97ce104e0ca82fc9a0d05ddc7a76e Mon Sep 17 00:00:00 2001 From: andyk Date: Thu, 17 Jun 2021 17:01:19 +0300 Subject: [PATCH 17/62] fix params order in getAssetData --- contracts/misc/UiPoolDataProvider.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 8eff3e4e..86876aab 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -138,21 +138,21 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // incentives if (address(0) != address(incentivesController)) { ( + reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, - reserveData.aIncentivesLastUpdateTimestamp, - reserveData.aTokenIncentivesIndex + reserveData.aIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.aTokenAddress); ( + reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, - reserveData.sIncentivesLastUpdateTimestamp, - reserveData.sTokenIncentivesIndex + reserveData.sIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); ( + reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, - reserveData.vIncentivesLastUpdateTimestamp, - reserveData.vTokenIncentivesIndex + reserveData.vIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); } } From b34499c5309a49a16e6f8d9624647b8e3e8378f9 Mon Sep 17 00:00:00 2001 From: Hadrien Charlanes Date: Mon, 21 Jun 2021 09:42:50 +0200 Subject: [PATCH 18/62] feat: added possibility to discard bytecode max size --- hardhat.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hardhat.config.ts b/hardhat.config.ts index 10b4402b..278577bb 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -30,6 +30,7 @@ const HARDFORK = 'istanbul'; const ETHERSCAN_KEY = process.env.ETHERSCAN_KEY || ''; const MNEMONIC_PATH = "m/44'/60'/0'/0"; const MNEMONIC = process.env.MNEMONIC || ''; +const UNLIMITED_BYTECODE_SIZE = process.env.UNLIMITED_BYTECODE_SIZE === 'true'; // Prevent to load scripts before compilation and typechain if (!SKIP_LOAD) { @@ -104,6 +105,7 @@ const buidlerConfig: HardhatUserConfig = { blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT, gas: DEFAULT_BLOCK_GAS_LIMIT, gasPrice: 8000000000, + allowUnlimitedContractSize: UNLIMITED_BYTECODE_SIZE, chainId: BUIDLEREVM_CHAINID, throwOnTransactionFailures: true, throwOnCallFailures: true, From d51ac1d6fea00bb49ed850390c504c58ebe1172e Mon Sep 17 00:00:00 2001 From: andyk Date: Wed, 14 Jul 2021 15:56:41 +0200 Subject: [PATCH 19/62] temp fix for UIPoolDataProvider on polygon --- .../interfaces/IAaveIncentivesController.sol | 15 +++++++++++++++ contracts/misc/UiPoolDataProvider.sol | 18 ++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/contracts/interfaces/IAaveIncentivesController.sol b/contracts/interfaces/IAaveIncentivesController.sol index bae75967..0006e31e 100644 --- a/contracts/interfaces/IAaveIncentivesController.sol +++ b/contracts/interfaces/IAaveIncentivesController.sol @@ -30,6 +30,21 @@ interface IAaveIncentivesController { uint256 ); + /* + * LEGACY ************************** + * @dev Returns the configuration of the distribution for a certain asset + * @param asset The address of the reference asset of the distribution + * @return The asset index, the emission per second and the last updated timestamp + **/ + function assets(address asset) + external + view + returns ( + uint128, + uint128, + uint256 + ); + /** * @dev Whitelists an address to claim the rewards on behalf of another address * @param user The address of the user diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 86876aab..5be19954 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -141,19 +141,22 @@ contract UiPoolDataProvider is IUiPoolDataProvider { reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.aTokenAddress); + // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.aTokenAddress); ( reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, reserveData.sIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); + // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, reserveData.vIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); + // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } } @@ -315,19 +318,22 @@ contract UiPoolDataProvider is IUiPoolDataProvider { reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.aTokenAddress); + // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.aTokenAddress); ( reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, reserveData.sIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); + // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, reserveData.vIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); + // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix + ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } if (user != address(0)) { From 79294d052497d0e836a83f43405187687729895f Mon Sep 17 00:00:00 2001 From: David Racero Date: Wed, 14 Jul 2021 16:41:32 +0200 Subject: [PATCH 20/62] feat: support custom quote currencies. Added base scripts for custom atokens and rates. --- contracts/misc/AaveOracleV2.sol | 125 ++++++++++++++++++++++ hardhat.config.ts | 2 +- helper-hardhat-config.ts | 6 +- helpers/configuration.ts | 33 +++--- helpers/constants.ts | 2 + helpers/contracts-deployments.ts | 99 +++++++++++++++-- helpers/contracts-getters.ts | 147 +++++++++++++++++--------- helpers/contracts-helpers.ts | 49 ++++++--- helpers/init-helpers.ts | 170 ++++++++---------------------- helpers/misc-utils.ts | 23 ++++ helpers/types.ts | 20 ++-- markets/aave/commons.ts | 44 ++++---- markets/aave/index.ts | 2 +- markets/aave/reservesConfigs.ts | 44 ++++---- markets/amm/commons.ts | 41 +++---- markets/amm/index.ts | 5 +- markets/matic/commons.ts | 2 + markets/xdai/commons.ts | 1 + tasks/dev/3_lending_pool.ts | 8 +- tasks/dev/4_oracles.ts | 25 +++-- tasks/dev/5_initialize.ts | 8 +- tasks/full/2_lending_pool.ts | 4 +- tasks/full/3_oracles.ts | 29 +++-- tasks/full/6-initialize.ts | 1 + tasks/helpers/deploy-new-asset.ts | 15 +-- 25 files changed, 592 insertions(+), 313 deletions(-) create mode 100644 contracts/misc/AaveOracleV2.sol diff --git a/contracts/misc/AaveOracleV2.sol b/contracts/misc/AaveOracleV2.sol new file mode 100644 index 00000000..8af3b08e --- /dev/null +++ b/contracts/misc/AaveOracleV2.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; + +import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; +import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; + +import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; +import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol'; +import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; + +/// @title AaveOracleV2 +/// @author Aave +/// @notice Proxy smart contract to get the price of an asset from a price source, with Chainlink Aggregator +/// smart contracts as primary option +/// - If the returned price by a Chainlink aggregator is <= 0, the call is forwarded to a fallbackOracle +/// - Owned by the Aave governance system, allowed to add sources for assets, replace them +/// and change the fallbackOracle +contract AaveOracleV2 is IPriceOracleGetter, Ownable { + using SafeERC20 for IERC20; + + event QuoteCurrencySet(address indexed quoteCurrency, uint256 quoteUnit); + event AssetSourceUpdated(address indexed asset, address indexed source); + event FallbackOracleUpdated(address indexed fallbackOracle); + + mapping(address => IChainlinkAggregator) private assetsSources; + IPriceOracleGetter private _fallbackOracle; + address public immutable QUOTE_CURRENCY; + uint256 public immutable QUOTE_CURRENCY_UNIT; + + /// @notice Constructor + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + /// @param fallbackOracle The address of the fallback oracle to use if the data of an + /// aggregator is not consistent + constructor( + address[] memory assets, + address[] memory sources, + address fallbackOracle, + address quoteCurrency, + uint256 quoteCurrencyUnits + ) public { + _setFallbackOracle(fallbackOracle); + _setAssetsSources(assets, sources); + QUOTE_CURRENCY = quoteCurrency; + QUOTE_CURRENCY_UNIT = quoteCurrencyUnits; + emit QuoteCurrencySet(quoteCurrency, quoteCurrencyUnits); + } + + /// @notice External function called by the Aave governance to set or replace sources of assets + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + function setAssetSources(address[] calldata assets, address[] calldata sources) + external + onlyOwner + { + _setAssetsSources(assets, sources); + } + + /// @notice Sets the fallbackOracle + /// - Callable only by the Aave governance + /// @param fallbackOracle The address of the fallbackOracle + function setFallbackOracle(address fallbackOracle) external onlyOwner { + _setFallbackOracle(fallbackOracle); + } + + /// @notice Internal function to set the sources for each asset + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + function _setAssetsSources(address[] memory assets, address[] memory sources) internal { + require(assets.length == sources.length, 'INCONSISTENT_PARAMS_LENGTH'); + for (uint256 i = 0; i < assets.length; i++) { + assetsSources[assets[i]] = IChainlinkAggregator(sources[i]); + emit AssetSourceUpdated(assets[i], sources[i]); + } + } + + /// @notice Internal function to set the fallbackOracle + /// @param fallbackOracle The address of the fallbackOracle + function _setFallbackOracle(address fallbackOracle) internal { + _fallbackOracle = IPriceOracleGetter(fallbackOracle); + emit FallbackOracleUpdated(fallbackOracle); + } + + /// @notice Gets an asset price by address + /// @param asset The asset address + function getAssetPrice(address asset) public view override returns (uint256) { + IChainlinkAggregator source = assetsSources[asset]; + + if (asset == QUOTE_CURRENCY) { + return QUOTE_CURRENCY_UNIT; + } else if (address(source) == address(0)) { + return _fallbackOracle.getAssetPrice(asset); + } else { + int256 price = IChainlinkAggregator(source).latestAnswer(); + if (price > 0) { + return uint256(price); + } else { + return _fallbackOracle.getAssetPrice(asset); + } + } + } + + /// @notice Gets a list of prices from a list of assets addresses + /// @param assets The list of assets addresses + function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) { + uint256[] memory prices = new uint256[](assets.length); + for (uint256 i = 0; i < assets.length; i++) { + prices[i] = getAssetPrice(assets[i]); + } + return prices; + } + + /// @notice Gets the address of the source for an asset address + /// @param asset The address of the asset + /// @return address The address of the source + function getSourceOfAsset(address asset) external view returns (address) { + return address(assetsSources[asset]); + } + + /// @notice Gets the address of the fallback oracle + /// @return address The addres of the fallback oracle + function getFallbackOracle() external view returns (address) { + return address(_fallbackOracle); + } +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 278577bb..cb1b9432 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -96,7 +96,7 @@ const buidlerConfig: HardhatUserConfig = { kovan: getCommonNetworkConfig(eEthereumNetwork.kovan, 42), ropsten: getCommonNetworkConfig(eEthereumNetwork.ropsten, 3), main: getCommonNetworkConfig(eEthereumNetwork.main, 1), - tenderlyMain: getCommonNetworkConfig(eEthereumNetwork.tenderlyMain, 3030), + tenderly: getCommonNetworkConfig(eEthereumNetwork.tenderly, 3030), matic: getCommonNetworkConfig(ePolygonNetwork.matic, 137), mumbai: getCommonNetworkConfig(ePolygonNetwork.mumbai, 80001), xdai: getCommonNetworkConfig(eXDaiNetwork.xdai, 100), diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index 3df38000..2cfe077b 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -45,7 +45,7 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { [eEthereumNetwork.coverage]: 'http://localhost:8555', [eEthereumNetwork.hardhat]: 'http://localhost:8545', [eEthereumNetwork.buidlerevm]: 'http://localhost:8545', - [eEthereumNetwork.tenderlyMain]: `https://rpc.tenderly.co/fork/${TENDERLY_FORK_ID}`, + [eEthereumNetwork.tenderly]: `https://rpc.tenderly.co/fork/`, [ePolygonNetwork.mumbai]: 'https://rpc-mumbai.maticvigil.com', [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', [eXDaiNetwork.xdai]: 'https://rpc.xdaichain.com/', @@ -58,7 +58,7 @@ export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { [eEthereumNetwork.coverage]: 65 * GWEI, [eEthereumNetwork.hardhat]: 65 * GWEI, [eEthereumNetwork.buidlerevm]: 65 * GWEI, - [eEthereumNetwork.tenderlyMain]: 0.01 * GWEI, + [eEthereumNetwork.tenderly]: 1 * GWEI, [ePolygonNetwork.mumbai]: 1 * GWEI, [ePolygonNetwork.matic]: 1 * GWEI, [eXDaiNetwork.xdai]: 1 * GWEI, @@ -71,7 +71,7 @@ export const BLOCK_TO_FORK: iParamsPerNetwork = { [eEthereumNetwork.coverage]: undefined, [eEthereumNetwork.hardhat]: undefined, [eEthereumNetwork.buidlerevm]: undefined, - [eEthereumNetwork.tenderlyMain]: 12406069, + [eEthereumNetwork.tenderly]: undefined, [ePolygonNetwork.mumbai]: undefined, [ePolygonNetwork.matic]: undefined, [eXDaiNetwork.xdai]: undefined, diff --git a/helpers/configuration.ts b/helpers/configuration.ts index 82e74e41..f22a2584 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -3,13 +3,14 @@ import { iMultiPoolsAssets, IReserveParams, PoolConfiguration, - ICommonConfiguration, eNetwork, + IBaseConfiguration, } from './types'; import { getEthersSignersAddresses, getParamPerPool } from './contracts-helpers'; import AaveConfig from '../markets/aave'; import MaticConfig from '../markets/matic'; import AmmConfig from '../markets/amm'; + import { CommonsConfig } from '../markets/aave/commons'; import { DRE, filterMapBy } from './misc-utils'; import { tEthereumAddress } from './types'; @@ -59,7 +60,7 @@ export const getReservesConfigByPool = (pool: AavePools): iMultiPoolsAssets => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const targetAddress = getParamPerNetwork(config.PoolAdmin, currentNetwork); @@ -71,9 +72,7 @@ export const getGenesisPoolAdmin = async ( return addressList[addressIndex]; }; -export const getEmergencyAdmin = async ( - config: ICommonConfiguration -): Promise => { +export const getEmergencyAdmin = async (config: IBaseConfiguration): Promise => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const targetAddress = getParamPerNetwork(config.EmergencyAdmin, currentNetwork); if (targetAddress) { @@ -84,19 +83,17 @@ export const getEmergencyAdmin = async ( return addressList[addressIndex]; }; -export const getTreasuryAddress = async ( - config: ICommonConfiguration -): Promise => { +export const getTreasuryAddress = async (config: IBaseConfiguration): Promise => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; return getParamPerNetwork(config.ReserveFactorTreasuryAddress, currentNetwork); }; export const getATokenDomainSeparatorPerNetwork = ( network: eNetwork, - config: ICommonConfiguration + config: IBaseConfiguration ): tEthereumAddress => getParamPerNetwork(config.ATokenDomainSeparator, network); -export const getWethAddress = async (config: ICommonConfiguration) => { +export const getWethAddress = async (config: IBaseConfiguration) => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const wethAddress = getParamPerNetwork(config.WETH, currentNetwork); if (wethAddress) { @@ -109,7 +106,7 @@ export const getWethAddress = async (config: ICommonConfiguration) => { return weth.address; }; -export const getWrappedNativeTokenAddress = async (config: ICommonConfiguration) => { +export const getWrappedNativeTokenAddress = async (config: IBaseConfiguration) => { const currentNetwork = process.env.MAINNET_FORK === 'true' ? 'main' : DRE.network.name; const wethAddress = getParamPerNetwork(config.WrappedNativeToken, currentNetwork); if (wethAddress) { @@ -122,7 +119,7 @@ export const getWrappedNativeTokenAddress = async (config: ICommonConfiguration) return weth.address; }; -export const getLendingRateOracles = (poolConfig: ICommonConfiguration) => { +export const getLendingRateOracles = (poolConfig: IBaseConfiguration) => { const { ProtocolGlobalParams: { UsdAddress }, LendingRateOracleRatesCommon, @@ -134,3 +131,15 @@ export const getLendingRateOracles = (poolConfig: ICommonConfiguration) => { Object.keys(ReserveAssets[network]).includes(key) ); }; + +export const getQuoteCurrency = async (config: IBaseConfiguration) => { + switch (config.OracleQuoteCurrency) { + case 'ETH': + case 'WETH': + return getWethAddress(config); + case 'USD': + return config.ProtocolGlobalParams.UsdAddress; + default: + throw `Quote ${config.OracleQuoteCurrency} currency not set. Add a new case to getQuoteCurrency switch`; + } +}; diff --git a/helpers/constants.ts b/helpers/constants.ts index 95e8922b..2ecf38dc 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -1,4 +1,5 @@ import BigNumber from 'bignumber.js'; +import { eEthereumNetwork } from './types'; // ---------------- // MATH @@ -12,6 +13,7 @@ export const RAY = new BigNumber(10).exponentiatedBy(27).toFixed(); export const HALF_RAY = new BigNumber(RAY).multipliedBy(0.5).toFixed(); export const WAD_RAY_RATIO = Math.pow(10, 9).toString(); export const oneEther = new BigNumber(Math.pow(10, 18)); +export const oneUsd = new BigNumber(Math.pow(10, 8)); export const oneRay = new BigNumber(Math.pow(10, 27)); export const MAX_UINT_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 2d764885..ef8c729e 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -1,5 +1,5 @@ import { Contract } from 'ethers'; -import { DRE } from './misc-utils'; +import { DRE, notFalsyOrZeroAddress } from './misc-utils'; import { tEthereumAddress, eContractid, @@ -13,9 +13,8 @@ import { } from './types'; import { MintableERC20 } from '../types/MintableERC20'; import { MockContract } from 'ethereum-waffle'; -import { getReservesConfigByPool } from './configuration'; +import { ConfigNames, getReservesConfigByPool, loadPoolConfig } from './configuration'; import { getFirstSigner } from './contracts-getters'; -import { ZERO_ADDRESS } from './constants'; import { AaveProtocolDataProviderFactory, ATokenFactory, @@ -49,6 +48,7 @@ import { WETH9MockedFactory, WETHGatewayFactory, FlashLiquidationAdapterFactory, + AaveOracleV2Factory, } from '../types'; import { withSaveAndVerify, @@ -57,6 +57,7 @@ import { insertContractAddressInDb, deployContract, verifyContract, + getOptionalParamAddressPerNetwork, } from './contracts-helpers'; import { StableAndVariableTokensHelperFactory } from '../types/StableAndVariableTokensHelperFactory'; import { MintableDelegationERC20 } from '../types/MintableDelegationERC20'; @@ -64,6 +65,7 @@ import { readArtifact as buidlerReadArtifact } from '@nomiclabs/buidler/plugins' import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { LendingPoolLibraryAddresses } from '../types/LendingPoolFactory'; import { UiPoolDataProvider } from '../types'; +import { eNetwork } from './types'; export const deployUiPoolDataProvider = async ( [incentivesController, aaveOracle]: [tEthereumAddress, tEthereumAddress], @@ -233,6 +235,17 @@ export const deployAaveOracle = async ( verify ); +export const deployAaveOracleV2 = async ( + args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress, string], + verify?: boolean +) => + withSaveAndVerify( + await new AaveOracleV2Factory(await getFirstSigner()).deploy(...args), + eContractid.AaveOracleV2, + args, + verify + ); + export const deployLendingPoolCollateralManager = async (verify?: boolean) => { const collateralManagerImpl = await new LendingPoolCollateralManagerFactory( await getFirstSigner() @@ -351,20 +364,20 @@ export const deployVariableDebtToken = async ( return instance; }; -export const deployGenericStableDebtToken = async () => +export const deployGenericStableDebtToken = async (verify?: boolean) => withSaveAndVerify( await new StableDebtTokenFactory(await getFirstSigner()).deploy(), eContractid.StableDebtToken, [], - false + verify ); -export const deployGenericVariableDebtToken = async () => +export const deployGenericVariableDebtToken = async (verify?: boolean) => withSaveAndVerify( await new VariableDebtTokenFactory(await getFirstSigner()).deploy(), eContractid.VariableDebtToken, [], - false + verify ); export const deployGenericAToken = async ( @@ -637,3 +650,75 @@ export const deployFlashLiquidationAdapter = async ( args, verify ); + +export const chooseATokenDeployment = (id: eContractid) => { + switch (id) { + case eContractid.AToken: + return deployGenericATokenImpl; + case eContractid.DelegationAwareAToken: + return deployDelegationAwareATokenImpl; + default: + throw Error(`Missing aToken implementation deployment script for: ${id}`); + } +}; + +export const deployATokenImplementations = async ( + pool: ConfigNames, + reservesConfig: { [key: string]: IReserveParams }, + verify = false +) => { + const poolConfig = loadPoolConfig(pool); + const network = DRE.network.name; + + // Obtain the different AToken implementations of all reserves inside the Market config + const aTokenImplementations = [ + ...Object.entries(reservesConfig).reduce>((acc, [, entry]) => { + acc.add(entry.aTokenImpl); + return acc; + }, new Set()), + ]; + + console.log(aTokenImplementations); + + for (let x = 0; x < aTokenImplementations.length; x++) { + const aTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig[aTokenImplementations[x].toString()], + network + ); + if (!notFalsyOrZeroAddress(aTokenAddress)) { + const deployImplementationMethod = chooseATokenDeployment(aTokenImplementations[x]); + console.log(`Deploying implementation`, aTokenImplementations[x]); + await deployImplementationMethod(verify); + } + } + + // Debt tokens, for now all Market configs follows same implementations + const genericStableDebtTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig.StableDebtTokenImplementation, + network + ); + const geneticVariableDebtTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig.VariableDebtTokenImplementation, + network + ); + + if (!notFalsyOrZeroAddress(genericStableDebtTokenAddress)) { + await deployGenericStableDebtToken(verify); + } + if (!notFalsyOrZeroAddress(geneticVariableDebtTokenAddress)) { + await deployGenericVariableDebtToken(verify); + } +}; + +export const deployRateStrategy = async ( + strategyName: string, + args: [tEthereumAddress, string, string, string, string, string, string], + verify: boolean +): Promise => { + switch (strategyName) { + default: + return await ( + await deployDefaultReserveInterestRateStrategy(args, verify) + ).address; + } +}; diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index b441363c..21641d97 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -33,7 +33,7 @@ import { } from '../types'; import { IERC20DetailedFactory } from '../types/IERC20DetailedFactory'; import { getEthersSigners, MockTokenMap } from './contracts-helpers'; -import { DRE, getDb, notFalsyOrZeroAddress } from './misc-utils'; +import { DRE, getDb, notFalsyOrZeroAddress, omit } from './misc-utils'; import { eContractid, PoolConfiguration, tEthereumAddress, TokenContractId } from './types'; export const getFirstSigner = async () => (await getEthersSigners())[0]; @@ -41,16 +41,18 @@ export const getFirstSigner = async () => (await getEthersSigners())[0]; export const getLendingPoolAddressesProvider = async (address?: tEthereumAddress) => { return await LendingPoolAddressesProviderFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); }; export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress) => { return await LendingPoolConfiguratorFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolConfigurator}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolConfigurator}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); }; @@ -58,14 +60,18 @@ export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress export const getLendingPool = async (address?: tEthereumAddress) => await LendingPoolFactory.connect( address || - (await getDb().get(`${eContractid.LendingPool}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingPool}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getPriceOracle = async (address?: tEthereumAddress) => await PriceOracleFactory.connect( address || - (await getDb().get(`${eContractid.PriceOracle}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.PriceOracle}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -78,36 +84,45 @@ export const getAToken = async (address?: tEthereumAddress) => export const getStableDebtToken = async (address?: tEthereumAddress) => await StableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.StableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.StableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getVariableDebtToken = async (address?: tEthereumAddress) => await VariableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.VariableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.VariableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getMintableERC20 = async (address: tEthereumAddress) => await MintableERC20Factory.connect( address || - (await getDb().get(`${eContractid.MintableERC20}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.MintableERC20}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getIErc20Detailed = async (address: tEthereumAddress) => await IERC20DetailedFactory.connect( address || - (await getDb().get(`${eContractid.IERC20Detailed}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.IERC20Detailed}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getAaveProtocolDataProvider = async (address?: tEthereumAddress) => await AaveProtocolDataProviderFactory.connect( address || - (await getDb().get(`${eContractid.AaveProtocolDataProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.AaveProtocolDataProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -125,15 +140,18 @@ export const getInterestRateStrategy = async (address?: tEthereumAddress) => export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => await MockFlashLoanReceiverFactory.connect( address || - (await getDb().get(`${eContractid.MockFlashLoanReceiver}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockFlashLoanReceiver}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingRateOracle = async (address?: tEthereumAddress) => await LendingRateOracleFactory.connect( address || - (await getDb().get(`${eContractid.LendingRateOracle}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingRateOracle}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -166,23 +184,37 @@ export const getAllMockedTokens = async () => { return tokens; }; +export const getQuoteCurrencies = (oracleQuoteCurrency: string): string[] => { + switch (oracleQuoteCurrency) { + case 'USD': + return ['USD']; + case 'ETH': + case 'WETH': + default: + return ['ETH', 'WETH']; + } +}; + export const getPairsTokenAggregator = ( allAssetsAddresses: { [tokenSymbol: string]: tEthereumAddress; }, - aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress } + aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress }, + oracleQuoteCurrency: string ): [string[], string[]] => { - const { ETH, WETH, ...assetsAddressesWithoutEth } = allAssetsAddresses; + const assetsWithoutQuoteCurrency = omit( + allAssetsAddresses, + getQuoteCurrencies(oracleQuoteCurrency) + ); - const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => { + const pairs = Object.entries(assetsWithoutQuoteCurrency).map(([tokenSymbol, tokenAddress]) => { //if (true/*tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH' && tokenSymbol !== 'LpWETH'*/) { const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( (value) => value === tokenSymbol ); - const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ - string, - tEthereumAddress - ][])[aggregatorAddressIndex]; + const [, aggregatorAddress] = ( + Object.entries(aggregatorsAddresses) as [string, tEthereumAddress][] + )[aggregatorAddressIndex]; return [tokenAddress, aggregatorAddress]; //} }) as [string, string][]; @@ -208,14 +240,18 @@ export const getLendingPoolAddressesProviderRegistry = async (address?: tEthereu export const getReserveLogic = async (address?: tEthereumAddress) => await ReserveLogicFactory.connect( address || - (await getDb().get(`${eContractid.ReserveLogic}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.ReserveLogic}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getGenericLogic = async (address?: tEthereumAddress) => await GenericLogicFactory.connect( address || - (await getDb().get(`${eContractid.GenericLogic}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.GenericLogic}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -233,15 +269,18 @@ export const getStableAndVariableTokensHelper = async (address?: tEthereumAddres export const getATokensAndRatesHelper = async (address?: tEthereumAddress) => await ATokensAndRatesHelperFactory.connect( address || - (await getDb().get(`${eContractid.ATokensAndRatesHelper}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.ATokensAndRatesHelper}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getWETHGateway = async (address?: tEthereumAddress) => await WETHGatewayFactory.connect( address || - (await getDb().get(`${eContractid.WETHGateway}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.WETHGateway}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -260,23 +299,27 @@ export const getMockAToken = async (address?: tEthereumAddress) => export const getMockVariableDebtToken = async (address?: tEthereumAddress) => await MockVariableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.MockVariableDebtToken}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockVariableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getMockStableDebtToken = async (address?: tEthereumAddress) => await MockStableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.MockStableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.MockStableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getSelfdestructTransferMock = async (address?: tEthereumAddress) => await SelfdestructTransferFactory.connect( address || - (await getDb().get(`${eContractid.SelfdestructTransferMock}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.SelfdestructTransferMock}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -286,15 +329,18 @@ export const getProxy = async (address: tEthereumAddress) => export const getLendingPoolImpl = async (address?: tEthereumAddress) => await LendingPoolFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolImpl}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingPoolImpl}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingPoolConfiguratorImpl = async (address?: tEthereumAddress) => await LendingPoolConfiguratorFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolConfiguratorImpl}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolConfiguratorImpl}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -312,16 +358,18 @@ export const getLendingPoolCollateralManagerImpl = async (address?: tEthereumAdd export const getWalletProvider = async (address?: tEthereumAddress) => await WalletBalanceProviderFactory.connect( address || - (await getDb().get(`${eContractid.WalletBalanceProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.WalletBalanceProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingPoolCollateralManager = async (address?: tEthereumAddress) => await LendingPoolCollateralManagerFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolCollateralManager}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolCollateralManager}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -337,30 +385,35 @@ export const getAaveOracle = async (address?: tEthereumAddress) => export const getMockUniswapRouter = async (address?: tEthereumAddress) => await MockUniswapV2Router02Factory.connect( address || - (await getDb().get(`${eContractid.MockUniswapV2Router02}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockUniswapV2Router02}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getUniswapLiquiditySwapAdapter = async (address?: tEthereumAddress) => await UniswapLiquiditySwapAdapterFactory.connect( address || - (await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getUniswapRepayAdapter = async (address?: tEthereumAddress) => await UniswapRepayAdapterFactory.connect( address || - (await getDb().get(`${eContractid.UniswapRepayAdapter}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.UniswapRepayAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getFlashLiquidationAdapter = async (address?: tEthereumAddress) => await FlashLiquidationAdapterFactory.connect( address || - (await getDb().get(`${eContractid.FlashLiquidationAdapter}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.FlashLiquidationAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index cb7c016e..e7a4edbb 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -2,7 +2,7 @@ import { Contract, Signer, utils, ethers, BigNumberish } from 'ethers'; import { signTypedData_v4 } from 'eth-sig-util'; import { fromRpcSig, ECDSASignature } from 'ethereumjs-util'; import BigNumber from 'bignumber.js'; -import { getDb, DRE, waitForTx } from './misc-utils'; +import { getDb, DRE, waitForTx, notFalsyOrZeroAddress } from './misc-utils'; import { tEthereumAddress, eContractid, @@ -14,7 +14,6 @@ import { ePolygonNetwork, eXDaiNetwork, eNetwork, - iParamsPerNetworkAll, iEthereumParamsPerNetwork, iPolygonParamsPerNetwork, iXDaiParamsPerNetwork, @@ -26,6 +25,8 @@ import { verifyEtherscanContract } from './etherscan-verification'; import { getFirstSigner, getIErc20Detailed } from './contracts-getters'; import { usingTenderly, verifyAtTenderly } from './tenderly-utils'; import { usingPolygon, verifyAtPolygon } from './polygon-utils'; +import { ConfigNames, loadPoolConfig } from './configuration'; +import { ZERO_ADDRESS } from './constants'; import { getDefenderRelaySigner, usingDefender } from './defender-utils'; export type MockTokenMap = { [symbol: string]: MintableERC20 }; @@ -142,14 +143,8 @@ export const linkBytecode = (artifact: BuidlerArtifact | Artifact, libraries: an }; export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNetwork) => { - const { - main, - ropsten, - kovan, - coverage, - buidlerevm, - tenderlyMain, - } = param as iEthereumParamsPerNetwork; + const { main, ropsten, kovan, coverage, buidlerevm, tenderly } = + param as iEthereumParamsPerNetwork; const { matic, mumbai } = param as iPolygonParamsPerNetwork; const { xdai } = param as iXDaiParamsPerNetwork; if (process.env.FORK) { @@ -169,8 +164,8 @@ export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNet return ropsten; case eEthereumNetwork.main: return main; - case eEthereumNetwork.tenderlyMain: - return tenderlyMain; + case eEthereumNetwork.tenderly: + return tenderly; case ePolygonNetwork.matic: return matic; case ePolygonNetwork.mumbai: @@ -180,6 +175,16 @@ export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNet } }; +export const getOptionalParamAddressPerNetwork = ( + param: iParamsPerNetwork | undefined | null, + network: eNetwork +) => { + if (!param) { + return ZERO_ADDRESS; + } + return getParamPerNetwork(param, network); +}; + export const getParamPerPool = ({ proto, amm, matic }: iParamsPerPool, pool: AavePools) => { switch (pool) { case AavePools.proto: @@ -342,3 +347,23 @@ export const verifyContract = async ( } return instance; }; + +export const getContractAddressWithJsonFallback = async ( + id: string, + pool: ConfigNames +): Promise => { + const poolConfig = loadPoolConfig(pool); + const network = DRE.network.name; + const db = getDb(); + + const contractAtMarketConfig = getOptionalParamAddressPerNetwork(poolConfig[id], network); + if (notFalsyOrZeroAddress(contractAtMarketConfig)) { + return contractAtMarketConfig; + } + + const contractAtDb = await getDb().get(`${id}.${DRE.network.name}`).value(); + if (contractAtDb?.address) { + return contractAtDb.address as tEthereumAddress; + } + throw Error(`Missing contract address ${id} at Market config and JSON local db`); +}; diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index aa209583..45cc3972 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -1,48 +1,31 @@ import { eContractid, - eEthereumNetwork, eNetwork, iMultiPoolsAssets, IReserveParams, tEthereumAddress, } from './types'; import { AaveProtocolDataProvider } from '../types/AaveProtocolDataProvider'; -import { chunk, DRE, getDb, waitForTx } from './misc-utils'; +import { chunk, getDb, waitForTx } from './misc-utils'; import { - getAaveProtocolDataProvider, getAToken, getATokensAndRatesHelper, - getFirstSigner, getLendingPoolAddressesProvider, getLendingPoolConfiguratorProxy, - getStableAndVariableTokensHelper, } from './contracts-getters'; -import { rawInsertContractAddressInDb } from './contracts-helpers'; -import { BigNumber, BigNumberish, Signer } from 'ethers'; import { - deployDefaultReserveInterestRateStrategy, - deployDelegationAwareAToken, - deployDelegationAwareATokenImpl, - deployGenericAToken, - deployGenericATokenImpl, - deployGenericStableDebtToken, - deployGenericVariableDebtToken, - deployStableDebtToken, - deployVariableDebtToken, -} from './contracts-deployments'; -import { ZERO_ADDRESS } from './constants'; -import { isZeroAddress } from 'ethereumjs-util'; -import { DefaultReserveInterestRateStrategy, DelegationAwareAToken } from '../types'; -import { config } from 'process'; + getContractAddressWithJsonFallback, + rawInsertContractAddressInDb, +} from './contracts-helpers'; +import { BigNumberish } from 'ethers'; +import { ConfigNames } from './configuration'; +import { deployRateStrategy } from './contracts-deployments'; -export const chooseATokenDeployment = (id: eContractid) => { - switch (id) { - case eContractid.AToken: - return deployGenericAToken; - case eContractid.DelegationAwareAToken: - return deployDelegationAwareAToken; +export const getATokenExtraParams = async (aTokenName: string, tokenAddress: tEthereumAddress) => { + console.log(aTokenName); + switch (aTokenName) { default: - throw Error(`Missing aToken deployment script for: ${id}`); + return '0x10'; } }; @@ -56,19 +39,15 @@ export const initReservesByHelper = async ( admin: tEthereumAddress, treasuryAddress: tEthereumAddress, incentivesController: tEthereumAddress, + poolName: ConfigNames, verify: boolean -): Promise => { - let gasUsage = BigNumber.from('0'); - const stableAndVariableDeployer = await getStableAndVariableTokensHelper(); - +) => { const addressProvider = await getLendingPoolAddressesProvider(); // CHUNK CONFIGURATION - const initChunks = 4; + const initChunks = 1; // Initialize variables for future reserves initialization - let reserveTokens: string[] = []; - let reserveInitDecimals: string[] = []; let reserveSymbols: string[] = []; let initInputParams: { @@ -101,49 +80,8 @@ export const initReservesByHelper = async ( ]; let rateStrategies: Record = {}; let strategyAddresses: Record = {}; - let strategyAddressPerAsset: Record = {}; - let aTokenType: Record = {}; - let delegationAwareATokenImplementationAddress = ''; - let aTokenImplementationAddress = ''; - let stableDebtTokenImplementationAddress = ''; - let variableDebtTokenImplementationAddress = ''; - // NOT WORKING ON MATIC, DEPLOYING INDIVIDUAL IMPLs INSTEAD - // const tx1 = await waitForTx( - // await stableAndVariableDeployer.initDeployment([ZERO_ADDRESS], ["1"]) - // ); - // console.log(tx1.events); - // tx1.events?.forEach((event, index) => { - // stableDebtTokenImplementationAddress = event?.args?.stableToken; - // variableDebtTokenImplementationAddress = event?.args?.variableToken; - // rawInsertContractAddressInDb(`stableDebtTokenImpl`, stableDebtTokenImplementationAddress); - // rawInsertContractAddressInDb(`variableDebtTokenImpl`, variableDebtTokenImplementationAddress); - // }); - //gasUsage = gasUsage.add(tx1.gasUsed); - stableDebtTokenImplementationAddress = await (await deployGenericStableDebtToken()).address; - variableDebtTokenImplementationAddress = await (await deployGenericVariableDebtToken()).address; - - const aTokenImplementation = await deployGenericATokenImpl(verify); - aTokenImplementationAddress = aTokenImplementation.address; - rawInsertContractAddressInDb(`aTokenImpl`, aTokenImplementationAddress); - - const delegatedAwareReserves = Object.entries(reservesParams).filter( - ([_, { aTokenImpl }]) => aTokenImpl === eContractid.DelegationAwareAToken - ) as [string, IReserveParams][]; - - if (delegatedAwareReserves.length > 0) { - const delegationAwareATokenImplementation = await deployDelegationAwareATokenImpl(verify); - delegationAwareATokenImplementationAddress = delegationAwareATokenImplementation.address; - rawInsertContractAddressInDb( - `delegationAwareATokenImpl`, - delegationAwareATokenImplementationAddress - ); - } - - const reserves = Object.entries(reservesParams).filter( - ([_, { aTokenImpl }]) => - aTokenImpl === eContractid.DelegationAwareAToken || aTokenImpl === eContractid.AToken - ) as [string, IReserveParams][]; + const reserves = Object.entries(reservesParams); for (let [symbol, params] of reserves) { if (!tokenAddresses[symbol]) { @@ -170,52 +108,41 @@ export const initReservesByHelper = async ( stableRateSlope1, stableRateSlope2, ]; - strategyAddresses[strategy.name] = ( - await deployDefaultReserveInterestRateStrategy(rateStrategies[strategy.name], verify) - ).address; + strategyAddresses[strategy.name] = await deployRateStrategy( + strategy.name, + rateStrategies[strategy.name], + verify + ); + // This causes the last strategy to be printed twice, once under "DefaultReserveInterestRateStrategy" // and once under the actual `strategyASSET` key. rawInsertContractAddressInDb(strategy.name, strategyAddresses[strategy.name]); } - strategyAddressPerAsset[symbol] = strategyAddresses[strategy.name]; - console.log('Strategy address for asset %s: %s', symbol, strategyAddressPerAsset[symbol]); - - if (aTokenImpl === eContractid.AToken) { - aTokenType[symbol] = 'generic'; - } else if (aTokenImpl === eContractid.DelegationAwareAToken) { - aTokenType[symbol] = 'delegation aware'; - } - - reserveInitDecimals.push(reserveDecimals); - reserveTokens.push(tokenAddresses[symbol]); + // Prepare input parameters reserveSymbols.push(symbol); - } - - for (let i = 0; i < reserveSymbols.length; i++) { - let aTokenToUse: string; - if (aTokenType[reserveSymbols[i]] === 'generic') { - aTokenToUse = aTokenImplementationAddress; - } else { - aTokenToUse = delegationAwareATokenImplementationAddress; - } - initInputParams.push({ - aTokenImpl: aTokenToUse, - stableDebtTokenImpl: stableDebtTokenImplementationAddress, - variableDebtTokenImpl: variableDebtTokenImplementationAddress, - underlyingAssetDecimals: reserveInitDecimals[i], - interestRateStrategyAddress: strategyAddressPerAsset[reserveSymbols[i]], - underlyingAsset: reserveTokens[i], + aTokenImpl: await getContractAddressWithJsonFallback(aTokenImpl, poolName), + stableDebtTokenImpl: await getContractAddressWithJsonFallback( + eContractid.StableDebtToken, + poolName + ), + variableDebtTokenImpl: await getContractAddressWithJsonFallback( + eContractid.VariableDebtToken, + poolName + ), + underlyingAssetDecimals: reserveDecimals, + interestRateStrategyAddress: strategyAddresses[strategy.name], + underlyingAsset: tokenAddresses[symbol], treasury: treasuryAddress, - incentivesController, - underlyingAssetName: reserveSymbols[i], - aTokenName: `${aTokenNamePrefix} ${reserveSymbols[i]}`, - aTokenSymbol: `a${symbolPrefix}${reserveSymbols[i]}`, - variableDebtTokenName: `${variableDebtTokenNamePrefix} ${symbolPrefix}${reserveSymbols[i]}`, - variableDebtTokenSymbol: `variableDebt${symbolPrefix}${reserveSymbols[i]}`, - stableDebtTokenName: `${stableDebtTokenNamePrefix} ${reserveSymbols[i]}`, - stableDebtTokenSymbol: `stableDebt${symbolPrefix}${reserveSymbols[i]}`, - params: '0x10', + incentivesController: incentivesController, + underlyingAssetName: symbol, + aTokenName: `${aTokenNamePrefix} ${symbol}`, + aTokenSymbol: `a${symbolPrefix}${symbol}`, + variableDebtTokenName: `${variableDebtTokenNamePrefix} ${symbolPrefix}${symbol}`, + variableDebtTokenSymbol: `variableDebt${symbolPrefix}${symbol}`, + stableDebtTokenName: `${stableDebtTokenNamePrefix} ${symbol}`, + stableDebtTokenSymbol: `stableDebt${symbolPrefix}${symbol}`, + params: await getATokenExtraParams(aTokenImpl, tokenAddresses[symbol]), }); } @@ -224,7 +151,6 @@ export const initReservesByHelper = async ( const chunkedInitInputParams = chunk(initInputParams, initChunks); const configurator = await getLendingPoolConfiguratorProxy(); - //await waitForTx(await addressProvider.setPoolAdmin(admin)); console.log(`- Reserves initialization in ${chunkedInitInputParams.length} txs`); for (let chunkIndex = 0; chunkIndex < chunkedInitInputParams.length; chunkIndex++) { @@ -234,10 +160,7 @@ export const initReservesByHelper = async ( console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`); console.log(' * gasUsed', tx3.gasUsed.toString()); - //gasUsage = gasUsage.add(tx3.gasUsed); } - - return gasUsage; // Deprecated }; export const getPairsTokenAggregator = ( @@ -253,10 +176,9 @@ export const getPairsTokenAggregator = ( const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( (value) => value === tokenSymbol ); - const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ - string, - tEthereumAddress - ][])[aggregatorAddressIndex]; + const [, aggregatorAddress] = ( + Object.entries(aggregatorsAddresses) as [string, tEthereumAddress][] + )[aggregatorAddressIndex]; return [tokenAddress, aggregatorAddress]; } }) as [string, string][]; diff --git a/helpers/misc-utils.ts b/helpers/misc-utils.ts index 0315dfe0..c0456a0c 100644 --- a/helpers/misc-utils.ts +++ b/helpers/misc-utils.ts @@ -9,6 +9,8 @@ import { BuidlerRuntimeEnvironment } from '@nomiclabs/buidler/types'; import { tEthereumAddress } from './types'; import { isAddress } from 'ethers/lib/utils'; import { isZeroAddress } from 'ethereumjs-util'; +import { SignerWithAddress } from '../test-suites/test-aave/helpers/make-suite'; +import { usingTenderly } from './tenderly-utils'; export const toWad = (value: string | number) => new BigNumber(value).times(WAD).toFixed(); @@ -116,6 +118,27 @@ export const notFalsyOrZeroAddress = (address: tEthereumAddress | null | undefin return isAddress(address) && !isZeroAddress(address); }; +export const impersonateAddress = async (address: tEthereumAddress): Promise => { + if (!usingTenderly()) { + await (DRE as HardhatRuntimeEnvironment).network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [address], + }); + } + const signer = await DRE.ethers.provider.getSigner(address); + + return { + signer, + address, + }; +}; + +export const omit = (obj: T, keys: U[]): Omit => + (Object.keys(obj) as U[]).reduce( + (acc, curr) => (keys.includes(curr) ? acc : { ...acc, [curr]: obj[curr] }), + {} as Omit + ); + export const impersonateAccountsHardhat = async (accounts: string[]) => { if (process.env.TENDERLY === 'true') { return; diff --git a/helpers/types.ts b/helpers/types.ts index 267b5abb..7b68e146 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -13,7 +13,7 @@ export enum eEthereumNetwork { main = 'main', coverage = 'coverage', hardhat = 'hardhat', - tenderlyMain = 'tenderlyMain', + tenderly = 'tenderly', } export enum ePolygonNetwork { @@ -87,6 +87,7 @@ export enum eContractid { UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter', UniswapRepayAdapter = 'UniswapRepayAdapter', FlashLiquidationAdapter = 'FlashLiquidationAdapter', + AaveOracleV2 = 'AaveOracleV2', } /* @@ -408,7 +409,7 @@ export interface iEthereumParamsPerNetwork { [eEthereumNetwork.ropsten]: T; [eEthereumNetwork.main]: T; [eEthereumNetwork.hardhat]: T; - [eEthereumNetwork.tenderlyMain]: T; + [eEthereumNetwork.tenderly]: T; } export interface iPolygonParamsPerNetwork { @@ -462,7 +463,7 @@ export interface ILendingRate { borrowRate: string; } -export interface ICommonConfiguration { +export interface IBaseConfiguration { MarketId: string; ATokenNamePrefix: string; StableDebtTokenNamePrefix: string; @@ -470,7 +471,6 @@ export interface ICommonConfiguration { SymbolPrefix: string; ProviderId: number; ProtocolGlobalParams: IProtocolGlobalConfig; - Mocks: IMocksConfig; ProviderRegistry: iParamsPerNetwork; ProviderRegistryOwner: iParamsPerNetwork; LendingPoolCollateralManager: iParamsPerNetwork; @@ -486,14 +486,22 @@ export interface ICommonConfiguration { PoolAdminIndex: number; EmergencyAdmin: iParamsPerNetwork; EmergencyAdminIndex: number; - ReserveAssets: iParamsPerNetwork>; - ReservesConfig: iMultiPoolsAssets; ATokenDomainSeparator: iParamsPerNetwork; WETH: iParamsPerNetwork; WrappedNativeToken: iParamsPerNetwork; WethGateway: iParamsPerNetwork; ReserveFactorTreasuryAddress: iParamsPerNetwork; IncentivesController: iParamsPerNetwork; + StableDebtTokenImplementation?: iParamsPerNetwork; + VariableDebtTokenImplementation?: iParamsPerNetwork; + ReserveAssets: iParamsPerNetwork>; + OracleQuoteCurrency: string; + OracleQuoteUnit: string; +} + +export interface ICommonConfiguration extends IBaseConfiguration { + ReservesConfig: iMultiPoolsAssets; + Mocks: IMocksConfig; } export interface IAaveConfiguration extends ICommonConfiguration { diff --git a/markets/aave/commons.ts b/markets/aave/commons.ts index 134e37eb..d0a34bcd 100644 --- a/markets/aave/commons.ts +++ b/markets/aave/commons.ts @@ -1,10 +1,8 @@ -import BigNumber from 'bignumber.js'; import { - oneEther, oneRay, - RAY, ZERO_ADDRESS, MOCK_CHAINLINK_AGGREGATORS_PRICES, + oneEther, } from '../../helpers/constants'; import { ICommonConfiguration, eEthereumNetwork } from '../../helpers/types'; @@ -19,6 +17,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave variable debt bearing', SymbolPrefix: '', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', @@ -113,7 +113,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, PoolAdminIndex: 0, EmergencyAdmin: { @@ -123,7 +123,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, EmergencyAdminIndex: 1, ProviderRegistry: { @@ -133,7 +133,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', + [eEthereumNetwork.tenderly]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', }, ProviderRegistryOwner: { [eEthereumNetwork.kovan]: '0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F', @@ -142,7 +142,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', + [eEthereumNetwork.tenderly]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', }, LendingRateOracle: { [eEthereumNetwork.coverage]: '', @@ -151,7 +151,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', //'0xdCde9Bb6a49e37fA433990832AB541AE2d4FEB4a', [eEthereumNetwork.ropsten]: '0x05dcca805a6562c1bdd0423768754acb6993241b', [eEthereumNetwork.main]: '', //'0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', - [eEthereumNetwork.tenderlyMain]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', + [eEthereumNetwork.tenderly]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', }, LendingPoolCollateralManager: { [eEthereumNetwork.coverage]: '', @@ -160,7 +160,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x9269b6453d0d75370c4c85e5a42977a53efdb72a', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', - [eEthereumNetwork.tenderlyMain]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', + [eEthereumNetwork.tenderly]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', }, LendingPoolConfigurator: { [eEthereumNetwork.coverage]: '', @@ -169,7 +169,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, LendingPool: { [eEthereumNetwork.coverage]: '', @@ -178,7 +178,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WethGateway: { [eEthereumNetwork.coverage]: '', @@ -187,7 +187,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, TokenDistributor: { [eEthereumNetwork.coverage]: '', @@ -196,7 +196,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x971efe90088f21dc6a36f610ffed77fc19710708', [eEthereumNetwork.ropsten]: '0xeba2ea67942b8250d870b12750b594696d02fc9c', [eEthereumNetwork.main]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', - [eEthereumNetwork.tenderlyMain]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', + [eEthereumNetwork.tenderly]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', }, AaveOracle: { [eEthereumNetwork.coverage]: '', @@ -205,7 +205,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', //'0xB8bE51E6563BB312Cbb2aa26e352516c25c26ac1', [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: '', //'0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', - [eEthereumNetwork.tenderlyMain]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', + [eEthereumNetwork.tenderly]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', }, FallbackOracle: { [eEthereumNetwork.coverage]: '', @@ -214,7 +214,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x50913E8E1c650E790F8a1E741FF9B1B1bB251dfe', [eEthereumNetwork.ropsten]: '0xAD1a978cdbb8175b2eaeC47B01404f8AEC5f4F0d', [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, ChainlinkAggregator: { [eEthereumNetwork.coverage]: {}, @@ -287,7 +287,7 @@ export const CommonsConfig: ICommonConfiguration = { USD: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419', xSUSHI: '0x9b26214bEC078E68a394AaEbfbffF406Ce14893F', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { AAVE: '0x6Df09E975c830ECae5bd4eD9d90f3A95a4f88012', BAT: '0x0d16d4528239e9ee52fa531af613AcdB23D88c94', BUSD: '0x614715d2Af89E6EC99A233818275142cE88d1Cfd', @@ -318,7 +318,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.main]: {}, [eEthereumNetwork.kovan]: {}, [eEthereumNetwork.ropsten]: {}, - [eEthereumNetwork.tenderlyMain]: {}, + [eEthereumNetwork.tenderly]: {}, }, ReservesConfig: {}, ATokenDomainSeparator: { @@ -331,7 +331,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WETH: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -340,7 +340,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, WrappedNativeToken: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -349,7 +349,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, ReserveFactorTreasuryAddress: { [eEthereumNetwork.coverage]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', @@ -358,7 +358,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.ropsten]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.main]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', - [eEthereumNetwork.tenderlyMain]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', + [eEthereumNetwork.tenderly]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', }, IncentivesController: { [eEthereumNetwork.coverage]: ZERO_ADDRESS, @@ -367,6 +367,6 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: ZERO_ADDRESS, [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, }; diff --git a/markets/aave/index.ts b/markets/aave/index.ts index 2ff2be79..72f25152 100644 --- a/markets/aave/index.ts +++ b/markets/aave/index.ts @@ -128,7 +128,7 @@ export const AaveConfig: IAaveConfiguration = { ZRX: '0xE41d2489571d322189246DaFA5ebDe1F4699F498', xSUSHI: '0x8798249c2E607446EfB7Ad49eC89dD1865Ff4272', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { AAVE: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', BAT: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', BUSD: '0x4Fabb145d64652a948d72533023f6E7A623C7C53', diff --git a/markets/aave/reservesConfigs.ts b/markets/aave/reservesConfigs.ts index a29e16d7..b41ae417 100644 --- a/markets/aave/reservesConfigs.ts +++ b/markets/aave/reservesConfigs.ts @@ -1,6 +1,6 @@ import { eContractid, IReserveParams } from '../../helpers/types'; -import { +import { rateStrategyStableOne, rateStrategyStableTwo, rateStrategyStableThree, @@ -21,7 +21,7 @@ export const strategyBUSD: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyDAI: IReserveParams = { @@ -33,7 +33,7 @@ export const strategyDAI: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategySUSD: IReserveParams = { @@ -45,7 +45,7 @@ export const strategySUSD: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyTUSD: IReserveParams = { @@ -57,7 +57,7 @@ export const strategyTUSD: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyUSDC: IReserveParams = { @@ -69,7 +69,7 @@ export const strategyUSDC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyUSDT: IReserveParams = { @@ -81,7 +81,7 @@ export const strategyUSDT: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyAAVE: IReserveParams = { @@ -93,7 +93,7 @@ export const strategyAAVE: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '0' + reserveFactor: '0', }; export const strategyBAT: IReserveParams = { @@ -105,7 +105,7 @@ export const strategyBAT: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyENJ: IReserveParams = { @@ -117,7 +117,7 @@ export const strategyENJ: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyWETH: IReserveParams = { @@ -129,7 +129,7 @@ export const strategyWETH: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyKNC: IReserveParams = { @@ -141,7 +141,7 @@ export const strategyKNC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyLINK: IReserveParams = { @@ -153,7 +153,7 @@ export const strategyLINK: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyMANA: IReserveParams = { @@ -165,7 +165,7 @@ export const strategyMANA: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '3500' + reserveFactor: '3500', }; export const strategyMKR: IReserveParams = { @@ -177,7 +177,7 @@ export const strategyMKR: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyREN: IReserveParams = { @@ -189,7 +189,7 @@ export const strategyREN: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategySNX: IReserveParams = { @@ -201,7 +201,7 @@ export const strategySNX: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '3500' + reserveFactor: '3500', }; // Invalid borrow rates in params currently, replaced with snx params @@ -214,7 +214,7 @@ export const strategyUNI: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.DelegationAwareAToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyWBTC: IReserveParams = { @@ -226,7 +226,7 @@ export const strategyWBTC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '8', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyYFI: IReserveParams = { @@ -238,7 +238,7 @@ export const strategyYFI: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyZRX: IReserveParams = { @@ -250,7 +250,7 @@ export const strategyZRX: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyXSUSHI: IReserveParams = { @@ -263,4 +263,4 @@ export const strategyXSUSHI: IReserveParams = { reserveDecimals: '18', aTokenImpl: eContractid.AToken, reserveFactor: '3500', -}; \ No newline at end of file +}; diff --git a/markets/amm/commons.ts b/markets/amm/commons.ts index 8be1f2c0..39fca1d0 100644 --- a/markets/amm/commons.ts +++ b/markets/amm/commons.ts @@ -5,6 +5,7 @@ import { RAY, ZERO_ADDRESS, MOCK_CHAINLINK_AGGREGATORS_PRICES, + oneUsd, } from '../../helpers/constants'; import { ICommonConfiguration, eEthereumNetwork } from '../../helpers/types'; @@ -19,6 +20,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave AMM Market variable debt', SymbolPrefix: 'Amm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', @@ -116,7 +119,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, PoolAdminIndex: 0, EmergencyAdmin: { @@ -126,7 +129,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, EmergencyAdminIndex: 1, ProviderRegistry: { @@ -136,7 +139,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', + [eEthereumNetwork.tenderly]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', }, ProviderRegistryOwner: { [eEthereumNetwork.kovan]: '0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F', @@ -145,7 +148,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', + [eEthereumNetwork.tenderly]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', }, LendingRateOracle: { [eEthereumNetwork.coverage]: '', @@ -154,7 +157,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd00Bd28FAdDa9d5658D1D4e0c151973146C7A533', //'0xE48F95873855bfd97BF89572DDf5cBC44D9c545b' [eEthereumNetwork.ropsten]: '0x05dcca805a6562c1bdd0423768754acb6993241b', [eEthereumNetwork.main]: '', //'0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', // Need to re-deploy because of onlyOwner - [eEthereumNetwork.tenderlyMain]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', + [eEthereumNetwork.tenderly]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', }, LendingPoolCollateralManager: { [eEthereumNetwork.coverage]: '', @@ -163,7 +166,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x9269b6453d0d75370c4c85e5a42977a53efdb72a', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', - [eEthereumNetwork.tenderlyMain]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', + [eEthereumNetwork.tenderly]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', }, LendingPoolConfigurator: { [eEthereumNetwork.coverage]: '', @@ -172,7 +175,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x36eB31800aa67a9c50df1d56EE01981A6E14Cce5', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, LendingPool: { [eEthereumNetwork.coverage]: '', @@ -181,7 +184,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x78142De7a1930412E9e50dEB3b80dB284c2dFa3A', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WethGateway: { [eEthereumNetwork.coverage]: '', @@ -190,7 +193,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x1c4A1cC35A477aa1cF35DF671d93ACc04d8131E0', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, TokenDistributor: { [eEthereumNetwork.coverage]: '', @@ -199,7 +202,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x971efe90088f21dc6a36f610ffed77fc19710708', [eEthereumNetwork.ropsten]: '0xeba2ea67942b8250d870b12750b594696d02fc9c', [eEthereumNetwork.main]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', - [eEthereumNetwork.tenderlyMain]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', + [eEthereumNetwork.tenderly]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', }, AaveOracle: { [eEthereumNetwork.coverage]: '', @@ -208,7 +211,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x8fb777d67e9945e2c01936e319057f9d41d559e6', // Need to re-deploy because of onlyOwner [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: '', //'0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', // Need to re-deploy because of onlyOwner - [eEthereumNetwork.tenderlyMain]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', + [eEthereumNetwork.tenderly]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', }, FallbackOracle: { [eEthereumNetwork.coverage]: '', @@ -217,7 +220,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x50913E8E1c650E790F8a1E741FF9B1B1bB251dfe', [eEthereumNetwork.ropsten]: '0xAD1a978cdbb8175b2eaeC47B01404f8AEC5f4F0d', [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, ChainlinkAggregator: { [eEthereumNetwork.coverage]: {}, @@ -270,7 +273,7 @@ export const CommonsConfig: ICommonConfiguration = { BptBALWETH: '0x2e4e78936b100be6Ef85BCEf7FB25bC770B02B85', USD: '0x9326BFA02ADD2366b30bacB125260Af641031331', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { USDT: '0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46', WBTC: '0xdeb288F737066589598e9214E782fa5A8eD689e8', USDC: '0x986b5E1e1755e3C2440e960477f25201B0a8bbD4', @@ -301,7 +304,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.main]: {}, [eEthereumNetwork.kovan]: {}, [eEthereumNetwork.ropsten]: {}, - [eEthereumNetwork.tenderlyMain]: {}, + [eEthereumNetwork.tenderly]: {}, }, ReservesConfig: {}, ATokenDomainSeparator: { @@ -314,7 +317,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WETH: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -323,7 +326,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, WrappedNativeToken: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -332,7 +335,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, ReserveFactorTreasuryAddress: { [eEthereumNetwork.coverage]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', @@ -341,7 +344,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.ropsten]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.main]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', - [eEthereumNetwork.tenderlyMain]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', + [eEthereumNetwork.tenderly]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', }, IncentivesController: { [eEthereumNetwork.coverage]: ZERO_ADDRESS, @@ -350,6 +353,6 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: ZERO_ADDRESS, [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, }; diff --git a/markets/amm/index.ts b/markets/amm/index.ts index e42dbdec..37bc46b6 100644 --- a/markets/amm/index.ts +++ b/markets/amm/index.ts @@ -83,8 +83,7 @@ export const AmmConfig: IAmmConfiguration = { BptWBTCWETH: '0x110569E3261bC0934dA637b019f6f1b6F50ec574', BptBALWETH: '0xad01D8e0Fa9EAA8Fe76dA30CFb1BCe12707aE6c5', }, - [eEthereumNetwork.ropsten]: { - }, + [eEthereumNetwork.ropsten]: {}, [eEthereumNetwork.main]: { DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', @@ -108,7 +107,7 @@ export const AmmConfig: IAmmConfiguration = { BptWBTCWETH: '0x1efF8aF5D577060BA4ac8A29A13525bb0Ee2A3D5', BptBALWETH: '0x59A19D8c652FA0284f44113D0ff9aBa70bd46fB4', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 8a0274a0..dc6fb173 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -19,6 +19,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave Matic Market variable debt', SymbolPrefix: 'm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', diff --git a/markets/xdai/commons.ts b/markets/xdai/commons.ts index ee9f1f9f..856dd50a 100644 --- a/markets/xdai/commons.ts +++ b/markets/xdai/commons.ts @@ -19,6 +19,7 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave XDAI Market variable debt', SymbolPrefix: 'm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', diff --git a/tasks/dev/3_lending_pool.ts b/tasks/dev/3_lending_pool.ts index 9936abfa..5f4336c6 100644 --- a/tasks/dev/3_lending_pool.ts +++ b/tasks/dev/3_lending_pool.ts @@ -1,5 +1,6 @@ import { task } from 'hardhat/config'; import { + deployATokenImplementations, deployATokensAndRatesHelper, deployLendingPool, deployLendingPoolConfigurator, @@ -13,13 +14,15 @@ import { getLendingPoolConfiguratorProxy, } from '../../helpers/contracts-getters'; import { insertContractAddressInDb } from '../../helpers/contracts-helpers'; +import { ConfigNames, loadPoolConfig } from '../../helpers/configuration'; task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') - .setAction(async ({ verify }, localBRE) => { + .addParam('pool', `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`) + .setAction(async ({ verify, pool }, localBRE) => { await localBRE.run('set-DRE'); - const addressesProvider = await getLendingPoolAddressesProvider(); + const poolConfig = loadPoolConfig(pool); const lendingPoolImpl = await deployLendingPool(verify); @@ -55,4 +58,5 @@ task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], verify ); + await deployATokenImplementations(pool, poolConfig.ReservesConfig, verify); }); diff --git a/tasks/dev/4_oracles.ts b/tasks/dev/4_oracles.ts index 23c24133..44a657af 100644 --- a/tasks/dev/4_oracles.ts +++ b/tasks/dev/4_oracles.ts @@ -1,7 +1,7 @@ import { task } from 'hardhat/config'; import { deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingRateOracle, } from '../../helpers/contracts-deployments'; import { @@ -12,14 +12,19 @@ import { import { ICommonConfiguration, iAssetBase, TokenContractId } from '../../helpers/types'; import { waitForTx } from '../../helpers/misc-utils'; import { getAllAggregatorsAddresses, getAllTokenAddresses } from '../../helpers/mock-helpers'; -import { ConfigNames, loadPoolConfig, getWethAddress } from '../../helpers/configuration'; +import { + ConfigNames, + loadPoolConfig, + getWethAddress, + getQuoteCurrency, +} from '../../helpers/configuration'; import { getAllMockedTokens, getLendingPoolAddressesProvider, getPairsTokenAggregator, } from '../../helpers/contracts-getters'; -task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') +task('dev:deploy-oracles', 'Deploy oracles for dev environment') .addFlag('verify', 'Verify contracts at Etherscan') .addParam('pool', `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`) .setAction(async ({ verify, pool }, localBRE) => { @@ -29,6 +34,7 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') Mocks: { AllAssetsInitialPrices }, ProtocolGlobalParams: { UsdAddress, MockUsdPriceInWei }, LendingRateOracleRatesCommon, + OracleQuoteCurrency, } = poolConfig as ICommonConfiguration; const defaultTokenList = { @@ -54,11 +60,18 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') const [tokens, aggregators] = getPairsTokenAggregator( allTokenAddresses, - allAggregatorsAddresses + allAggregatorsAddresses, + OracleQuoteCurrency ); - await deployAaveOracle( - [tokens, aggregators, fallbackOracle.address, await getWethAddress(poolConfig)], + await deployAaveOracleV2( + [ + tokens, + aggregators, + fallbackOracle.address, + await getQuoteCurrency(poolConfig), + pool.OracleQuoteUnit, + ], verify ); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); diff --git a/tasks/dev/5_initialize.ts b/tasks/dev/5_initialize.ts index f36a4e09..c791656f 100644 --- a/tasks/dev/5_initialize.ts +++ b/tasks/dev/5_initialize.ts @@ -40,6 +40,7 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') VariableDebtTokenNamePrefix, SymbolPrefix, WethGateway, + ReservesConfig, } = poolConfig; const mockTokens = await getAllMockedTokens(); const allTokenAddresses = getAllTokenAddresses(mockTokens); @@ -52,14 +53,12 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address, verify); - const reservesParams = getReservesConfigByPool(AavePools.proto); - const admin = await addressesProvider.getPoolAdmin(); const treasuryAddress = await getTreasuryAddress(poolConfig); await initReservesByHelper( - reservesParams, + ReservesConfig, protoPoolReservesAddresses, ATokenNamePrefix, StableDebtTokenNamePrefix, @@ -68,9 +67,10 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') admin, treasuryAddress, ZERO_ADDRESS, + pool, verify ); - await configureReservesByHelper(reservesParams, protoPoolReservesAddresses, testHelpers, admin); + await configureReservesByHelper(ReservesConfig, protoPoolReservesAddresses, testHelpers, admin); const collateralManager = await deployLendingPoolCollateralManager(verify); await waitForTx( diff --git a/tasks/full/2_lending_pool.ts b/tasks/full/2_lending_pool.ts index e318846e..ac930251 100644 --- a/tasks/full/2_lending_pool.ts +++ b/tasks/full/2_lending_pool.ts @@ -1,6 +1,7 @@ import { task } from 'hardhat/config'; import { getParamPerNetwork, insertContractAddressInDb } from '../../helpers/contracts-helpers'; import { + deployATokenImplementations, deployATokensAndRatesHelper, deployLendingPool, deployLendingPoolConfigurator, @@ -78,11 +79,12 @@ task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], verify ); + await deployATokenImplementations(pool, poolConfig.ReservesConfig, verify); } catch (error) { if (DRE.network.name.includes('tenderly')) { const transactionLink = `https://dashboard.tenderly.co/${DRE.config.tenderly.username}/${ DRE.config.tenderly.project - }/fork/${DRE.tenderlyNetwork.getFork()}/simulation/${DRE.tenderlyNetwork.getHead()}`; + }/fork/${DRE.tenderly.network().getFork()}/simulation/${DRE.tenderly.network().getHead()}`; console.error('Check tx error:', transactionLink); } throw error; diff --git a/tasks/full/3_oracles.ts b/tasks/full/3_oracles.ts index df06f34c..740cf1df 100644 --- a/tasks/full/3_oracles.ts +++ b/tasks/full/3_oracles.ts @@ -1,6 +1,6 @@ import { task } from 'hardhat/config'; import { getParamPerNetwork } from '../../helpers/contracts-helpers'; -import { deployAaveOracle, deployLendingRateOracle } from '../../helpers/contracts-deployments'; +import { deployAaveOracleV2, deployLendingRateOracle } from '../../helpers/contracts-deployments'; import { setInitialMarketRatesInRatesOracleByHelper } from '../../helpers/oracles-helpers'; import { ICommonConfiguration, eNetwork, SymbolMap } from '../../helpers/types'; import { waitForTx, notFalsyOrZeroAddress } from '../../helpers/misc-utils'; @@ -10,6 +10,7 @@ import { getWethAddress, getGenesisPoolAdmin, getLendingRateOracles, + getQuoteCurrency, } from '../../helpers/configuration'; import { getAaveOracle, @@ -17,7 +18,8 @@ import { getLendingRateOracle, getPairsTokenAggregator, } from '../../helpers/contracts-getters'; -import { AaveOracle, LendingRateOracle } from '../../types'; +import { AaveOracle, AaveOracleV2, LendingRateOracle } from '../../types'; +import { isAddress } from 'ethers/lib/utils'; task('full:deploy-oracles', 'Deploy oracles for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -46,16 +48,27 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') ...reserveAssets, USD: UsdAddress, }; - const [tokens, aggregators] = getPairsTokenAggregator(tokensToWatch, chainlinkAggregators); + const [tokens, aggregators] = getPairsTokenAggregator( + tokensToWatch, + chainlinkAggregators, + poolConfig.OracleQuoteCurrency + ); - let aaveOracle: AaveOracle; + let aaveOracle: AaveOracle | AaveOracleV2; let lendingRateOracle: LendingRateOracle; if (notFalsyOrZeroAddress(aaveOracleAddress)) { aaveOracle = await await getAaveOracle(aaveOracleAddress); + await waitForTx(await aaveOracle.setAssetSources(tokens, aggregators)); } else { - aaveOracle = await deployAaveOracle( - [tokens, aggregators, fallbackOracleAddress, await getWethAddress(poolConfig)], + aaveOracle = await deployAaveOracleV2( + [ + tokens, + aggregators, + fallbackOracleAddress, + await getQuoteCurrency(poolConfig), + poolConfig.OracleQuoteUnit, + ], verify ); await waitForTx(await aaveOracle.setAssetSources(tokens, aggregators)); @@ -74,7 +87,7 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') ); } - console.log('Aave Oracle: %s', lendingRateOracle.address); + console.log('Aave Oracle: %s', aaveOracle.address); console.log('Lending Rate Oracle: %s', lendingRateOracle.address); // Register the proxy price provider on the addressesProvider @@ -84,7 +97,7 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') if (DRE.network.name.includes('tenderly')) { const transactionLink = `https://dashboard.tenderly.co/${DRE.config.tenderly.username}/${ DRE.config.tenderly.project - }/fork/${DRE.tenderlyNetwork.getFork()}/simulation/${DRE.tenderlyNetwork.getHead()}`; + }/fork/${DRE.tenderly.network().getFork()}/simulation/${DRE.tenderly.network().getHead()}`; console.error('Check tx error:', transactionLink); } throw error; diff --git a/tasks/full/6-initialize.ts b/tasks/full/6-initialize.ts index bfe2925e..f315f36b 100644 --- a/tasks/full/6-initialize.ts +++ b/tasks/full/6-initialize.ts @@ -66,6 +66,7 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') admin, treasuryAddress, incentivesController, + pool, verify ); await configureReservesByHelper(ReservesConfig, reserveAssets, testHelpers, admin); diff --git a/tasks/helpers/deploy-new-asset.ts b/tasks/helpers/deploy-new-asset.ts index 718b6372..86b4958a 100644 --- a/tasks/helpers/deploy-new-asset.ts +++ b/tasks/helpers/deploy-new-asset.ts @@ -3,9 +3,9 @@ import { eEthereumNetwork } from '../../helpers/types'; import { getTreasuryAddress } from '../../helpers/configuration'; import * as marketConfigs from '../../markets/aave'; import * as reserveConfigs from '../../markets/aave/reservesConfigs'; -import { chooseATokenDeployment } from '../../helpers/init-helpers'; import { getLendingPoolAddressesProvider } from './../../helpers/contracts-getters'; import { + chooseATokenDeployment, deployDefaultReserveInterestRateStrategy, deployStableDebtToken, deployVariableDebtToken, @@ -47,18 +47,7 @@ WRONG RESERVE ASSET SETUP: LENDING_POOL_ADDRESS_PROVIDER[network] ); const poolAddress = await addressProvider.getLendingPool(); - const treasuryAddress = await getTreasuryAddress(marketConfigs.AaveConfig); - const aToken = await deployCustomAToken( - [ - poolAddress, - reserveAssetAddress, - treasuryAddress, - ZERO_ADDRESS, // Incentives Controller - `Aave interest bearing ${symbol}`, - `a${symbol}`, - ], - verify - ); + const aToken = await deployCustomAToken(verify); const stableDebt = await deployStableDebtToken( [ poolAddress, From 6319f22ad5ab86a74128738f5bb5ce5eabce7ac3 Mon Sep 17 00:00:00 2001 From: David Racero Date: Wed, 14 Jul 2021 16:56:03 +0200 Subject: [PATCH 21/62] tests: fixed tests to support latest changes --- helpers/configuration.ts | 6 ++- package-lock.json | 2 +- test-suites/test-aave/__setup.spec.ts | 55 ++++++++++++++++----------- test-suites/test-amm/__setup.spec.ts | 46 +++++++++++++--------- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/helpers/configuration.ts b/helpers/configuration.ts index f22a2584..5e682ee7 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -35,7 +35,11 @@ export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => { case ConfigNames.Commons: return CommonsConfig; default: - throw new Error(`Unsupported pool configuration: ${Object.values(ConfigNames)}`); + throw new Error( + `Unsupported pool configuration: ${configName} is not one of the supported configs ${Object.values( + ConfigNames + )}` + ); } }; diff --git a/package-lock.json b/package-lock.json index 7f3c76fd..e5198127 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14793,7 +14793,7 @@ } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index c004d10f..6affdb1c 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -13,7 +13,7 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -28,8 +28,8 @@ import { deployUniswapRepayAdapter, deployFlashLiquidationAdapter, authorizeWETHGateway, + deployATokenImplementations, } from '../../helpers/contracts-deployments'; -import { eEthereumNetwork } from '../../helpers/types'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; import { MintableERC20 } from '../../types/MintableERC20'; @@ -49,7 +49,7 @@ import { import { DRE, waitForTx } from '../../helpers/misc-utils'; import { initReservesByHelper, configureReservesByHelper } from '../../helpers/init-helpers'; import AaveConfig from '../../markets/aave'; -import { ZERO_ADDRESS } from '../../helpers/constants'; +import { oneEther, ZERO_ADDRESS } from '../../helpers/constants'; import { getLendingPool, getLendingPoolConfiguratorProxy, @@ -60,7 +60,6 @@ import { WETH9Mocked } from '../../types/WETH9Mocked'; const MOCK_USD_PRICE_IN_WEI = AaveConfig.ProtocolGlobalParams.MockUsdPriceInWei; const ALL_ASSETS_INITIAL_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; const USD_ADDRESS = AaveConfig.ProtocolGlobalParams.UsdAddress; -const MOCK_CHAINLINK_AGGREGATORS_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; const LENDING_RATE_ORACLE_RATES_COMMON = AaveConfig.LendingRateOracleRatesCommon; const deployAllMockTokens = async (deployer: Signer) => { @@ -96,9 +95,13 @@ const deployAllMockTokens = async (deployer: Signer) => { const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.time('setup'); const aaveAdmin = await deployer.getAddress(); + const config = loadPoolConfig(ConfigNames.Aave); - const mockTokens = await deployAllMockTokens(deployer); - console.log('Deployed mocks'); + const mockTokens: { + [symbol: string]: MockContract | MintableERC20 | WETH9Mocked; + } = { + ...(await deployAllMockTokens(deployer)), + }; const addressesProvider = await deployLendingPoolAddressesProvider(AaveConfig.MarketId); await waitForTx(await addressesProvider.setPoolAdmin(aaveAdmin)); @@ -195,8 +198,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { fallbackOracle ); - const mockAggregators = await deployAllMockAggregators(MOCK_CHAINLINK_AGGREGATORS_PRICES); - console.log('Mock aggs deployed'); + const mockAggregators = await deployAllMockAggregators(ALL_ASSETS_INITIAL_PRICES); const allTokenAddresses = Object.entries(mockTokens).reduce( (accum: { [tokenSymbol: string]: tEthereumAddress }, [tokenSymbol, tokenContract]) => ({ ...accum, @@ -212,9 +214,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { {} ); - const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses); + const [tokens, aggregators] = getPairsTokenAggregator( + allTokenAddresses, + allAggregatorsAddresses, + config.OracleQuoteCurrency + ); - await deployAaveOracle([tokens, aggregators, fallbackOracle.address, mockTokens.WETH.address]); + await deployAaveOracleV2([ + tokens, + aggregators, + fallbackOracle.address, + mockTokens.WETH.address, + oneEther.toString(), + ]); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); const lendingRateOracle = await deployLendingRateOracle(); @@ -231,23 +243,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { aaveAdmin ); - const reservesParams = getReservesConfigByPool(AavePools.proto); + // Reserve params from AAVE pool + mocked tokens + const reservesParams = { + ...config.ReservesConfig, + }; const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address); - await insertContractAddressInDb(eContractid.AaveProtocolDataProvider, testHelpers.address); + await deployATokenImplementations(ConfigNames.Aave, reservesParams, false); + const admin = await deployer.getAddress(); - console.log('Initialize configuration'); - - const config = loadPoolConfig(ConfigNames.Aave); - - const { - ATokenNamePrefix, - StableDebtTokenNamePrefix, - VariableDebtTokenNamePrefix, - SymbolPrefix, - } = config; + const { ATokenNamePrefix, StableDebtTokenNamePrefix, VariableDebtTokenNamePrefix, SymbolPrefix } = + config; const treasuryAddress = await getTreasuryAddress(config); await initReservesByHelper( @@ -260,6 +268,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { admin, treasuryAddress, ZERO_ADDRESS, + ConfigNames.Aave, false ); @@ -297,7 +306,7 @@ before(async () => { const FORK = process.env.FORK; if (FORK) { - await rawBRE.run('aave:mainnet'); + await rawBRE.run('aave:mainnet', { skipRegistry: true }); } else { console.log('-> Deploying test environment...'); await buildTestEnv(deployer, secondaryWallet); diff --git a/test-suites/test-amm/__setup.spec.ts b/test-suites/test-amm/__setup.spec.ts index 0fae3acd..ef398214 100644 --- a/test-suites/test-amm/__setup.spec.ts +++ b/test-suites/test-amm/__setup.spec.ts @@ -13,7 +13,7 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -28,6 +28,7 @@ import { deployUniswapRepayAdapter, deployFlashLiquidationAdapter, authorizeWETHGateway, + deployATokenImplementations, } from '../../helpers/contracts-deployments'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; @@ -48,7 +49,7 @@ import { import { DRE, waitForTx } from '../../helpers/misc-utils'; import { initReservesByHelper, configureReservesByHelper } from '../../helpers/init-helpers'; import AmmConfig from '../../markets/amm'; -import { ZERO_ADDRESS } from '../../helpers/constants'; +import { oneEther, ZERO_ADDRESS } from '../../helpers/constants'; import { getLendingPool, getLendingPoolConfiguratorProxy, @@ -95,6 +96,14 @@ const deployAllMockTokens = async (deployer: Signer) => { const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.time('setup'); const aaveAdmin = await deployer.getAddress(); + const config = loadPoolConfig(ConfigNames.Amm); + const { + ATokenNamePrefix, + StableDebtTokenNamePrefix, + VariableDebtTokenNamePrefix, + SymbolPrefix, + ReservesConfig, + } = config; const mockTokens = await deployAllMockTokens(deployer); @@ -189,6 +198,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { WMATIC: mockTokens.WMATIC.address, USD: USD_ADDRESS, STAKE: mockTokens.STAKE.address, + xSUSHI: ZERO_ADDRESS, }, fallbackOracle ); @@ -210,9 +220,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { {} ); - const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses); + const [tokens, aggregators] = getPairsTokenAggregator( + allTokenAddresses, + allAggregatorsAddresses, + config.OracleQuoteCurrency + ); - await deployAaveOracle([tokens, aggregators, fallbackOracle.address, mockTokens.WETH.address]); + await deployAaveOracleV2([ + tokens, + aggregators, + fallbackOracle.address, + mockTokens.WETH.address, + oneEther.toString(), + ]); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); const lendingRateOracle = await deployLendingRateOracle(); @@ -228,8 +248,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { lendingRateOracle, aaveAdmin ); - - const reservesParams = getReservesConfigByPool(AavePools.amm); + await deployATokenImplementations(ConfigNames.Amm, ReservesConfig); const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address); @@ -238,18 +257,10 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.log('Initialize configuration'); - const config = loadPoolConfig(ConfigNames.Amm); - - const { - ATokenNamePrefix, - StableDebtTokenNamePrefix, - VariableDebtTokenNamePrefix, - SymbolPrefix, - } = config; const treasuryAddress = await getTreasuryAddress(config); await initReservesByHelper( - reservesParams, + ReservesConfig, allReservesAddresses, ATokenNamePrefix, StableDebtTokenNamePrefix, @@ -258,9 +269,10 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { admin, treasuryAddress, ZERO_ADDRESS, + ConfigNames.Amm, false ); - await configureReservesByHelper(reservesParams, allReservesAddresses, testHelpers, admin); + await configureReservesByHelper(ReservesConfig, allReservesAddresses, testHelpers, admin); const collateralManager = await deployLendingPoolCollateralManager(); await waitForTx( @@ -294,7 +306,7 @@ before(async () => { const FORK = process.env.FORK; if (FORK) { - await rawBRE.run('amm:mainnet'); + await rawBRE.run('amm:mainnet', { skipRegistry: true }); } else { console.log('-> Deploying test environment...'); await buildTestEnv(deployer, secondaryWallet); From a0a6210902506b6bc70fe81adcbbb5420afd993c Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Fri, 16 Jul 2021 10:46:07 +0200 Subject: [PATCH 22/62] feat: Add Avalanche network configuration --- hardhat.config.ts | 10 ++++++++- helper-hardhat-config.ts | 7 ++++++ helpers/configuration.ts | 7 ++++++ helpers/constants.ts | 1 + helpers/contracts-helpers.ts | 21 ++++++++++-------- helpers/init-helpers.ts | 2 +- helpers/types.ts | 31 +++++++++++++++++++++++++-- test-suites/test-aave/__setup.spec.ts | 1 + 8 files changed, 67 insertions(+), 13 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 278577bb..dc47392f 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -3,7 +3,13 @@ import fs from 'fs'; import { HardhatUserConfig } from 'hardhat/types'; // @ts-ignore import { accounts } from './test-wallets.js'; -import { eEthereumNetwork, eNetwork, ePolygonNetwork, eXDaiNetwork } from './helpers/types'; +import { + eAvalancheNetwork, + eEthereumNetwork, + eNetwork, + ePolygonNetwork, + eXDaiNetwork, +} from './helpers/types'; import { BUIDLEREVM_CHAINID, COVERAGE_CHAINID } from './helpers/buidler-constants'; import { NETWORKS_RPC_URL, @@ -100,6 +106,8 @@ const buidlerConfig: HardhatUserConfig = { matic: getCommonNetworkConfig(ePolygonNetwork.matic, 137), mumbai: getCommonNetworkConfig(ePolygonNetwork.mumbai, 80001), xdai: getCommonNetworkConfig(eXDaiNetwork.xdai, 100), + avalanche: getCommonNetworkConfig(eAvalancheNetwork.avalanche, 43114), + fuji: getCommonNetworkConfig(eAvalancheNetwork.fuji, 43113), hardhat: { hardfork: 'berlin', blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT, diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index 3df38000..6747c444 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -1,6 +1,7 @@ // @ts-ignore import { HardhatNetworkForkingUserConfig, HardhatUserConfig } from 'hardhat/types'; import { + eAvalancheNetwork, eEthereumNetwork, ePolygonNetwork, eXDaiNetwork, @@ -49,6 +50,8 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { [ePolygonNetwork.mumbai]: 'https://rpc-mumbai.maticvigil.com', [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', [eXDaiNetwork.xdai]: 'https://rpc.xdaichain.com/', + [eAvalancheNetwork.avalanche]: 'https://cchain.explorer.avax.network/', + [eAvalancheNetwork.fuji]: 'https://api.avax-test.network/ext/bc/C/rpc' }; export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { @@ -62,6 +65,8 @@ export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { [ePolygonNetwork.mumbai]: 1 * GWEI, [ePolygonNetwork.matic]: 1 * GWEI, [eXDaiNetwork.xdai]: 1 * GWEI, + [eAvalancheNetwork.avalanche]: 255 * GWEI, + [eAvalancheNetwork.fuji]: 255 * GWEI }; export const BLOCK_TO_FORK: iParamsPerNetwork = { @@ -75,4 +80,6 @@ export const BLOCK_TO_FORK: iParamsPerNetwork = { [ePolygonNetwork.mumbai]: undefined, [ePolygonNetwork.matic]: undefined, [eXDaiNetwork.xdai]: undefined, + [eAvalancheNetwork.avalanche]: undefined, + [eAvalancheNetwork.fuji]: undefined }; diff --git a/helpers/configuration.ts b/helpers/configuration.ts index 82e74e41..5ba2c386 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -9,6 +9,7 @@ import { import { getEthersSignersAddresses, getParamPerPool } from './contracts-helpers'; import AaveConfig from '../markets/aave'; import MaticConfig from '../markets/matic'; +import AvalancheConfig from '../markets/avalanche'; import AmmConfig from '../markets/amm'; import { CommonsConfig } from '../markets/aave/commons'; import { DRE, filterMapBy } from './misc-utils'; @@ -21,6 +22,7 @@ export enum ConfigNames { Aave = 'Aave', Matic = 'Matic', Amm = 'Amm', + Avalanche = 'Avalanche' } export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => { @@ -31,6 +33,8 @@ export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => { return MaticConfig; case ConfigNames.Amm: return AmmConfig; + case ConfigNames.Avalanche: + return AvalancheConfig; case ConfigNames.Commons: return CommonsConfig; default: @@ -54,6 +58,9 @@ export const getReservesConfigByPool = (pool: AavePools): iMultiPoolsAssets(param: iParamsPerNetwork, network: eNetwork) => { - const { - main, - ropsten, - kovan, - coverage, - buidlerevm, - tenderlyMain, - } = param as iEthereumParamsPerNetwork; + const { main, ropsten, kovan, coverage, buidlerevm, tenderlyMain } = + param as iEthereumParamsPerNetwork; const { matic, mumbai } = param as iPolygonParamsPerNetwork; const { xdai } = param as iXDaiParamsPerNetwork; + const { avalanche, fuji } = param as iAvalancheParamsPerNetwork; if (process.env.FORK) { return param[process.env.FORK as eNetwork] as T; } @@ -177,10 +174,14 @@ export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNet return mumbai; case eXDaiNetwork.xdai: return xdai; + case eAvalancheNetwork.avalanche: + return avalanche; + case eAvalancheNetwork.fuji: + return fuji; } }; -export const getParamPerPool = ({ proto, amm, matic }: iParamsPerPool, pool: AavePools) => { +export const getParamPerPool = ({ proto, amm, matic, avalanche }: iParamsPerPool, pool: AavePools) => { switch (pool) { case AavePools.proto: return proto; @@ -188,6 +189,8 @@ export const getParamPerPool = ({ proto, amm, matic }: iParamsPerPool, poo return amm; case AavePools.matic: return matic; + case AavePools.avalanche: + return avalanche; default: return proto; } diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index aa209583..a3035692 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -349,7 +349,7 @@ export const configureReservesByHelper = async ( for (let chunkIndex = 0; chunkIndex < chunkedInputParams.length; chunkIndex++) { await waitForTx( await atokenAndRatesDeployer.configureReserves(chunkedInputParams[chunkIndex], { - gasLimit: 12000000, + gasLimit: 8000000, // TODO: Change this }) ); console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); diff --git a/helpers/types.ts b/helpers/types.ts index 267b5abb..e2052c7f 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -4,7 +4,7 @@ export interface SymbolMap { [symbol: string]: T; } -export type eNetwork = eEthereumNetwork | ePolygonNetwork | eXDaiNetwork; +export type eNetwork = eEthereumNetwork | ePolygonNetwork | eXDaiNetwork | eAvalancheNetwork; export enum eEthereumNetwork { buidlerevm = 'buidlerevm', @@ -25,6 +25,11 @@ export enum eXDaiNetwork { xdai = 'xdai', } +export enum eAvalancheNetwork { + avalanche = 'avalanche', + fuji = 'fuji', +} + export enum EthereumNetworkNames { kovan = 'kovan', ropsten = 'ropsten', @@ -32,12 +37,16 @@ export enum EthereumNetworkNames { matic = 'matic', mumbai = 'mumbai', xdai = 'xdai', + avalanche = 'avalanche', + fuji = 'fuji' + } export enum AavePools { proto = 'proto', matic = 'matic', amm = 'amm', + avalanche = 'avalanche' } export enum eContractid { @@ -239,6 +248,7 @@ export interface iAssetBase { WMATIC: T; STAKE: T; xSUSHI: T; + AVAX: T; } export type iAssetsWithoutETH = Omit, 'ETH'>; @@ -305,6 +315,11 @@ export type iXDAIPoolAssets = Pick< 'DAI' | 'USDC' | 'USDT' | 'WBTC' | 'WETH' | 'STAKE' >; +export type iAvalanchePoolAssets = Pick< + iAssetsWithoutUSD, + 'WETH' | 'DAI' | 'USDC' | 'USDT' | 'AAVE' | 'WBTC' | 'AVAX' +>; + export type iMultiPoolsAssets = iAssetCommon | iAavePoolAssets; export type iAavePoolTokens = Omit, 'ETH'>; @@ -352,6 +367,7 @@ export enum TokenContractId { WMATIC = 'WMATIC', STAKE = 'STAKE', xSUSHI = 'xSUSHI', + AVAX = 'AVAX' } export interface IReserveParams extends IReserveBorrowParams, IReserveCollateralParams { @@ -394,7 +410,8 @@ export interface IMarketRates { export type iParamsPerNetwork = | iEthereumParamsPerNetwork | iPolygonParamsPerNetwork - | iXDaiParamsPerNetwork; + | iXDaiParamsPerNetwork + | iAvalancheParamsPerNetwork; export interface iParamsPerNetworkAll extends iEthereumParamsPerNetwork, @@ -420,10 +437,16 @@ export interface iXDaiParamsPerNetwork { [eXDaiNetwork.xdai]: T; } +export interface iAvalancheParamsPerNetwork { + [eAvalancheNetwork.avalanche]: T; + [eAvalancheNetwork.fuji]: T; +} + export interface iParamsPerPool { [AavePools.proto]: T; [AavePools.matic]: T; [AavePools.amm]: T; + [AavePools.avalanche]: T; } export interface iBasicDistributionParams { @@ -512,6 +535,10 @@ export interface IXDAIConfiguration extends ICommonConfiguration { ReservesConfig: iXDAIPoolAssets; } +export interface IAvalancheConfiguration extends ICommonConfiguration { + ReservesConfig: iAvalanchePoolAssets; +} + export interface ITokenAddress { [token: string]: tEthereumAddress; } diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index c004d10f..ca9f7698 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -191,6 +191,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { USD: USD_ADDRESS, STAKE: mockTokens.STAKE.address, xSUSHI: mockTokens.xSUSHI.address, + AVAX: mockTokens.AVAX.address }, fallbackOracle ); From 14fe2ba139f5a224e98e1898f2e181636d00f67c Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Fri, 16 Jul 2021 10:47:16 +0200 Subject: [PATCH 23/62] feat: Add Avalanche market config --- markets/avalanche/commons.ts | 165 ++++++++++++++++++++++++++ markets/avalanche/index.ts | 54 +++++++++ markets/avalanche/rateStrategies.ts | 105 ++++++++++++++++ markets/avalanche/reservesConfigs.ts | 94 +++++++++++++++ package.json | 3 + tasks/migrations/avalanche.mainnet.ts | 60 ++++++++++ 6 files changed, 481 insertions(+) create mode 100644 markets/avalanche/commons.ts create mode 100644 markets/avalanche/index.ts create mode 100644 markets/avalanche/rateStrategies.ts create mode 100644 markets/avalanche/reservesConfigs.ts create mode 100644 tasks/migrations/avalanche.mainnet.ts diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts new file mode 100644 index 00000000..f3e47e3d --- /dev/null +++ b/markets/avalanche/commons.ts @@ -0,0 +1,165 @@ +import BigNumber from 'bignumber.js'; +import { + oneEther, + oneRay, + RAY, + ZERO_ADDRESS, + MOCK_CHAINLINK_AGGREGATORS_PRICES, +} from '../../helpers/constants'; +import { ICommonConfiguration, eAvalancheNetwork } from '../../helpers/types'; + +// ---------------- +// PROTOCOL GLOBAL PARAMS +// ---------------- + +export const CommonsConfig: ICommonConfiguration = { + MarketId: 'Commons', + ATokenNamePrefix: 'Aave Avalanche Market', + StableDebtTokenNamePrefix: 'Aave Avalanche Market stable debt', + VariableDebtTokenNamePrefix: 'Aave Avalanche Market variable debt', + SymbolPrefix: '', // TODO: add a symbol? + ProviderId: 0, // Overriden in index.ts + ProtocolGlobalParams: { + TokenDistributorPercentageBase: '10000', + MockUsdPriceInWei: '5848466240000000', + UsdAddress: '0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96', // TODO: what is this? + NilAddress: '0x0000000000000000000000000000000000000000', + OneAddress: '0x0000000000000000000000000000000000000001', + AaveReferral: '0', + }, + + // ---------------- + // COMMON PROTOCOL PARAMS ACROSS POOLS AND NETWORKS + // ---------------- + + Mocks: { + AllAssetsInitialPrices: { + ...MOCK_CHAINLINK_AGGREGATORS_PRICES, + }, + }, + // TODO: reorg alphabetically, checking the reason of tests failing + LendingRateOracleRatesCommon: { + WETH: { + borrowRate: oneRay.multipliedBy(0.03).toFixed(), + }, + DAI: { + borrowRate: oneRay.multipliedBy(0.039).toFixed(), + }, + USDC: { + borrowRate: oneRay.multipliedBy(0.039).toFixed(), + }, + USDT: { + borrowRate: oneRay.multipliedBy(0.035).toFixed(), + }, + AAVE: { + borrowRate: oneRay.multipliedBy(0.03).toFixed(), + }, + WBTC: { + borrowRate: oneRay.multipliedBy(0.03).toFixed(), + }, + AVAX: { + borrowRate: oneRay.multipliedBy(0.05).toFixed(), // TODO: fix borrowRate? + } + }, + // ---------------- + // COMMON PROTOCOL ADDRESSES ACROSS POOLS + // ---------------- + + // If PoolAdmin/emergencyAdmin is set, will take priority over PoolAdminIndex/emergencyAdminIndex + PoolAdmin: { + [eAvalancheNetwork.avalanche]: undefined, + [eAvalancheNetwork.fuji]: undefined + }, + PoolAdminIndex: 0, + EmergencyAdminIndex: 0, + EmergencyAdmin: { + [eAvalancheNetwork.avalanche]: undefined, + [eAvalancheNetwork.fuji]: undefined + }, + ProviderRegistry: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '0x3C50d48864d0866B854120fd5B6e1CC7783BB92c' + }, + ProviderRegistryOwner: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '0xA68E2f643e0fa7062A78DFB6C629577aE21ad829' + }, + LendingRateOracle: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '0x82493D29a6CD24cF6C3865Ad5Ef728A6A8920194' + }, + LendingPoolCollateralManager: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '0x67abd0a85e1a2eAf10995820C23A455De7E164Af' + }, + LendingPoolConfigurator: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + LendingPool: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + WethGateway: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + TokenDistributor: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + AaveOracle: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + FallbackOracle: { + [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, + [eAvalancheNetwork.fuji]: ZERO_ADDRESS // TODO: Deploy? + }, + ChainlinkAggregator: { + [eAvalancheNetwork.avalanche]: { + WETH: '', + DAI: '', + USDC: '', + USDT: '', + AAVE: '', + WBTC: ' ', + AVAX: '', + }, + [eAvalancheNetwork.fuji]: { + WETH: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA', + // DAI: '', + // USDC: '', + USDT: '0x7898AcCC83587C3C55116c5230C17a6Cd9C71bad', + // AAVE: '', + WBTC: '0x31CF013A08c6Ac228C94551d535d5BAfE19c602a', + // AVAX: '0x5498BB86BC934c8D34FDA08E81D444153d0D06aD', + USD: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA' + }, + }, + ReserveAssets: { + [eAvalancheNetwork.avalanche]: {}, + [eAvalancheNetwork.fuji]: {} + }, + ReservesConfig: {}, + ATokenDomainSeparator: { + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '' + }, + WETH: { + [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // TODO: Add WETH address + [eAvalancheNetwork.fuji]: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA' + }, + WrappedNativeToken: { + [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', + [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // TODO: Add WAVAX address? + }, + ReserveFactorTreasuryAddress: { + [eAvalancheNetwork.avalanche]: '0x652e2Ac6b072Ba8bF7BEF2B11B092447dBc40bde', // TODO: Deploy Treasury + [eAvalancheNetwork.fuji]: '0x652e2Ac6b072Ba8bF7BEF2B11B092447dBc40bde' + }, + IncentivesController: { + [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, + [eAvalancheNetwork.fuji]: ZERO_ADDRESS + }, +}; diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts new file mode 100644 index 00000000..4c27bfca --- /dev/null +++ b/markets/avalanche/index.ts @@ -0,0 +1,54 @@ +import { oneRay, ZERO_ADDRESS } from '../../helpers/constants'; +import { IAaveConfiguration, eEthereumNetwork, eAvalancheNetwork, IAvalancheConfiguration } from '../../helpers/types'; + +import { CommonsConfig } from './commons'; +import { + strategyWETH, + strategyDAI, + strategyUSDC, + strategyUSDT, + strategyAAVE, + strategyWBTC, + strategyAVAX +} from './reservesConfigs'; + +// ---------------- +// POOL--SPECIFIC PARAMS +// ---------------- + +export const AvalancheConfig: IAvalancheConfiguration = { + ...CommonsConfig, + MarketId: 'Avalanche market', + ProviderId: 5, // TODO: What is this? + ReservesConfig: { + WETH: strategyWETH, + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + AAVE: strategyAAVE, + WBTC: strategyWBTC, + AVAX: strategyAVAX, + }, + ReserveAssets: { + [eAvalancheNetwork.avalanche]: { // TODO: Check this + WETH: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', + // DAI: '0xbA7dEebBFC5fA1100Fb055a87773e1E99Cd3507a', + // USDC: '', // TODO: Not yet deployed by Circle + USDT: '0xde3A24028580884448a5397872046a019649b084', + // AAVE: '0x8cE2Dee54bB9921a2AE0A63dBb2DF8eD88B91dD9', // TODO: What we are going to do? + WBTC: '0x408D4cD0ADb7ceBd1F1A1C33A0Ba2098E1295bAB', + // AVAX: '' // TODO: Use WAVAX? + }, + [eAvalancheNetwork.fuji]: { // TODO: Deploy Mock tokens + WETH: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0', + // DAI: '0x51BC2DfB9D12d9dB50C855A5330fBA0faF761D15', + // USDC: '0x7804D7f48f6E5749AF5c8Fa87b20702C34a7f5c2', + USDT: '0x533AE347203DD2aa2bc710E93cafE7650E1bC4e2', + // AAVE: '0x47183584aCbc1C45608d7B61cce1C562Ee180E7e', + WBTC: '0xDc880858bFE85F41deadBbB1CA1e6fFCe25f5B66', + // AVAX: '0x28575C264f7bf17e8C91f80585765D92d4B9d113' + }, + }, +}; + +export default AvalancheConfig; diff --git a/markets/avalanche/rateStrategies.ts b/markets/avalanche/rateStrategies.ts new file mode 100644 index 00000000..4a7125dd --- /dev/null +++ b/markets/avalanche/rateStrategies.ts @@ -0,0 +1,105 @@ +import BigNumber from 'bignumber.js'; +import { oneRay } from '../../helpers/constants'; +import { IInterestRateStrategyParams } from '../../helpers/types'; + +// BUSD SUSD +export const rateStrategyStableOne: IInterestRateStrategyParams = { + name: "rateStrategyStableOne", + optimalUtilizationRate: new BigNumber(0.8).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), + stableRateSlope1: '0', + stableRateSlope2: '0', +}; + +// DAI TUSD +export const rateStrategyStableTwo: IInterestRateStrategyParams = { + name: "rateStrategyStableTwo", + optimalUtilizationRate: new BigNumber(0.8).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(0.75).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.02).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(0.75).multipliedBy(oneRay).toFixed(), +} + +// USDC USDT +export const rateStrategyStableThree: IInterestRateStrategyParams = { + name: "rateStrategyStableThree", + optimalUtilizationRate: new BigNumber(0.9).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(0.60).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.02).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(0.60).multipliedBy(oneRay).toFixed(), +} + +// WETH +export const rateStrategyWETH: IInterestRateStrategyParams = { + name: "rateStrategyWETH", + optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), +} + +// AAVE +export const rateStrategyAAVE: IInterestRateStrategyParams = { + name: "rateStrategyAAVE", + optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: '0', + variableRateSlope1: '0', + variableRateSlope2: '0', + stableRateSlope1: '0', + stableRateSlope2: '0', +} + +// BAT ENJ LINK MANA MKR REN YFI ZRX +export const rateStrategyVolatileOne: IInterestRateStrategyParams = { + name: "rateStrategyVolatileOne", + optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.07).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), +} + +// KNC WBTC +export const rateStrategyVolatileTwo: IInterestRateStrategyParams = { + name: "rateStrategyVolatileTwo", + optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), +} + +// SNX +export const rateStrategyVolatileThree: IInterestRateStrategyParams = { + name: "rateStrategyVolatileThree", + optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), + stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), + stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), +} + + +export const rateStrategyVolatileFour: IInterestRateStrategyParams = { + name: "rateStrategyVolatileFour", + optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), + baseVariableBorrowRate: '0', + variableRateSlope1: new BigNumber(0.07).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), + stableRateSlope1: '0', + stableRateSlope2: '0', +} + + + diff --git a/markets/avalanche/reservesConfigs.ts b/markets/avalanche/reservesConfigs.ts new file mode 100644 index 00000000..f80e5a8b --- /dev/null +++ b/markets/avalanche/reservesConfigs.ts @@ -0,0 +1,94 @@ +import { eContractid, IReserveParams } from '../../helpers/types'; + +import { + rateStrategyStableTwo, + rateStrategyStableThree, + rateStrategyWETH, + rateStrategyAAVE, + rateStrategyVolatileOne, + rateStrategyVolatileTwo, +} from './rateStrategies'; + +export const strategyDAI: IReserveParams = { + strategy: rateStrategyStableTwo, + baseLTVAsCollateral: '7500', + liquidationThreshold: '8000', + liquidationBonus: '10500', + borrowingEnabled: true, + stableBorrowRateEnabled: true, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '1000' +}; + +export const strategyUSDC: IReserveParams = { + strategy: rateStrategyStableThree, + baseLTVAsCollateral: '8000', + liquidationThreshold: '8500', + liquidationBonus: '10500', + borrowingEnabled: true, + stableBorrowRateEnabled: true, + reserveDecimals: '6', + aTokenImpl: eContractid.AToken, + reserveFactor: '1000' +}; + +export const strategyUSDT: IReserveParams = { + strategy: rateStrategyStableThree, + baseLTVAsCollateral: '8000', + liquidationThreshold: '8500', + liquidationBonus: '10500', + borrowingEnabled: true, + stableBorrowRateEnabled: true, + reserveDecimals: '6', + aTokenImpl: eContractid.AToken, + reserveFactor: '1000' +}; + +export const strategyAAVE: IReserveParams = { + strategy: rateStrategyAAVE, + baseLTVAsCollateral: '5000', + liquidationThreshold: '6500', + liquidationBonus: '11000', + borrowingEnabled: false, + stableBorrowRateEnabled: false, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '0' +}; + +export const strategyWETH: IReserveParams = { + strategy: rateStrategyWETH, + baseLTVAsCollateral: '8000', + liquidationThreshold: '8250', + liquidationBonus: '10500', + borrowingEnabled: true, + stableBorrowRateEnabled: true, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '1000' +}; + +export const strategyWBTC: IReserveParams = { + strategy: rateStrategyVolatileTwo, + baseLTVAsCollateral: '7000', + liquidationThreshold: '7500', + liquidationBonus: '11000', + borrowingEnabled: true, + stableBorrowRateEnabled: true, + reserveDecimals: '8', + aTokenImpl: eContractid.AToken, + reserveFactor: '2000' +}; + +export const strategyAVAX: IReserveParams = { + strategy: rateStrategyVolatileOne, + baseLTVAsCollateral: '5000', + liquidationThreshold: '6500', + liquidationBonus: '11000', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '2000', +}; diff --git a/package.json b/package.json index b9debafc..e404b482 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "hardhat:docker": "hardhat --network hardhatevm_docker", "hardhat:mumbai": "hardhat --network mumbai", "hardhat:matic": "hardhat --network matic", + "hardhat:fuji": "hardhat --network fuji", + "hardhat:avalanche": "hardhat --network avalanche", "compile": "SKIP_LOAD=true hardhat compile", "console:fork": "FORK=main hardhat console", "test": "npm run compile && TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-aave/*.spec.ts", @@ -30,6 +32,7 @@ "aave:kovan:full:migration": "npm run compile && npm run hardhat:kovan -- aave:mainnet --skip-registry", "matic:mumbai:full:migration": "npm run compile && npm run hardhat:mumbai sidechain:mainnet -- --pool Matic --skip-registry", "matic:matic:full:migration": "npm run compile && npm run hardhat:matic sidechain:mainnet -- --pool Matic --skip-registry", + "avalanche:fuji:full:migration": "npm run compile && npm run hardhat:fuji avalanche:mainnet -- --pool Avalanche --skip-registry", "amm:kovan:full:migration": "npm run compile && npm run hardhat:kovan -- amm:mainnet --skip-registry", "aave:docker:full:migration:add-registry": "npm run compile && npm run hardhat:docker -- aave:mainnet", "aave:kovan:full:migration:add-registry": "npm run compile && npm run hardhat:kovan -- aave:mainnet", diff --git a/tasks/migrations/avalanche.mainnet.ts b/tasks/migrations/avalanche.mainnet.ts new file mode 100644 index 00000000..3a373dec --- /dev/null +++ b/tasks/migrations/avalanche.mainnet.ts @@ -0,0 +1,60 @@ +import { task } from 'hardhat/config'; +import { checkVerification } from '../../helpers/etherscan-verification'; +import { ConfigNames } from '../../helpers/configuration'; +import { printContracts } from '../../helpers/misc-utils'; +import { usingTenderly } from '../../helpers/tenderly-utils'; + +task('avalanche:mainnet', 'Deploy market at avalanche') + .addParam('pool', `Market pool configuration, one of ${Object.keys(ConfigNames)}`) + .addFlag('verify', 'Verify contracts at Etherscan') + .addFlag('skipRegistry', 'Skip addresses provider registration at Addresses Provider Registry') + .setAction(async ({ verify, pool, skipRegistry }, DRE) => { + const POOL_NAME = pool; + await DRE.run('set-DRE'); + + // Prevent loss of gas verifying all the needed ENVs for Etherscan verification + if (verify) { + checkVerification(); + } + + console.log('Migration started\n'); + + console.log('0. Deploy address provider registry'); + await DRE.run('full:deploy-address-provider-registry', { pool: POOL_NAME }); + + console.log('1. Deploy address provider'); + await DRE.run('full:deploy-address-provider', { pool: POOL_NAME, skipRegistry }); + + console.log('2. Deploy lending pool'); + await DRE.run('full:deploy-lending-pool', { pool: POOL_NAME }); + + console.log('3. Deploy oracles'); + await DRE.run('full:deploy-oracles', { pool: POOL_NAME }); + + console.log('4. Deploy Data Provider'); + await DRE.run('full:data-provider', { pool: POOL_NAME }); + console.log('5. Deploy WETH Gateway'); + await DRE.run('full-deploy-weth-gateway', { pool: POOL_NAME }); + + console.log('6. Initialize lending pool'); + await DRE.run('full:initialize-lending-pool', { pool: POOL_NAME }); + + if (verify) { + printContracts(); + console.log('7. Veryfing contracts'); + await DRE.run('verify:general', { all: true, pool: POOL_NAME }); + + console.log('8. Veryfing aTokens and debtTokens'); + await DRE.run('verify:tokens', { pool: POOL_NAME }); + } + + if (usingTenderly()) { + const postDeployHead = DRE.tenderlyNetwork.getHead(); + const postDeployFork = DRE.tenderlyNetwork.getFork(); + console.log('Tenderly Info'); + console.log('- Head', postDeployHead); + console.log('- Fork', postDeployFork); + } + console.log('\nFinished migrations'); + printContracts(); + }); From 95e9c3588cdeff1038e57d702c2936158c0f2664 Mon Sep 17 00:00:00 2001 From: David Racero Date: Wed, 14 Jul 2021 16:41:32 +0200 Subject: [PATCH 24/62] feat: support custom quote currencies. Added base scripts for custom atokens and rates. --- contracts/misc/AaveOracleV2.sol | 125 ++++++++++++++++++++++ hardhat.config.ts | 2 +- helper-hardhat-config.ts | 6 +- helpers/configuration.ts | 33 +++--- helpers/constants.ts | 2 + helpers/contracts-deployments.ts | 99 +++++++++++++++-- helpers/contracts-getters.ts | 147 +++++++++++++++++--------- helpers/contracts-helpers.ts | 43 ++++++-- helpers/init-helpers.ts | 170 ++++++++---------------------- helpers/misc-utils.ts | 23 ++++ helpers/types.ts | 20 ++-- markets/aave/commons.ts | 44 ++++---- markets/aave/index.ts | 2 +- markets/aave/reservesConfigs.ts | 44 ++++---- markets/amm/commons.ts | 41 +++---- markets/amm/index.ts | 5 +- markets/matic/commons.ts | 2 + markets/xdai/commons.ts | 1 + tasks/dev/3_lending_pool.ts | 8 +- tasks/dev/4_oracles.ts | 25 +++-- tasks/dev/5_initialize.ts | 8 +- tasks/full/2_lending_pool.ts | 4 +- tasks/full/3_oracles.ts | 29 +++-- tasks/full/6-initialize.ts | 1 + tasks/helpers/deploy-new-asset.ts | 15 +-- 25 files changed, 592 insertions(+), 307 deletions(-) create mode 100644 contracts/misc/AaveOracleV2.sol diff --git a/contracts/misc/AaveOracleV2.sol b/contracts/misc/AaveOracleV2.sol new file mode 100644 index 00000000..8af3b08e --- /dev/null +++ b/contracts/misc/AaveOracleV2.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; + +import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; +import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; + +import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; +import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol'; +import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; + +/// @title AaveOracleV2 +/// @author Aave +/// @notice Proxy smart contract to get the price of an asset from a price source, with Chainlink Aggregator +/// smart contracts as primary option +/// - If the returned price by a Chainlink aggregator is <= 0, the call is forwarded to a fallbackOracle +/// - Owned by the Aave governance system, allowed to add sources for assets, replace them +/// and change the fallbackOracle +contract AaveOracleV2 is IPriceOracleGetter, Ownable { + using SafeERC20 for IERC20; + + event QuoteCurrencySet(address indexed quoteCurrency, uint256 quoteUnit); + event AssetSourceUpdated(address indexed asset, address indexed source); + event FallbackOracleUpdated(address indexed fallbackOracle); + + mapping(address => IChainlinkAggregator) private assetsSources; + IPriceOracleGetter private _fallbackOracle; + address public immutable QUOTE_CURRENCY; + uint256 public immutable QUOTE_CURRENCY_UNIT; + + /// @notice Constructor + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + /// @param fallbackOracle The address of the fallback oracle to use if the data of an + /// aggregator is not consistent + constructor( + address[] memory assets, + address[] memory sources, + address fallbackOracle, + address quoteCurrency, + uint256 quoteCurrencyUnits + ) public { + _setFallbackOracle(fallbackOracle); + _setAssetsSources(assets, sources); + QUOTE_CURRENCY = quoteCurrency; + QUOTE_CURRENCY_UNIT = quoteCurrencyUnits; + emit QuoteCurrencySet(quoteCurrency, quoteCurrencyUnits); + } + + /// @notice External function called by the Aave governance to set or replace sources of assets + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + function setAssetSources(address[] calldata assets, address[] calldata sources) + external + onlyOwner + { + _setAssetsSources(assets, sources); + } + + /// @notice Sets the fallbackOracle + /// - Callable only by the Aave governance + /// @param fallbackOracle The address of the fallbackOracle + function setFallbackOracle(address fallbackOracle) external onlyOwner { + _setFallbackOracle(fallbackOracle); + } + + /// @notice Internal function to set the sources for each asset + /// @param assets The addresses of the assets + /// @param sources The address of the source of each asset + function _setAssetsSources(address[] memory assets, address[] memory sources) internal { + require(assets.length == sources.length, 'INCONSISTENT_PARAMS_LENGTH'); + for (uint256 i = 0; i < assets.length; i++) { + assetsSources[assets[i]] = IChainlinkAggregator(sources[i]); + emit AssetSourceUpdated(assets[i], sources[i]); + } + } + + /// @notice Internal function to set the fallbackOracle + /// @param fallbackOracle The address of the fallbackOracle + function _setFallbackOracle(address fallbackOracle) internal { + _fallbackOracle = IPriceOracleGetter(fallbackOracle); + emit FallbackOracleUpdated(fallbackOracle); + } + + /// @notice Gets an asset price by address + /// @param asset The asset address + function getAssetPrice(address asset) public view override returns (uint256) { + IChainlinkAggregator source = assetsSources[asset]; + + if (asset == QUOTE_CURRENCY) { + return QUOTE_CURRENCY_UNIT; + } else if (address(source) == address(0)) { + return _fallbackOracle.getAssetPrice(asset); + } else { + int256 price = IChainlinkAggregator(source).latestAnswer(); + if (price > 0) { + return uint256(price); + } else { + return _fallbackOracle.getAssetPrice(asset); + } + } + } + + /// @notice Gets a list of prices from a list of assets addresses + /// @param assets The list of assets addresses + function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) { + uint256[] memory prices = new uint256[](assets.length); + for (uint256 i = 0; i < assets.length; i++) { + prices[i] = getAssetPrice(assets[i]); + } + return prices; + } + + /// @notice Gets the address of the source for an asset address + /// @param asset The address of the asset + /// @return address The address of the source + function getSourceOfAsset(address asset) external view returns (address) { + return address(assetsSources[asset]); + } + + /// @notice Gets the address of the fallback oracle + /// @return address The addres of the fallback oracle + function getFallbackOracle() external view returns (address) { + return address(_fallbackOracle); + } +} diff --git a/hardhat.config.ts b/hardhat.config.ts index dc47392f..5b263e36 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -102,7 +102,7 @@ const buidlerConfig: HardhatUserConfig = { kovan: getCommonNetworkConfig(eEthereumNetwork.kovan, 42), ropsten: getCommonNetworkConfig(eEthereumNetwork.ropsten, 3), main: getCommonNetworkConfig(eEthereumNetwork.main, 1), - tenderlyMain: getCommonNetworkConfig(eEthereumNetwork.tenderlyMain, 3030), + tenderly: getCommonNetworkConfig(eEthereumNetwork.tenderly, 3030), matic: getCommonNetworkConfig(ePolygonNetwork.matic, 137), mumbai: getCommonNetworkConfig(ePolygonNetwork.mumbai, 80001), xdai: getCommonNetworkConfig(eXDaiNetwork.xdai, 100), diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index 6747c444..374b9403 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -46,7 +46,7 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { [eEthereumNetwork.coverage]: 'http://localhost:8555', [eEthereumNetwork.hardhat]: 'http://localhost:8545', [eEthereumNetwork.buidlerevm]: 'http://localhost:8545', - [eEthereumNetwork.tenderlyMain]: `https://rpc.tenderly.co/fork/${TENDERLY_FORK_ID}`, + [eEthereumNetwork.tenderly]: `https://rpc.tenderly.co/fork/`, [ePolygonNetwork.mumbai]: 'https://rpc-mumbai.maticvigil.com', [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', [eXDaiNetwork.xdai]: 'https://rpc.xdaichain.com/', @@ -61,7 +61,7 @@ export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { [eEthereumNetwork.coverage]: 65 * GWEI, [eEthereumNetwork.hardhat]: 65 * GWEI, [eEthereumNetwork.buidlerevm]: 65 * GWEI, - [eEthereumNetwork.tenderlyMain]: 0.01 * GWEI, + [eEthereumNetwork.tenderly]: 1 * GWEI, [ePolygonNetwork.mumbai]: 1 * GWEI, [ePolygonNetwork.matic]: 1 * GWEI, [eXDaiNetwork.xdai]: 1 * GWEI, @@ -76,7 +76,7 @@ export const BLOCK_TO_FORK: iParamsPerNetwork = { [eEthereumNetwork.coverage]: undefined, [eEthereumNetwork.hardhat]: undefined, [eEthereumNetwork.buidlerevm]: undefined, - [eEthereumNetwork.tenderlyMain]: 12406069, + [eEthereumNetwork.tenderly]: undefined, [ePolygonNetwork.mumbai]: undefined, [ePolygonNetwork.matic]: undefined, [eXDaiNetwork.xdai]: undefined, diff --git a/helpers/configuration.ts b/helpers/configuration.ts index 5ba2c386..eb33d135 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -3,14 +3,15 @@ import { iMultiPoolsAssets, IReserveParams, PoolConfiguration, - ICommonConfiguration, eNetwork, + IBaseConfiguration, } from './types'; import { getEthersSignersAddresses, getParamPerPool } from './contracts-helpers'; import AaveConfig from '../markets/aave'; import MaticConfig from '../markets/matic'; import AvalancheConfig from '../markets/avalanche'; import AmmConfig from '../markets/amm'; + import { CommonsConfig } from '../markets/aave/commons'; import { DRE, filterMapBy } from './misc-utils'; import { tEthereumAddress } from './types'; @@ -66,7 +67,7 @@ export const getReservesConfigByPool = (pool: AavePools): iMultiPoolsAssets => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const targetAddress = getParamPerNetwork(config.PoolAdmin, currentNetwork); @@ -78,9 +79,7 @@ export const getGenesisPoolAdmin = async ( return addressList[addressIndex]; }; -export const getEmergencyAdmin = async ( - config: ICommonConfiguration -): Promise => { +export const getEmergencyAdmin = async (config: IBaseConfiguration): Promise => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const targetAddress = getParamPerNetwork(config.EmergencyAdmin, currentNetwork); if (targetAddress) { @@ -91,19 +90,17 @@ export const getEmergencyAdmin = async ( return addressList[addressIndex]; }; -export const getTreasuryAddress = async ( - config: ICommonConfiguration -): Promise => { +export const getTreasuryAddress = async (config: IBaseConfiguration): Promise => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; return getParamPerNetwork(config.ReserveFactorTreasuryAddress, currentNetwork); }; export const getATokenDomainSeparatorPerNetwork = ( network: eNetwork, - config: ICommonConfiguration + config: IBaseConfiguration ): tEthereumAddress => getParamPerNetwork(config.ATokenDomainSeparator, network); -export const getWethAddress = async (config: ICommonConfiguration) => { +export const getWethAddress = async (config: IBaseConfiguration) => { const currentNetwork = process.env.FORK ? process.env.FORK : DRE.network.name; const wethAddress = getParamPerNetwork(config.WETH, currentNetwork); if (wethAddress) { @@ -116,7 +113,7 @@ export const getWethAddress = async (config: ICommonConfiguration) => { return weth.address; }; -export const getWrappedNativeTokenAddress = async (config: ICommonConfiguration) => { +export const getWrappedNativeTokenAddress = async (config: IBaseConfiguration) => { const currentNetwork = process.env.MAINNET_FORK === 'true' ? 'main' : DRE.network.name; const wethAddress = getParamPerNetwork(config.WrappedNativeToken, currentNetwork); if (wethAddress) { @@ -129,7 +126,7 @@ export const getWrappedNativeTokenAddress = async (config: ICommonConfiguration) return weth.address; }; -export const getLendingRateOracles = (poolConfig: ICommonConfiguration) => { +export const getLendingRateOracles = (poolConfig: IBaseConfiguration) => { const { ProtocolGlobalParams: { UsdAddress }, LendingRateOracleRatesCommon, @@ -141,3 +138,15 @@ export const getLendingRateOracles = (poolConfig: ICommonConfiguration) => { Object.keys(ReserveAssets[network]).includes(key) ); }; + +export const getQuoteCurrency = async (config: IBaseConfiguration) => { + switch (config.OracleQuoteCurrency) { + case 'ETH': + case 'WETH': + return getWethAddress(config); + case 'USD': + return config.ProtocolGlobalParams.UsdAddress; + default: + throw `Quote ${config.OracleQuoteCurrency} currency not set. Add a new case to getQuoteCurrency switch`; + } +}; diff --git a/helpers/constants.ts b/helpers/constants.ts index acd1d14d..c1defc3c 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -1,4 +1,5 @@ import BigNumber from 'bignumber.js'; +import { eEthereumNetwork } from './types'; // ---------------- // MATH @@ -12,6 +13,7 @@ export const RAY = new BigNumber(10).exponentiatedBy(27).toFixed(); export const HALF_RAY = new BigNumber(RAY).multipliedBy(0.5).toFixed(); export const WAD_RAY_RATIO = Math.pow(10, 9).toString(); export const oneEther = new BigNumber(Math.pow(10, 18)); +export const oneUsd = new BigNumber(Math.pow(10, 8)); export const oneRay = new BigNumber(Math.pow(10, 27)); export const MAX_UINT_AMOUNT = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 2d764885..ef8c729e 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -1,5 +1,5 @@ import { Contract } from 'ethers'; -import { DRE } from './misc-utils'; +import { DRE, notFalsyOrZeroAddress } from './misc-utils'; import { tEthereumAddress, eContractid, @@ -13,9 +13,8 @@ import { } from './types'; import { MintableERC20 } from '../types/MintableERC20'; import { MockContract } from 'ethereum-waffle'; -import { getReservesConfigByPool } from './configuration'; +import { ConfigNames, getReservesConfigByPool, loadPoolConfig } from './configuration'; import { getFirstSigner } from './contracts-getters'; -import { ZERO_ADDRESS } from './constants'; import { AaveProtocolDataProviderFactory, ATokenFactory, @@ -49,6 +48,7 @@ import { WETH9MockedFactory, WETHGatewayFactory, FlashLiquidationAdapterFactory, + AaveOracleV2Factory, } from '../types'; import { withSaveAndVerify, @@ -57,6 +57,7 @@ import { insertContractAddressInDb, deployContract, verifyContract, + getOptionalParamAddressPerNetwork, } from './contracts-helpers'; import { StableAndVariableTokensHelperFactory } from '../types/StableAndVariableTokensHelperFactory'; import { MintableDelegationERC20 } from '../types/MintableDelegationERC20'; @@ -64,6 +65,7 @@ import { readArtifact as buidlerReadArtifact } from '@nomiclabs/buidler/plugins' import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { LendingPoolLibraryAddresses } from '../types/LendingPoolFactory'; import { UiPoolDataProvider } from '../types'; +import { eNetwork } from './types'; export const deployUiPoolDataProvider = async ( [incentivesController, aaveOracle]: [tEthereumAddress, tEthereumAddress], @@ -233,6 +235,17 @@ export const deployAaveOracle = async ( verify ); +export const deployAaveOracleV2 = async ( + args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress, string], + verify?: boolean +) => + withSaveAndVerify( + await new AaveOracleV2Factory(await getFirstSigner()).deploy(...args), + eContractid.AaveOracleV2, + args, + verify + ); + export const deployLendingPoolCollateralManager = async (verify?: boolean) => { const collateralManagerImpl = await new LendingPoolCollateralManagerFactory( await getFirstSigner() @@ -351,20 +364,20 @@ export const deployVariableDebtToken = async ( return instance; }; -export const deployGenericStableDebtToken = async () => +export const deployGenericStableDebtToken = async (verify?: boolean) => withSaveAndVerify( await new StableDebtTokenFactory(await getFirstSigner()).deploy(), eContractid.StableDebtToken, [], - false + verify ); -export const deployGenericVariableDebtToken = async () => +export const deployGenericVariableDebtToken = async (verify?: boolean) => withSaveAndVerify( await new VariableDebtTokenFactory(await getFirstSigner()).deploy(), eContractid.VariableDebtToken, [], - false + verify ); export const deployGenericAToken = async ( @@ -637,3 +650,75 @@ export const deployFlashLiquidationAdapter = async ( args, verify ); + +export const chooseATokenDeployment = (id: eContractid) => { + switch (id) { + case eContractid.AToken: + return deployGenericATokenImpl; + case eContractid.DelegationAwareAToken: + return deployDelegationAwareATokenImpl; + default: + throw Error(`Missing aToken implementation deployment script for: ${id}`); + } +}; + +export const deployATokenImplementations = async ( + pool: ConfigNames, + reservesConfig: { [key: string]: IReserveParams }, + verify = false +) => { + const poolConfig = loadPoolConfig(pool); + const network = DRE.network.name; + + // Obtain the different AToken implementations of all reserves inside the Market config + const aTokenImplementations = [ + ...Object.entries(reservesConfig).reduce>((acc, [, entry]) => { + acc.add(entry.aTokenImpl); + return acc; + }, new Set()), + ]; + + console.log(aTokenImplementations); + + for (let x = 0; x < aTokenImplementations.length; x++) { + const aTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig[aTokenImplementations[x].toString()], + network + ); + if (!notFalsyOrZeroAddress(aTokenAddress)) { + const deployImplementationMethod = chooseATokenDeployment(aTokenImplementations[x]); + console.log(`Deploying implementation`, aTokenImplementations[x]); + await deployImplementationMethod(verify); + } + } + + // Debt tokens, for now all Market configs follows same implementations + const genericStableDebtTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig.StableDebtTokenImplementation, + network + ); + const geneticVariableDebtTokenAddress = getOptionalParamAddressPerNetwork( + poolConfig.VariableDebtTokenImplementation, + network + ); + + if (!notFalsyOrZeroAddress(genericStableDebtTokenAddress)) { + await deployGenericStableDebtToken(verify); + } + if (!notFalsyOrZeroAddress(geneticVariableDebtTokenAddress)) { + await deployGenericVariableDebtToken(verify); + } +}; + +export const deployRateStrategy = async ( + strategyName: string, + args: [tEthereumAddress, string, string, string, string, string, string], + verify: boolean +): Promise => { + switch (strategyName) { + default: + return await ( + await deployDefaultReserveInterestRateStrategy(args, verify) + ).address; + } +}; diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index b441363c..21641d97 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -33,7 +33,7 @@ import { } from '../types'; import { IERC20DetailedFactory } from '../types/IERC20DetailedFactory'; import { getEthersSigners, MockTokenMap } from './contracts-helpers'; -import { DRE, getDb, notFalsyOrZeroAddress } from './misc-utils'; +import { DRE, getDb, notFalsyOrZeroAddress, omit } from './misc-utils'; import { eContractid, PoolConfiguration, tEthereumAddress, TokenContractId } from './types'; export const getFirstSigner = async () => (await getEthersSigners())[0]; @@ -41,16 +41,18 @@ export const getFirstSigner = async () => (await getEthersSigners())[0]; export const getLendingPoolAddressesProvider = async (address?: tEthereumAddress) => { return await LendingPoolAddressesProviderFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); }; export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress) => { return await LendingPoolConfiguratorFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolConfigurator}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolConfigurator}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); }; @@ -58,14 +60,18 @@ export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress export const getLendingPool = async (address?: tEthereumAddress) => await LendingPoolFactory.connect( address || - (await getDb().get(`${eContractid.LendingPool}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingPool}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getPriceOracle = async (address?: tEthereumAddress) => await PriceOracleFactory.connect( address || - (await getDb().get(`${eContractid.PriceOracle}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.PriceOracle}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -78,36 +84,45 @@ export const getAToken = async (address?: tEthereumAddress) => export const getStableDebtToken = async (address?: tEthereumAddress) => await StableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.StableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.StableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getVariableDebtToken = async (address?: tEthereumAddress) => await VariableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.VariableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.VariableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getMintableERC20 = async (address: tEthereumAddress) => await MintableERC20Factory.connect( address || - (await getDb().get(`${eContractid.MintableERC20}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.MintableERC20}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getIErc20Detailed = async (address: tEthereumAddress) => await IERC20DetailedFactory.connect( address || - (await getDb().get(`${eContractid.IERC20Detailed}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.IERC20Detailed}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getAaveProtocolDataProvider = async (address?: tEthereumAddress) => await AaveProtocolDataProviderFactory.connect( address || - (await getDb().get(`${eContractid.AaveProtocolDataProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.AaveProtocolDataProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -125,15 +140,18 @@ export const getInterestRateStrategy = async (address?: tEthereumAddress) => export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => await MockFlashLoanReceiverFactory.connect( address || - (await getDb().get(`${eContractid.MockFlashLoanReceiver}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockFlashLoanReceiver}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingRateOracle = async (address?: tEthereumAddress) => await LendingRateOracleFactory.connect( address || - (await getDb().get(`${eContractid.LendingRateOracle}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingRateOracle}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -166,23 +184,37 @@ export const getAllMockedTokens = async () => { return tokens; }; +export const getQuoteCurrencies = (oracleQuoteCurrency: string): string[] => { + switch (oracleQuoteCurrency) { + case 'USD': + return ['USD']; + case 'ETH': + case 'WETH': + default: + return ['ETH', 'WETH']; + } +}; + export const getPairsTokenAggregator = ( allAssetsAddresses: { [tokenSymbol: string]: tEthereumAddress; }, - aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress } + aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress }, + oracleQuoteCurrency: string ): [string[], string[]] => { - const { ETH, WETH, ...assetsAddressesWithoutEth } = allAssetsAddresses; + const assetsWithoutQuoteCurrency = omit( + allAssetsAddresses, + getQuoteCurrencies(oracleQuoteCurrency) + ); - const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => { + const pairs = Object.entries(assetsWithoutQuoteCurrency).map(([tokenSymbol, tokenAddress]) => { //if (true/*tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH' && tokenSymbol !== 'LpWETH'*/) { const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( (value) => value === tokenSymbol ); - const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ - string, - tEthereumAddress - ][])[aggregatorAddressIndex]; + const [, aggregatorAddress] = ( + Object.entries(aggregatorsAddresses) as [string, tEthereumAddress][] + )[aggregatorAddressIndex]; return [tokenAddress, aggregatorAddress]; //} }) as [string, string][]; @@ -208,14 +240,18 @@ export const getLendingPoolAddressesProviderRegistry = async (address?: tEthereu export const getReserveLogic = async (address?: tEthereumAddress) => await ReserveLogicFactory.connect( address || - (await getDb().get(`${eContractid.ReserveLogic}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.ReserveLogic}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getGenericLogic = async (address?: tEthereumAddress) => await GenericLogicFactory.connect( address || - (await getDb().get(`${eContractid.GenericLogic}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.GenericLogic}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -233,15 +269,18 @@ export const getStableAndVariableTokensHelper = async (address?: tEthereumAddres export const getATokensAndRatesHelper = async (address?: tEthereumAddress) => await ATokensAndRatesHelperFactory.connect( address || - (await getDb().get(`${eContractid.ATokensAndRatesHelper}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.ATokensAndRatesHelper}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getWETHGateway = async (address?: tEthereumAddress) => await WETHGatewayFactory.connect( address || - (await getDb().get(`${eContractid.WETHGateway}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.WETHGateway}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -260,23 +299,27 @@ export const getMockAToken = async (address?: tEthereumAddress) => export const getMockVariableDebtToken = async (address?: tEthereumAddress) => await MockVariableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.MockVariableDebtToken}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockVariableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getMockStableDebtToken = async (address?: tEthereumAddress) => await MockStableDebtTokenFactory.connect( address || - (await getDb().get(`${eContractid.MockStableDebtToken}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.MockStableDebtToken}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getSelfdestructTransferMock = async (address?: tEthereumAddress) => await SelfdestructTransferFactory.connect( address || - (await getDb().get(`${eContractid.SelfdestructTransferMock}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.SelfdestructTransferMock}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -286,15 +329,18 @@ export const getProxy = async (address: tEthereumAddress) => export const getLendingPoolImpl = async (address?: tEthereumAddress) => await LendingPoolFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolImpl}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.LendingPoolImpl}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingPoolConfiguratorImpl = async (address?: tEthereumAddress) => await LendingPoolConfiguratorFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolConfiguratorImpl}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolConfiguratorImpl}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -312,16 +358,18 @@ export const getLendingPoolCollateralManagerImpl = async (address?: tEthereumAdd export const getWalletProvider = async (address?: tEthereumAddress) => await WalletBalanceProviderFactory.connect( address || - (await getDb().get(`${eContractid.WalletBalanceProvider}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.WalletBalanceProvider}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getLendingPoolCollateralManager = async (address?: tEthereumAddress) => await LendingPoolCollateralManagerFactory.connect( address || - (await getDb().get(`${eContractid.LendingPoolCollateralManager}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.LendingPoolCollateralManager}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); @@ -337,30 +385,35 @@ export const getAaveOracle = async (address?: tEthereumAddress) => export const getMockUniswapRouter = async (address?: tEthereumAddress) => await MockUniswapV2Router02Factory.connect( address || - (await getDb().get(`${eContractid.MockUniswapV2Router02}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.MockUniswapV2Router02}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getUniswapLiquiditySwapAdapter = async (address?: tEthereumAddress) => await UniswapLiquiditySwapAdapterFactory.connect( address || - (await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getUniswapRepayAdapter = async (address?: tEthereumAddress) => await UniswapRepayAdapterFactory.connect( address || - (await getDb().get(`${eContractid.UniswapRepayAdapter}.${DRE.network.name}`).value()).address, + ( + await getDb().get(`${eContractid.UniswapRepayAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); export const getFlashLiquidationAdapter = async (address?: tEthereumAddress) => await FlashLiquidationAdapterFactory.connect( address || - (await getDb().get(`${eContractid.FlashLiquidationAdapter}.${DRE.network.name}`).value()) - .address, + ( + await getDb().get(`${eContractid.FlashLiquidationAdapter}.${DRE.network.name}`).value() + ).address, await getFirstSigner() ); diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index 57becdad..fd310e90 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -2,7 +2,7 @@ import { Contract, Signer, utils, ethers, BigNumberish } from 'ethers'; import { signTypedData_v4 } from 'eth-sig-util'; import { fromRpcSig, ECDSASignature } from 'ethereumjs-util'; import BigNumber from 'bignumber.js'; -import { getDb, DRE, waitForTx } from './misc-utils'; +import { getDb, DRE, waitForTx, notFalsyOrZeroAddress } from './misc-utils'; import { tEthereumAddress, eContractid, @@ -14,7 +14,6 @@ import { ePolygonNetwork, eXDaiNetwork, eNetwork, - iParamsPerNetworkAll, iEthereumParamsPerNetwork, iPolygonParamsPerNetwork, iXDaiParamsPerNetwork, @@ -28,6 +27,8 @@ import { verifyEtherscanContract } from './etherscan-verification'; import { getFirstSigner, getIErc20Detailed } from './contracts-getters'; import { usingTenderly, verifyAtTenderly } from './tenderly-utils'; import { usingPolygon, verifyAtPolygon } from './polygon-utils'; +import { ConfigNames, loadPoolConfig } from './configuration'; +import { ZERO_ADDRESS } from './constants'; import { getDefenderRelaySigner, usingDefender } from './defender-utils'; export type MockTokenMap = { [symbol: string]: MintableERC20 }; @@ -144,7 +145,7 @@ export const linkBytecode = (artifact: BuidlerArtifact | Artifact, libraries: an }; export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNetwork) => { - const { main, ropsten, kovan, coverage, buidlerevm, tenderlyMain } = + const { main, ropsten, kovan, coverage, buidlerevm, tenderly } = param as iEthereumParamsPerNetwork; const { matic, mumbai } = param as iPolygonParamsPerNetwork; const { xdai } = param as iXDaiParamsPerNetwork; @@ -166,8 +167,8 @@ export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNet return ropsten; case eEthereumNetwork.main: return main; - case eEthereumNetwork.tenderlyMain: - return tenderlyMain; + case eEthereumNetwork.tenderly: + return tenderly; case ePolygonNetwork.matic: return matic; case ePolygonNetwork.mumbai: @@ -181,7 +182,17 @@ export const getParamPerNetwork = (param: iParamsPerNetwork, network: eNet } }; -export const getParamPerPool = ({ proto, amm, matic, avalanche }: iParamsPerPool, pool: AavePools) => { +export const getOptionalParamAddressPerNetwork = ( + param: iParamsPerNetwork | undefined | null, + network: eNetwork +) => { + if (!param) { + return ZERO_ADDRESS; + } + return getParamPerNetwork(param, network); +}; + +export const getParamPerPool = ({ proto, amm, matic }: iParamsPerPool, pool: AavePools) => { switch (pool) { case AavePools.proto: return proto; @@ -345,3 +356,23 @@ export const verifyContract = async ( } return instance; }; + +export const getContractAddressWithJsonFallback = async ( + id: string, + pool: ConfigNames +): Promise => { + const poolConfig = loadPoolConfig(pool); + const network = DRE.network.name; + const db = getDb(); + + const contractAtMarketConfig = getOptionalParamAddressPerNetwork(poolConfig[id], network); + if (notFalsyOrZeroAddress(contractAtMarketConfig)) { + return contractAtMarketConfig; + } + + const contractAtDb = await getDb().get(`${id}.${DRE.network.name}`).value(); + if (contractAtDb?.address) { + return contractAtDb.address as tEthereumAddress; + } + throw Error(`Missing contract address ${id} at Market config and JSON local db`); +}; diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index a3035692..6f1de0ab 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -1,48 +1,31 @@ import { eContractid, - eEthereumNetwork, eNetwork, iMultiPoolsAssets, IReserveParams, tEthereumAddress, } from './types'; import { AaveProtocolDataProvider } from '../types/AaveProtocolDataProvider'; -import { chunk, DRE, getDb, waitForTx } from './misc-utils'; +import { chunk, getDb, waitForTx } from './misc-utils'; import { - getAaveProtocolDataProvider, getAToken, getATokensAndRatesHelper, - getFirstSigner, getLendingPoolAddressesProvider, getLendingPoolConfiguratorProxy, - getStableAndVariableTokensHelper, } from './contracts-getters'; -import { rawInsertContractAddressInDb } from './contracts-helpers'; -import { BigNumber, BigNumberish, Signer } from 'ethers'; import { - deployDefaultReserveInterestRateStrategy, - deployDelegationAwareAToken, - deployDelegationAwareATokenImpl, - deployGenericAToken, - deployGenericATokenImpl, - deployGenericStableDebtToken, - deployGenericVariableDebtToken, - deployStableDebtToken, - deployVariableDebtToken, -} from './contracts-deployments'; -import { ZERO_ADDRESS } from './constants'; -import { isZeroAddress } from 'ethereumjs-util'; -import { DefaultReserveInterestRateStrategy, DelegationAwareAToken } from '../types'; -import { config } from 'process'; + getContractAddressWithJsonFallback, + rawInsertContractAddressInDb, +} from './contracts-helpers'; +import { BigNumberish } from 'ethers'; +import { ConfigNames } from './configuration'; +import { deployRateStrategy } from './contracts-deployments'; -export const chooseATokenDeployment = (id: eContractid) => { - switch (id) { - case eContractid.AToken: - return deployGenericAToken; - case eContractid.DelegationAwareAToken: - return deployDelegationAwareAToken; +export const getATokenExtraParams = async (aTokenName: string, tokenAddress: tEthereumAddress) => { + console.log(aTokenName); + switch (aTokenName) { default: - throw Error(`Missing aToken deployment script for: ${id}`); + return '0x10'; } }; @@ -56,19 +39,15 @@ export const initReservesByHelper = async ( admin: tEthereumAddress, treasuryAddress: tEthereumAddress, incentivesController: tEthereumAddress, + poolName: ConfigNames, verify: boolean -): Promise => { - let gasUsage = BigNumber.from('0'); - const stableAndVariableDeployer = await getStableAndVariableTokensHelper(); - +) => { const addressProvider = await getLendingPoolAddressesProvider(); // CHUNK CONFIGURATION - const initChunks = 4; + const initChunks = 1; // Initialize variables for future reserves initialization - let reserveTokens: string[] = []; - let reserveInitDecimals: string[] = []; let reserveSymbols: string[] = []; let initInputParams: { @@ -101,49 +80,8 @@ export const initReservesByHelper = async ( ]; let rateStrategies: Record = {}; let strategyAddresses: Record = {}; - let strategyAddressPerAsset: Record = {}; - let aTokenType: Record = {}; - let delegationAwareATokenImplementationAddress = ''; - let aTokenImplementationAddress = ''; - let stableDebtTokenImplementationAddress = ''; - let variableDebtTokenImplementationAddress = ''; - // NOT WORKING ON MATIC, DEPLOYING INDIVIDUAL IMPLs INSTEAD - // const tx1 = await waitForTx( - // await stableAndVariableDeployer.initDeployment([ZERO_ADDRESS], ["1"]) - // ); - // console.log(tx1.events); - // tx1.events?.forEach((event, index) => { - // stableDebtTokenImplementationAddress = event?.args?.stableToken; - // variableDebtTokenImplementationAddress = event?.args?.variableToken; - // rawInsertContractAddressInDb(`stableDebtTokenImpl`, stableDebtTokenImplementationAddress); - // rawInsertContractAddressInDb(`variableDebtTokenImpl`, variableDebtTokenImplementationAddress); - // }); - //gasUsage = gasUsage.add(tx1.gasUsed); - stableDebtTokenImplementationAddress = await (await deployGenericStableDebtToken()).address; - variableDebtTokenImplementationAddress = await (await deployGenericVariableDebtToken()).address; - - const aTokenImplementation = await deployGenericATokenImpl(verify); - aTokenImplementationAddress = aTokenImplementation.address; - rawInsertContractAddressInDb(`aTokenImpl`, aTokenImplementationAddress); - - const delegatedAwareReserves = Object.entries(reservesParams).filter( - ([_, { aTokenImpl }]) => aTokenImpl === eContractid.DelegationAwareAToken - ) as [string, IReserveParams][]; - - if (delegatedAwareReserves.length > 0) { - const delegationAwareATokenImplementation = await deployDelegationAwareATokenImpl(verify); - delegationAwareATokenImplementationAddress = delegationAwareATokenImplementation.address; - rawInsertContractAddressInDb( - `delegationAwareATokenImpl`, - delegationAwareATokenImplementationAddress - ); - } - - const reserves = Object.entries(reservesParams).filter( - ([_, { aTokenImpl }]) => - aTokenImpl === eContractid.DelegationAwareAToken || aTokenImpl === eContractid.AToken - ) as [string, IReserveParams][]; + const reserves = Object.entries(reservesParams); for (let [symbol, params] of reserves) { if (!tokenAddresses[symbol]) { @@ -170,52 +108,41 @@ export const initReservesByHelper = async ( stableRateSlope1, stableRateSlope2, ]; - strategyAddresses[strategy.name] = ( - await deployDefaultReserveInterestRateStrategy(rateStrategies[strategy.name], verify) - ).address; + strategyAddresses[strategy.name] = await deployRateStrategy( + strategy.name, + rateStrategies[strategy.name], + verify + ); + // This causes the last strategy to be printed twice, once under "DefaultReserveInterestRateStrategy" // and once under the actual `strategyASSET` key. rawInsertContractAddressInDb(strategy.name, strategyAddresses[strategy.name]); } - strategyAddressPerAsset[symbol] = strategyAddresses[strategy.name]; - console.log('Strategy address for asset %s: %s', symbol, strategyAddressPerAsset[symbol]); - - if (aTokenImpl === eContractid.AToken) { - aTokenType[symbol] = 'generic'; - } else if (aTokenImpl === eContractid.DelegationAwareAToken) { - aTokenType[symbol] = 'delegation aware'; - } - - reserveInitDecimals.push(reserveDecimals); - reserveTokens.push(tokenAddresses[symbol]); + // Prepare input parameters reserveSymbols.push(symbol); - } - - for (let i = 0; i < reserveSymbols.length; i++) { - let aTokenToUse: string; - if (aTokenType[reserveSymbols[i]] === 'generic') { - aTokenToUse = aTokenImplementationAddress; - } else { - aTokenToUse = delegationAwareATokenImplementationAddress; - } - initInputParams.push({ - aTokenImpl: aTokenToUse, - stableDebtTokenImpl: stableDebtTokenImplementationAddress, - variableDebtTokenImpl: variableDebtTokenImplementationAddress, - underlyingAssetDecimals: reserveInitDecimals[i], - interestRateStrategyAddress: strategyAddressPerAsset[reserveSymbols[i]], - underlyingAsset: reserveTokens[i], + aTokenImpl: await getContractAddressWithJsonFallback(aTokenImpl, poolName), + stableDebtTokenImpl: await getContractAddressWithJsonFallback( + eContractid.StableDebtToken, + poolName + ), + variableDebtTokenImpl: await getContractAddressWithJsonFallback( + eContractid.VariableDebtToken, + poolName + ), + underlyingAssetDecimals: reserveDecimals, + interestRateStrategyAddress: strategyAddresses[strategy.name], + underlyingAsset: tokenAddresses[symbol], treasury: treasuryAddress, - incentivesController, - underlyingAssetName: reserveSymbols[i], - aTokenName: `${aTokenNamePrefix} ${reserveSymbols[i]}`, - aTokenSymbol: `a${symbolPrefix}${reserveSymbols[i]}`, - variableDebtTokenName: `${variableDebtTokenNamePrefix} ${symbolPrefix}${reserveSymbols[i]}`, - variableDebtTokenSymbol: `variableDebt${symbolPrefix}${reserveSymbols[i]}`, - stableDebtTokenName: `${stableDebtTokenNamePrefix} ${reserveSymbols[i]}`, - stableDebtTokenSymbol: `stableDebt${symbolPrefix}${reserveSymbols[i]}`, - params: '0x10', + incentivesController: incentivesController, + underlyingAssetName: symbol, + aTokenName: `${aTokenNamePrefix} ${symbol}`, + aTokenSymbol: `a${symbolPrefix}${symbol}`, + variableDebtTokenName: `${variableDebtTokenNamePrefix} ${symbolPrefix}${symbol}`, + variableDebtTokenSymbol: `variableDebt${symbolPrefix}${symbol}`, + stableDebtTokenName: `${stableDebtTokenNamePrefix} ${symbol}`, + stableDebtTokenSymbol: `stableDebt${symbolPrefix}${symbol}`, + params: await getATokenExtraParams(aTokenImpl, tokenAddresses[symbol]), }); } @@ -224,7 +151,6 @@ export const initReservesByHelper = async ( const chunkedInitInputParams = chunk(initInputParams, initChunks); const configurator = await getLendingPoolConfiguratorProxy(); - //await waitForTx(await addressProvider.setPoolAdmin(admin)); console.log(`- Reserves initialization in ${chunkedInitInputParams.length} txs`); for (let chunkIndex = 0; chunkIndex < chunkedInitInputParams.length; chunkIndex++) { @@ -234,10 +160,7 @@ export const initReservesByHelper = async ( console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`); console.log(' * gasUsed', tx3.gasUsed.toString()); - //gasUsage = gasUsage.add(tx3.gasUsed); } - - return gasUsage; // Deprecated }; export const getPairsTokenAggregator = ( @@ -253,10 +176,9 @@ export const getPairsTokenAggregator = ( const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( (value) => value === tokenSymbol ); - const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ - string, - tEthereumAddress - ][])[aggregatorAddressIndex]; + const [, aggregatorAddress] = ( + Object.entries(aggregatorsAddresses) as [string, tEthereumAddress][] + )[aggregatorAddressIndex]; return [tokenAddress, aggregatorAddress]; } }) as [string, string][]; diff --git a/helpers/misc-utils.ts b/helpers/misc-utils.ts index 0315dfe0..c0456a0c 100644 --- a/helpers/misc-utils.ts +++ b/helpers/misc-utils.ts @@ -9,6 +9,8 @@ import { BuidlerRuntimeEnvironment } from '@nomiclabs/buidler/types'; import { tEthereumAddress } from './types'; import { isAddress } from 'ethers/lib/utils'; import { isZeroAddress } from 'ethereumjs-util'; +import { SignerWithAddress } from '../test-suites/test-aave/helpers/make-suite'; +import { usingTenderly } from './tenderly-utils'; export const toWad = (value: string | number) => new BigNumber(value).times(WAD).toFixed(); @@ -116,6 +118,27 @@ export const notFalsyOrZeroAddress = (address: tEthereumAddress | null | undefin return isAddress(address) && !isZeroAddress(address); }; +export const impersonateAddress = async (address: tEthereumAddress): Promise => { + if (!usingTenderly()) { + await (DRE as HardhatRuntimeEnvironment).network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [address], + }); + } + const signer = await DRE.ethers.provider.getSigner(address); + + return { + signer, + address, + }; +}; + +export const omit = (obj: T, keys: U[]): Omit => + (Object.keys(obj) as U[]).reduce( + (acc, curr) => (keys.includes(curr) ? acc : { ...acc, [curr]: obj[curr] }), + {} as Omit + ); + export const impersonateAccountsHardhat = async (accounts: string[]) => { if (process.env.TENDERLY === 'true') { return; diff --git a/helpers/types.ts b/helpers/types.ts index e2052c7f..53338c21 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -13,7 +13,7 @@ export enum eEthereumNetwork { main = 'main', coverage = 'coverage', hardhat = 'hardhat', - tenderlyMain = 'tenderlyMain', + tenderly = 'tenderly', } export enum ePolygonNetwork { @@ -96,6 +96,7 @@ export enum eContractid { UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter', UniswapRepayAdapter = 'UniswapRepayAdapter', FlashLiquidationAdapter = 'FlashLiquidationAdapter', + AaveOracleV2 = 'AaveOracleV2', } /* @@ -425,7 +426,7 @@ export interface iEthereumParamsPerNetwork { [eEthereumNetwork.ropsten]: T; [eEthereumNetwork.main]: T; [eEthereumNetwork.hardhat]: T; - [eEthereumNetwork.tenderlyMain]: T; + [eEthereumNetwork.tenderly]: T; } export interface iPolygonParamsPerNetwork { @@ -485,7 +486,7 @@ export interface ILendingRate { borrowRate: string; } -export interface ICommonConfiguration { +export interface IBaseConfiguration { MarketId: string; ATokenNamePrefix: string; StableDebtTokenNamePrefix: string; @@ -493,7 +494,6 @@ export interface ICommonConfiguration { SymbolPrefix: string; ProviderId: number; ProtocolGlobalParams: IProtocolGlobalConfig; - Mocks: IMocksConfig; ProviderRegistry: iParamsPerNetwork; ProviderRegistryOwner: iParamsPerNetwork; LendingPoolCollateralManager: iParamsPerNetwork; @@ -509,14 +509,22 @@ export interface ICommonConfiguration { PoolAdminIndex: number; EmergencyAdmin: iParamsPerNetwork; EmergencyAdminIndex: number; - ReserveAssets: iParamsPerNetwork>; - ReservesConfig: iMultiPoolsAssets; ATokenDomainSeparator: iParamsPerNetwork; WETH: iParamsPerNetwork; WrappedNativeToken: iParamsPerNetwork; WethGateway: iParamsPerNetwork; ReserveFactorTreasuryAddress: iParamsPerNetwork; IncentivesController: iParamsPerNetwork; + StableDebtTokenImplementation?: iParamsPerNetwork; + VariableDebtTokenImplementation?: iParamsPerNetwork; + ReserveAssets: iParamsPerNetwork>; + OracleQuoteCurrency: string; + OracleQuoteUnit: string; +} + +export interface ICommonConfiguration extends IBaseConfiguration { + ReservesConfig: iMultiPoolsAssets; + Mocks: IMocksConfig; } export interface IAaveConfiguration extends ICommonConfiguration { diff --git a/markets/aave/commons.ts b/markets/aave/commons.ts index 134e37eb..d0a34bcd 100644 --- a/markets/aave/commons.ts +++ b/markets/aave/commons.ts @@ -1,10 +1,8 @@ -import BigNumber from 'bignumber.js'; import { - oneEther, oneRay, - RAY, ZERO_ADDRESS, MOCK_CHAINLINK_AGGREGATORS_PRICES, + oneEther, } from '../../helpers/constants'; import { ICommonConfiguration, eEthereumNetwork } from '../../helpers/types'; @@ -19,6 +17,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave variable debt bearing', SymbolPrefix: '', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', @@ -113,7 +113,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, PoolAdminIndex: 0, EmergencyAdmin: { @@ -123,7 +123,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, EmergencyAdminIndex: 1, ProviderRegistry: { @@ -133,7 +133,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', + [eEthereumNetwork.tenderly]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', }, ProviderRegistryOwner: { [eEthereumNetwork.kovan]: '0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F', @@ -142,7 +142,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', + [eEthereumNetwork.tenderly]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', }, LendingRateOracle: { [eEthereumNetwork.coverage]: '', @@ -151,7 +151,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', //'0xdCde9Bb6a49e37fA433990832AB541AE2d4FEB4a', [eEthereumNetwork.ropsten]: '0x05dcca805a6562c1bdd0423768754acb6993241b', [eEthereumNetwork.main]: '', //'0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', - [eEthereumNetwork.tenderlyMain]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', + [eEthereumNetwork.tenderly]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', }, LendingPoolCollateralManager: { [eEthereumNetwork.coverage]: '', @@ -160,7 +160,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x9269b6453d0d75370c4c85e5a42977a53efdb72a', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', - [eEthereumNetwork.tenderlyMain]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', + [eEthereumNetwork.tenderly]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', }, LendingPoolConfigurator: { [eEthereumNetwork.coverage]: '', @@ -169,7 +169,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, LendingPool: { [eEthereumNetwork.coverage]: '', @@ -178,7 +178,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WethGateway: { [eEthereumNetwork.coverage]: '', @@ -187,7 +187,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, TokenDistributor: { [eEthereumNetwork.coverage]: '', @@ -196,7 +196,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x971efe90088f21dc6a36f610ffed77fc19710708', [eEthereumNetwork.ropsten]: '0xeba2ea67942b8250d870b12750b594696d02fc9c', [eEthereumNetwork.main]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', - [eEthereumNetwork.tenderlyMain]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', + [eEthereumNetwork.tenderly]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', }, AaveOracle: { [eEthereumNetwork.coverage]: '', @@ -205,7 +205,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', //'0xB8bE51E6563BB312Cbb2aa26e352516c25c26ac1', [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: '', //'0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', - [eEthereumNetwork.tenderlyMain]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', + [eEthereumNetwork.tenderly]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', }, FallbackOracle: { [eEthereumNetwork.coverage]: '', @@ -214,7 +214,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x50913E8E1c650E790F8a1E741FF9B1B1bB251dfe', [eEthereumNetwork.ropsten]: '0xAD1a978cdbb8175b2eaeC47B01404f8AEC5f4F0d', [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, ChainlinkAggregator: { [eEthereumNetwork.coverage]: {}, @@ -287,7 +287,7 @@ export const CommonsConfig: ICommonConfiguration = { USD: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419', xSUSHI: '0x9b26214bEC078E68a394AaEbfbffF406Ce14893F', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { AAVE: '0x6Df09E975c830ECae5bd4eD9d90f3A95a4f88012', BAT: '0x0d16d4528239e9ee52fa531af613AcdB23D88c94', BUSD: '0x614715d2Af89E6EC99A233818275142cE88d1Cfd', @@ -318,7 +318,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.main]: {}, [eEthereumNetwork.kovan]: {}, [eEthereumNetwork.ropsten]: {}, - [eEthereumNetwork.tenderlyMain]: {}, + [eEthereumNetwork.tenderly]: {}, }, ReservesConfig: {}, ATokenDomainSeparator: { @@ -331,7 +331,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WETH: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -340,7 +340,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, WrappedNativeToken: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -349,7 +349,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, ReserveFactorTreasuryAddress: { [eEthereumNetwork.coverage]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', @@ -358,7 +358,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.ropsten]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.main]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', - [eEthereumNetwork.tenderlyMain]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', + [eEthereumNetwork.tenderly]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', }, IncentivesController: { [eEthereumNetwork.coverage]: ZERO_ADDRESS, @@ -367,6 +367,6 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: ZERO_ADDRESS, [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, }; diff --git a/markets/aave/index.ts b/markets/aave/index.ts index 2ff2be79..72f25152 100644 --- a/markets/aave/index.ts +++ b/markets/aave/index.ts @@ -128,7 +128,7 @@ export const AaveConfig: IAaveConfiguration = { ZRX: '0xE41d2489571d322189246DaFA5ebDe1F4699F498', xSUSHI: '0x8798249c2E607446EfB7Ad49eC89dD1865Ff4272', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { AAVE: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', BAT: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', BUSD: '0x4Fabb145d64652a948d72533023f6E7A623C7C53', diff --git a/markets/aave/reservesConfigs.ts b/markets/aave/reservesConfigs.ts index a29e16d7..b41ae417 100644 --- a/markets/aave/reservesConfigs.ts +++ b/markets/aave/reservesConfigs.ts @@ -1,6 +1,6 @@ import { eContractid, IReserveParams } from '../../helpers/types'; -import { +import { rateStrategyStableOne, rateStrategyStableTwo, rateStrategyStableThree, @@ -21,7 +21,7 @@ export const strategyBUSD: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyDAI: IReserveParams = { @@ -33,7 +33,7 @@ export const strategyDAI: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategySUSD: IReserveParams = { @@ -45,7 +45,7 @@ export const strategySUSD: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyTUSD: IReserveParams = { @@ -57,7 +57,7 @@ export const strategyTUSD: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyUSDC: IReserveParams = { @@ -69,7 +69,7 @@ export const strategyUSDC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyUSDT: IReserveParams = { @@ -81,7 +81,7 @@ export const strategyUSDT: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyAAVE: IReserveParams = { @@ -93,7 +93,7 @@ export const strategyAAVE: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '0' + reserveFactor: '0', }; export const strategyBAT: IReserveParams = { @@ -105,7 +105,7 @@ export const strategyBAT: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyENJ: IReserveParams = { @@ -117,7 +117,7 @@ export const strategyENJ: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyWETH: IReserveParams = { @@ -129,7 +129,7 @@ export const strategyWETH: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '1000' + reserveFactor: '1000', }; export const strategyKNC: IReserveParams = { @@ -141,7 +141,7 @@ export const strategyKNC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyLINK: IReserveParams = { @@ -153,7 +153,7 @@ export const strategyLINK: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyMANA: IReserveParams = { @@ -165,7 +165,7 @@ export const strategyMANA: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '3500' + reserveFactor: '3500', }; export const strategyMKR: IReserveParams = { @@ -177,7 +177,7 @@ export const strategyMKR: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyREN: IReserveParams = { @@ -189,7 +189,7 @@ export const strategyREN: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategySNX: IReserveParams = { @@ -201,7 +201,7 @@ export const strategySNX: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '3500' + reserveFactor: '3500', }; // Invalid borrow rates in params currently, replaced with snx params @@ -214,7 +214,7 @@ export const strategyUNI: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.DelegationAwareAToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyWBTC: IReserveParams = { @@ -226,7 +226,7 @@ export const strategyWBTC: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '8', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyYFI: IReserveParams = { @@ -238,7 +238,7 @@ export const strategyYFI: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyZRX: IReserveParams = { @@ -250,7 +250,7 @@ export const strategyZRX: IReserveParams = { stableBorrowRateEnabled: true, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000' + reserveFactor: '2000', }; export const strategyXSUSHI: IReserveParams = { @@ -263,4 +263,4 @@ export const strategyXSUSHI: IReserveParams = { reserveDecimals: '18', aTokenImpl: eContractid.AToken, reserveFactor: '3500', -}; \ No newline at end of file +}; diff --git a/markets/amm/commons.ts b/markets/amm/commons.ts index 8be1f2c0..39fca1d0 100644 --- a/markets/amm/commons.ts +++ b/markets/amm/commons.ts @@ -5,6 +5,7 @@ import { RAY, ZERO_ADDRESS, MOCK_CHAINLINK_AGGREGATORS_PRICES, + oneUsd, } from '../../helpers/constants'; import { ICommonConfiguration, eEthereumNetwork } from '../../helpers/types'; @@ -19,6 +20,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave AMM Market variable debt', SymbolPrefix: 'Amm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', @@ -116,7 +119,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, PoolAdminIndex: 0, EmergencyAdmin: { @@ -126,7 +129,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, - [eEthereumNetwork.tenderlyMain]: undefined, + [eEthereumNetwork.tenderly]: undefined, }, EmergencyAdminIndex: 1, ProviderRegistry: { @@ -136,7 +139,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', + [eEthereumNetwork.tenderly]: '0x52D306e36E3B6B02c153d0266ff0f85d18BCD413', }, ProviderRegistryOwner: { [eEthereumNetwork.kovan]: '0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F', @@ -145,7 +148,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.coverage]: '', [eEthereumNetwork.hardhat]: '', [eEthereumNetwork.buidlerevm]: '', - [eEthereumNetwork.tenderlyMain]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', + [eEthereumNetwork.tenderly]: '0xB9062896ec3A615a4e4444DF183F0531a77218AE', }, LendingRateOracle: { [eEthereumNetwork.coverage]: '', @@ -154,7 +157,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd00Bd28FAdDa9d5658D1D4e0c151973146C7A533', //'0xE48F95873855bfd97BF89572DDf5cBC44D9c545b' [eEthereumNetwork.ropsten]: '0x05dcca805a6562c1bdd0423768754acb6993241b', [eEthereumNetwork.main]: '', //'0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', // Need to re-deploy because of onlyOwner - [eEthereumNetwork.tenderlyMain]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', + [eEthereumNetwork.tenderly]: '0x8A32f49FFbA88aba6EFF96F45D8BD1D4b3f35c7D', }, LendingPoolCollateralManager: { [eEthereumNetwork.coverage]: '', @@ -163,7 +166,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x9269b6453d0d75370c4c85e5a42977a53efdb72a', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', - [eEthereumNetwork.tenderlyMain]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', + [eEthereumNetwork.tenderly]: '0xbd4765210d4167CE2A5b87280D9E8Ee316D5EC7C', }, LendingPoolConfigurator: { [eEthereumNetwork.coverage]: '', @@ -172,7 +175,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x36eB31800aa67a9c50df1d56EE01981A6E14Cce5', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, LendingPool: { [eEthereumNetwork.coverage]: '', @@ -181,7 +184,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x78142De7a1930412E9e50dEB3b80dB284c2dFa3A', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WethGateway: { [eEthereumNetwork.coverage]: '', @@ -190,7 +193,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x1c4A1cC35A477aa1cF35DF671d93ACc04d8131E0', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, TokenDistributor: { [eEthereumNetwork.coverage]: '', @@ -199,7 +202,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x971efe90088f21dc6a36f610ffed77fc19710708', [eEthereumNetwork.ropsten]: '0xeba2ea67942b8250d870b12750b594696d02fc9c', [eEthereumNetwork.main]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', - [eEthereumNetwork.tenderlyMain]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', + [eEthereumNetwork.tenderly]: '0xe3d9988f676457123c5fd01297605efdd0cba1ae', }, AaveOracle: { [eEthereumNetwork.coverage]: '', @@ -208,7 +211,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x8fb777d67e9945e2c01936e319057f9d41d559e6', // Need to re-deploy because of onlyOwner [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: '', //'0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', // Need to re-deploy because of onlyOwner - [eEthereumNetwork.tenderlyMain]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', + [eEthereumNetwork.tenderly]: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', }, FallbackOracle: { [eEthereumNetwork.coverage]: '', @@ -217,7 +220,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x50913E8E1c650E790F8a1E741FF9B1B1bB251dfe', [eEthereumNetwork.ropsten]: '0xAD1a978cdbb8175b2eaeC47B01404f8AEC5f4F0d', [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, ChainlinkAggregator: { [eEthereumNetwork.coverage]: {}, @@ -270,7 +273,7 @@ export const CommonsConfig: ICommonConfiguration = { BptBALWETH: '0x2e4e78936b100be6Ef85BCEf7FB25bC770B02B85', USD: '0x9326BFA02ADD2366b30bacB125260Af641031331', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { USDT: '0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46', WBTC: '0xdeb288F737066589598e9214E782fa5A8eD689e8', USDC: '0x986b5E1e1755e3C2440e960477f25201B0a8bbD4', @@ -301,7 +304,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.main]: {}, [eEthereumNetwork.kovan]: {}, [eEthereumNetwork.ropsten]: {}, - [eEthereumNetwork.tenderlyMain]: {}, + [eEthereumNetwork.tenderly]: {}, }, ReservesConfig: {}, ATokenDomainSeparator: { @@ -314,7 +317,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', [eEthereumNetwork.main]: '', - [eEthereumNetwork.tenderlyMain]: '', + [eEthereumNetwork.tenderly]: '', }, WETH: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -323,7 +326,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, WrappedNativeToken: { [eEthereumNetwork.coverage]: '', // deployed in local evm @@ -332,7 +335,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', [eEthereumNetwork.ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', [eEthereumNetwork.main]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - [eEthereumNetwork.tenderlyMain]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [eEthereumNetwork.tenderly]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }, ReserveFactorTreasuryAddress: { [eEthereumNetwork.coverage]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', @@ -341,7 +344,7 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.ropsten]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', [eEthereumNetwork.main]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', - [eEthereumNetwork.tenderlyMain]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', + [eEthereumNetwork.tenderly]: '0x464c71f6c2f760dda6093dcb91c24c39e5d6e18c', }, IncentivesController: { [eEthereumNetwork.coverage]: ZERO_ADDRESS, @@ -350,6 +353,6 @@ export const CommonsConfig: ICommonConfiguration = { [eEthereumNetwork.kovan]: ZERO_ADDRESS, [eEthereumNetwork.ropsten]: ZERO_ADDRESS, [eEthereumNetwork.main]: ZERO_ADDRESS, - [eEthereumNetwork.tenderlyMain]: ZERO_ADDRESS, + [eEthereumNetwork.tenderly]: ZERO_ADDRESS, }, }; diff --git a/markets/amm/index.ts b/markets/amm/index.ts index e42dbdec..37bc46b6 100644 --- a/markets/amm/index.ts +++ b/markets/amm/index.ts @@ -83,8 +83,7 @@ export const AmmConfig: IAmmConfiguration = { BptWBTCWETH: '0x110569E3261bC0934dA637b019f6f1b6F50ec574', BptBALWETH: '0xad01D8e0Fa9EAA8Fe76dA30CFb1BCe12707aE6c5', }, - [eEthereumNetwork.ropsten]: { - }, + [eEthereumNetwork.ropsten]: {}, [eEthereumNetwork.main]: { DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', @@ -108,7 +107,7 @@ export const AmmConfig: IAmmConfiguration = { BptWBTCWETH: '0x1efF8aF5D577060BA4ac8A29A13525bb0Ee2A3D5', BptBALWETH: '0x59A19D8c652FA0284f44113D0ff9aBa70bd46fB4', }, - [eEthereumNetwork.tenderlyMain]: { + [eEthereumNetwork.tenderly]: { DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 8a0274a0..dc6fb173 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -19,6 +19,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave Matic Market variable debt', SymbolPrefix: 'm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', + OracleQuoteUnit: oneEther.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', diff --git a/markets/xdai/commons.ts b/markets/xdai/commons.ts index ee9f1f9f..856dd50a 100644 --- a/markets/xdai/commons.ts +++ b/markets/xdai/commons.ts @@ -19,6 +19,7 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave XDAI Market variable debt', SymbolPrefix: 'm', ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'ETH', ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', diff --git a/tasks/dev/3_lending_pool.ts b/tasks/dev/3_lending_pool.ts index 9936abfa..5f4336c6 100644 --- a/tasks/dev/3_lending_pool.ts +++ b/tasks/dev/3_lending_pool.ts @@ -1,5 +1,6 @@ import { task } from 'hardhat/config'; import { + deployATokenImplementations, deployATokensAndRatesHelper, deployLendingPool, deployLendingPoolConfigurator, @@ -13,13 +14,15 @@ import { getLendingPoolConfiguratorProxy, } from '../../helpers/contracts-getters'; import { insertContractAddressInDb } from '../../helpers/contracts-helpers'; +import { ConfigNames, loadPoolConfig } from '../../helpers/configuration'; task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') - .setAction(async ({ verify }, localBRE) => { + .addParam('pool', `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`) + .setAction(async ({ verify, pool }, localBRE) => { await localBRE.run('set-DRE'); - const addressesProvider = await getLendingPoolAddressesProvider(); + const poolConfig = loadPoolConfig(pool); const lendingPoolImpl = await deployLendingPool(verify); @@ -55,4 +58,5 @@ task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], verify ); + await deployATokenImplementations(pool, poolConfig.ReservesConfig, verify); }); diff --git a/tasks/dev/4_oracles.ts b/tasks/dev/4_oracles.ts index 23c24133..44a657af 100644 --- a/tasks/dev/4_oracles.ts +++ b/tasks/dev/4_oracles.ts @@ -1,7 +1,7 @@ import { task } from 'hardhat/config'; import { deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingRateOracle, } from '../../helpers/contracts-deployments'; import { @@ -12,14 +12,19 @@ import { import { ICommonConfiguration, iAssetBase, TokenContractId } from '../../helpers/types'; import { waitForTx } from '../../helpers/misc-utils'; import { getAllAggregatorsAddresses, getAllTokenAddresses } from '../../helpers/mock-helpers'; -import { ConfigNames, loadPoolConfig, getWethAddress } from '../../helpers/configuration'; +import { + ConfigNames, + loadPoolConfig, + getWethAddress, + getQuoteCurrency, +} from '../../helpers/configuration'; import { getAllMockedTokens, getLendingPoolAddressesProvider, getPairsTokenAggregator, } from '../../helpers/contracts-getters'; -task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') +task('dev:deploy-oracles', 'Deploy oracles for dev environment') .addFlag('verify', 'Verify contracts at Etherscan') .addParam('pool', `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`) .setAction(async ({ verify, pool }, localBRE) => { @@ -29,6 +34,7 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') Mocks: { AllAssetsInitialPrices }, ProtocolGlobalParams: { UsdAddress, MockUsdPriceInWei }, LendingRateOracleRatesCommon, + OracleQuoteCurrency, } = poolConfig as ICommonConfiguration; const defaultTokenList = { @@ -54,11 +60,18 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') const [tokens, aggregators] = getPairsTokenAggregator( allTokenAddresses, - allAggregatorsAddresses + allAggregatorsAddresses, + OracleQuoteCurrency ); - await deployAaveOracle( - [tokens, aggregators, fallbackOracle.address, await getWethAddress(poolConfig)], + await deployAaveOracleV2( + [ + tokens, + aggregators, + fallbackOracle.address, + await getQuoteCurrency(poolConfig), + pool.OracleQuoteUnit, + ], verify ); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); diff --git a/tasks/dev/5_initialize.ts b/tasks/dev/5_initialize.ts index f36a4e09..c791656f 100644 --- a/tasks/dev/5_initialize.ts +++ b/tasks/dev/5_initialize.ts @@ -40,6 +40,7 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') VariableDebtTokenNamePrefix, SymbolPrefix, WethGateway, + ReservesConfig, } = poolConfig; const mockTokens = await getAllMockedTokens(); const allTokenAddresses = getAllTokenAddresses(mockTokens); @@ -52,14 +53,12 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address, verify); - const reservesParams = getReservesConfigByPool(AavePools.proto); - const admin = await addressesProvider.getPoolAdmin(); const treasuryAddress = await getTreasuryAddress(poolConfig); await initReservesByHelper( - reservesParams, + ReservesConfig, protoPoolReservesAddresses, ATokenNamePrefix, StableDebtTokenNamePrefix, @@ -68,9 +67,10 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') admin, treasuryAddress, ZERO_ADDRESS, + pool, verify ); - await configureReservesByHelper(reservesParams, protoPoolReservesAddresses, testHelpers, admin); + await configureReservesByHelper(ReservesConfig, protoPoolReservesAddresses, testHelpers, admin); const collateralManager = await deployLendingPoolCollateralManager(verify); await waitForTx( diff --git a/tasks/full/2_lending_pool.ts b/tasks/full/2_lending_pool.ts index e318846e..ac930251 100644 --- a/tasks/full/2_lending_pool.ts +++ b/tasks/full/2_lending_pool.ts @@ -1,6 +1,7 @@ import { task } from 'hardhat/config'; import { getParamPerNetwork, insertContractAddressInDb } from '../../helpers/contracts-helpers'; import { + deployATokenImplementations, deployATokensAndRatesHelper, deployLendingPool, deployLendingPoolConfigurator, @@ -78,11 +79,12 @@ task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], verify ); + await deployATokenImplementations(pool, poolConfig.ReservesConfig, verify); } catch (error) { if (DRE.network.name.includes('tenderly')) { const transactionLink = `https://dashboard.tenderly.co/${DRE.config.tenderly.username}/${ DRE.config.tenderly.project - }/fork/${DRE.tenderlyNetwork.getFork()}/simulation/${DRE.tenderlyNetwork.getHead()}`; + }/fork/${DRE.tenderly.network().getFork()}/simulation/${DRE.tenderly.network().getHead()}`; console.error('Check tx error:', transactionLink); } throw error; diff --git a/tasks/full/3_oracles.ts b/tasks/full/3_oracles.ts index df06f34c..740cf1df 100644 --- a/tasks/full/3_oracles.ts +++ b/tasks/full/3_oracles.ts @@ -1,6 +1,6 @@ import { task } from 'hardhat/config'; import { getParamPerNetwork } from '../../helpers/contracts-helpers'; -import { deployAaveOracle, deployLendingRateOracle } from '../../helpers/contracts-deployments'; +import { deployAaveOracleV2, deployLendingRateOracle } from '../../helpers/contracts-deployments'; import { setInitialMarketRatesInRatesOracleByHelper } from '../../helpers/oracles-helpers'; import { ICommonConfiguration, eNetwork, SymbolMap } from '../../helpers/types'; import { waitForTx, notFalsyOrZeroAddress } from '../../helpers/misc-utils'; @@ -10,6 +10,7 @@ import { getWethAddress, getGenesisPoolAdmin, getLendingRateOracles, + getQuoteCurrency, } from '../../helpers/configuration'; import { getAaveOracle, @@ -17,7 +18,8 @@ import { getLendingRateOracle, getPairsTokenAggregator, } from '../../helpers/contracts-getters'; -import { AaveOracle, LendingRateOracle } from '../../types'; +import { AaveOracle, AaveOracleV2, LendingRateOracle } from '../../types'; +import { isAddress } from 'ethers/lib/utils'; task('full:deploy-oracles', 'Deploy oracles for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -46,16 +48,27 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') ...reserveAssets, USD: UsdAddress, }; - const [tokens, aggregators] = getPairsTokenAggregator(tokensToWatch, chainlinkAggregators); + const [tokens, aggregators] = getPairsTokenAggregator( + tokensToWatch, + chainlinkAggregators, + poolConfig.OracleQuoteCurrency + ); - let aaveOracle: AaveOracle; + let aaveOracle: AaveOracle | AaveOracleV2; let lendingRateOracle: LendingRateOracle; if (notFalsyOrZeroAddress(aaveOracleAddress)) { aaveOracle = await await getAaveOracle(aaveOracleAddress); + await waitForTx(await aaveOracle.setAssetSources(tokens, aggregators)); } else { - aaveOracle = await deployAaveOracle( - [tokens, aggregators, fallbackOracleAddress, await getWethAddress(poolConfig)], + aaveOracle = await deployAaveOracleV2( + [ + tokens, + aggregators, + fallbackOracleAddress, + await getQuoteCurrency(poolConfig), + poolConfig.OracleQuoteUnit, + ], verify ); await waitForTx(await aaveOracle.setAssetSources(tokens, aggregators)); @@ -74,7 +87,7 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') ); } - console.log('Aave Oracle: %s', lendingRateOracle.address); + console.log('Aave Oracle: %s', aaveOracle.address); console.log('Lending Rate Oracle: %s', lendingRateOracle.address); // Register the proxy price provider on the addressesProvider @@ -84,7 +97,7 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') if (DRE.network.name.includes('tenderly')) { const transactionLink = `https://dashboard.tenderly.co/${DRE.config.tenderly.username}/${ DRE.config.tenderly.project - }/fork/${DRE.tenderlyNetwork.getFork()}/simulation/${DRE.tenderlyNetwork.getHead()}`; + }/fork/${DRE.tenderly.network().getFork()}/simulation/${DRE.tenderly.network().getHead()}`; console.error('Check tx error:', transactionLink); } throw error; diff --git a/tasks/full/6-initialize.ts b/tasks/full/6-initialize.ts index bfe2925e..f315f36b 100644 --- a/tasks/full/6-initialize.ts +++ b/tasks/full/6-initialize.ts @@ -66,6 +66,7 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') admin, treasuryAddress, incentivesController, + pool, verify ); await configureReservesByHelper(ReservesConfig, reserveAssets, testHelpers, admin); diff --git a/tasks/helpers/deploy-new-asset.ts b/tasks/helpers/deploy-new-asset.ts index 718b6372..86b4958a 100644 --- a/tasks/helpers/deploy-new-asset.ts +++ b/tasks/helpers/deploy-new-asset.ts @@ -3,9 +3,9 @@ import { eEthereumNetwork } from '../../helpers/types'; import { getTreasuryAddress } from '../../helpers/configuration'; import * as marketConfigs from '../../markets/aave'; import * as reserveConfigs from '../../markets/aave/reservesConfigs'; -import { chooseATokenDeployment } from '../../helpers/init-helpers'; import { getLendingPoolAddressesProvider } from './../../helpers/contracts-getters'; import { + chooseATokenDeployment, deployDefaultReserveInterestRateStrategy, deployStableDebtToken, deployVariableDebtToken, @@ -47,18 +47,7 @@ WRONG RESERVE ASSET SETUP: LENDING_POOL_ADDRESS_PROVIDER[network] ); const poolAddress = await addressProvider.getLendingPool(); - const treasuryAddress = await getTreasuryAddress(marketConfigs.AaveConfig); - const aToken = await deployCustomAToken( - [ - poolAddress, - reserveAssetAddress, - treasuryAddress, - ZERO_ADDRESS, // Incentives Controller - `Aave interest bearing ${symbol}`, - `a${symbol}`, - ], - verify - ); + const aToken = await deployCustomAToken(verify); const stableDebt = await deployStableDebtToken( [ poolAddress, From 4b217fff845fb788c0147306e36adbe0e7b81c25 Mon Sep 17 00:00:00 2001 From: David Racero Date: Wed, 14 Jul 2021 16:56:03 +0200 Subject: [PATCH 25/62] tests: fixed tests to support latest changes --- helpers/configuration.ts | 6 ++- package-lock.json | 2 +- test-suites/test-aave/__setup.spec.ts | 55 ++++++++++++++++----------- test-suites/test-amm/__setup.spec.ts | 46 +++++++++++++--------- 4 files changed, 67 insertions(+), 42 deletions(-) diff --git a/helpers/configuration.ts b/helpers/configuration.ts index eb33d135..ddc568d7 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -39,7 +39,11 @@ export const loadPoolConfig = (configName: ConfigNames): PoolConfiguration => { case ConfigNames.Commons: return CommonsConfig; default: - throw new Error(`Unsupported pool configuration: ${Object.values(ConfigNames)}`); + throw new Error( + `Unsupported pool configuration: ${configName} is not one of the supported configs ${Object.values( + ConfigNames + )}` + ); } }; diff --git a/package-lock.json b/package-lock.json index 7f3c76fd..e5198127 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14793,7 +14793,7 @@ } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index ca9f7698..463435ea 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -13,7 +13,7 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -28,8 +28,8 @@ import { deployUniswapRepayAdapter, deployFlashLiquidationAdapter, authorizeWETHGateway, + deployATokenImplementations, } from '../../helpers/contracts-deployments'; -import { eEthereumNetwork } from '../../helpers/types'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; import { MintableERC20 } from '../../types/MintableERC20'; @@ -49,7 +49,7 @@ import { import { DRE, waitForTx } from '../../helpers/misc-utils'; import { initReservesByHelper, configureReservesByHelper } from '../../helpers/init-helpers'; import AaveConfig from '../../markets/aave'; -import { ZERO_ADDRESS } from '../../helpers/constants'; +import { oneEther, ZERO_ADDRESS } from '../../helpers/constants'; import { getLendingPool, getLendingPoolConfiguratorProxy, @@ -60,7 +60,6 @@ import { WETH9Mocked } from '../../types/WETH9Mocked'; const MOCK_USD_PRICE_IN_WEI = AaveConfig.ProtocolGlobalParams.MockUsdPriceInWei; const ALL_ASSETS_INITIAL_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; const USD_ADDRESS = AaveConfig.ProtocolGlobalParams.UsdAddress; -const MOCK_CHAINLINK_AGGREGATORS_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; const LENDING_RATE_ORACLE_RATES_COMMON = AaveConfig.LendingRateOracleRatesCommon; const deployAllMockTokens = async (deployer: Signer) => { @@ -96,9 +95,13 @@ const deployAllMockTokens = async (deployer: Signer) => { const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.time('setup'); const aaveAdmin = await deployer.getAddress(); + const config = loadPoolConfig(ConfigNames.Aave); - const mockTokens = await deployAllMockTokens(deployer); - console.log('Deployed mocks'); + const mockTokens: { + [symbol: string]: MockContract | MintableERC20 | WETH9Mocked; + } = { + ...(await deployAllMockTokens(deployer)), + }; const addressesProvider = await deployLendingPoolAddressesProvider(AaveConfig.MarketId); await waitForTx(await addressesProvider.setPoolAdmin(aaveAdmin)); @@ -196,8 +199,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { fallbackOracle ); - const mockAggregators = await deployAllMockAggregators(MOCK_CHAINLINK_AGGREGATORS_PRICES); - console.log('Mock aggs deployed'); + const mockAggregators = await deployAllMockAggregators(ALL_ASSETS_INITIAL_PRICES); const allTokenAddresses = Object.entries(mockTokens).reduce( (accum: { [tokenSymbol: string]: tEthereumAddress }, [tokenSymbol, tokenContract]) => ({ ...accum, @@ -213,9 +215,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { {} ); - const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses); + const [tokens, aggregators] = getPairsTokenAggregator( + allTokenAddresses, + allAggregatorsAddresses, + config.OracleQuoteCurrency + ); - await deployAaveOracle([tokens, aggregators, fallbackOracle.address, mockTokens.WETH.address]); + await deployAaveOracleV2([ + tokens, + aggregators, + fallbackOracle.address, + mockTokens.WETH.address, + oneEther.toString(), + ]); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); const lendingRateOracle = await deployLendingRateOracle(); @@ -232,23 +244,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { aaveAdmin ); - const reservesParams = getReservesConfigByPool(AavePools.proto); + // Reserve params from AAVE pool + mocked tokens + const reservesParams = { + ...config.ReservesConfig, + }; const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address); - await insertContractAddressInDb(eContractid.AaveProtocolDataProvider, testHelpers.address); + await deployATokenImplementations(ConfigNames.Aave, reservesParams, false); + const admin = await deployer.getAddress(); - console.log('Initialize configuration'); - - const config = loadPoolConfig(ConfigNames.Aave); - - const { - ATokenNamePrefix, - StableDebtTokenNamePrefix, - VariableDebtTokenNamePrefix, - SymbolPrefix, - } = config; + const { ATokenNamePrefix, StableDebtTokenNamePrefix, VariableDebtTokenNamePrefix, SymbolPrefix } = + config; const treasuryAddress = await getTreasuryAddress(config); await initReservesByHelper( @@ -261,6 +269,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { admin, treasuryAddress, ZERO_ADDRESS, + ConfigNames.Aave, false ); @@ -298,7 +307,7 @@ before(async () => { const FORK = process.env.FORK; if (FORK) { - await rawBRE.run('aave:mainnet'); + await rawBRE.run('aave:mainnet', { skipRegistry: true }); } else { console.log('-> Deploying test environment...'); await buildTestEnv(deployer, secondaryWallet); diff --git a/test-suites/test-amm/__setup.spec.ts b/test-suites/test-amm/__setup.spec.ts index 0fae3acd..ef398214 100644 --- a/test-suites/test-amm/__setup.spec.ts +++ b/test-suites/test-amm/__setup.spec.ts @@ -13,7 +13,7 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracle, + deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -28,6 +28,7 @@ import { deployUniswapRepayAdapter, deployFlashLiquidationAdapter, authorizeWETHGateway, + deployATokenImplementations, } from '../../helpers/contracts-deployments'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; @@ -48,7 +49,7 @@ import { import { DRE, waitForTx } from '../../helpers/misc-utils'; import { initReservesByHelper, configureReservesByHelper } from '../../helpers/init-helpers'; import AmmConfig from '../../markets/amm'; -import { ZERO_ADDRESS } from '../../helpers/constants'; +import { oneEther, ZERO_ADDRESS } from '../../helpers/constants'; import { getLendingPool, getLendingPoolConfiguratorProxy, @@ -95,6 +96,14 @@ const deployAllMockTokens = async (deployer: Signer) => { const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.time('setup'); const aaveAdmin = await deployer.getAddress(); + const config = loadPoolConfig(ConfigNames.Amm); + const { + ATokenNamePrefix, + StableDebtTokenNamePrefix, + VariableDebtTokenNamePrefix, + SymbolPrefix, + ReservesConfig, + } = config; const mockTokens = await deployAllMockTokens(deployer); @@ -189,6 +198,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { WMATIC: mockTokens.WMATIC.address, USD: USD_ADDRESS, STAKE: mockTokens.STAKE.address, + xSUSHI: ZERO_ADDRESS, }, fallbackOracle ); @@ -210,9 +220,19 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { {} ); - const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses); + const [tokens, aggregators] = getPairsTokenAggregator( + allTokenAddresses, + allAggregatorsAddresses, + config.OracleQuoteCurrency + ); - await deployAaveOracle([tokens, aggregators, fallbackOracle.address, mockTokens.WETH.address]); + await deployAaveOracleV2([ + tokens, + aggregators, + fallbackOracle.address, + mockTokens.WETH.address, + oneEther.toString(), + ]); await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); const lendingRateOracle = await deployLendingRateOracle(); @@ -228,8 +248,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { lendingRateOracle, aaveAdmin ); - - const reservesParams = getReservesConfigByPool(AavePools.amm); + await deployATokenImplementations(ConfigNames.Amm, ReservesConfig); const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address); @@ -238,18 +257,10 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { console.log('Initialize configuration'); - const config = loadPoolConfig(ConfigNames.Amm); - - const { - ATokenNamePrefix, - StableDebtTokenNamePrefix, - VariableDebtTokenNamePrefix, - SymbolPrefix, - } = config; const treasuryAddress = await getTreasuryAddress(config); await initReservesByHelper( - reservesParams, + ReservesConfig, allReservesAddresses, ATokenNamePrefix, StableDebtTokenNamePrefix, @@ -258,9 +269,10 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { admin, treasuryAddress, ZERO_ADDRESS, + ConfigNames.Amm, false ); - await configureReservesByHelper(reservesParams, allReservesAddresses, testHelpers, admin); + await configureReservesByHelper(ReservesConfig, allReservesAddresses, testHelpers, admin); const collateralManager = await deployLendingPoolCollateralManager(); await waitForTx( @@ -294,7 +306,7 @@ before(async () => { const FORK = process.env.FORK; if (FORK) { - await rawBRE.run('amm:mainnet'); + await rawBRE.run('amm:mainnet', { skipRegistry: true }); } else { console.log('-> Deploying test environment...'); await buildTestEnv(deployer, secondaryWallet); From 0e7bc49a372dacd18203cd71fafd20c7f6616446 Mon Sep 17 00:00:00 2001 From: David Racero Date: Tue, 20 Jul 2021 11:32:22 +0200 Subject: [PATCH 26/62] feat: Replace AaveOracle to the latest version. Fix dev deployment scripts. --- contracts/misc/AaveOracle.sol | 19 +++-- contracts/misc/AaveOracleV2.sol | 125 ------------------------------- helpers/contracts-deployments.ts | 14 +--- helpers/types.ts | 1 - tasks/dev/4_oracles.ts | 14 ++-- tasks/full/3_oracles.ts | 10 +-- tasks/migrations/aave.dev.ts | 2 +- 7 files changed, 23 insertions(+), 162 deletions(-) delete mode 100644 contracts/misc/AaveOracleV2.sol diff --git a/contracts/misc/AaveOracle.sol b/contracts/misc/AaveOracle.sol index 0cb8e180..bc921468 100644 --- a/contracts/misc/AaveOracle.sol +++ b/contracts/misc/AaveOracle.sol @@ -18,29 +18,34 @@ import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; contract AaveOracle is IPriceOracleGetter, Ownable { using SafeERC20 for IERC20; - event WethSet(address indexed weth); + event BaseCurrencySet(address indexed baseCurrency, uint256 baseCurrencyUnit); event AssetSourceUpdated(address indexed asset, address indexed source); event FallbackOracleUpdated(address indexed fallbackOracle); mapping(address => IChainlinkAggregator) private assetsSources; IPriceOracleGetter private _fallbackOracle; - address public immutable WETH; + address public immutable BASE_CURRENCY; + uint256 public immutable BASE_CURRENCY_UNIT; /// @notice Constructor /// @param assets The addresses of the assets /// @param sources The address of the source of each asset /// @param fallbackOracle The address of the fallback oracle to use if the data of an /// aggregator is not consistent + /// @param baseCurrency the base currency used for the price quotes. If USD is used, base currency is 0x0 + /// @param baseCurrencyUnit the unit of the base currency constructor( address[] memory assets, address[] memory sources, address fallbackOracle, - address weth + address baseCurrency, + uint256 baseCurrencyUnit ) public { _setFallbackOracle(fallbackOracle); _setAssetsSources(assets, sources); - WETH = weth; - emit WethSet(weth); + BASE_CURRENCY = baseCurrency; + BASE_CURRENCY_UNIT = baseCurrencyUnit; + emit BaseCurrencySet(baseCurrency, baseCurrencyUnit); } /// @notice External function called by the Aave governance to set or replace sources of assets @@ -83,8 +88,8 @@ contract AaveOracle is IPriceOracleGetter, Ownable { function getAssetPrice(address asset) public view override returns (uint256) { IChainlinkAggregator source = assetsSources[asset]; - if (asset == WETH) { - return 1 ether; + if (asset == BASE_CURRENCY) { + return BASE_CURRENCY_UNIT; } else if (address(source) == address(0)) { return _fallbackOracle.getAssetPrice(asset); } else { diff --git a/contracts/misc/AaveOracleV2.sol b/contracts/misc/AaveOracleV2.sol deleted file mode 100644 index 8af3b08e..00000000 --- a/contracts/misc/AaveOracleV2.sol +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.6.12; - -import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; -import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol'; - -import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; -import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol'; -import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol'; - -/// @title AaveOracleV2 -/// @author Aave -/// @notice Proxy smart contract to get the price of an asset from a price source, with Chainlink Aggregator -/// smart contracts as primary option -/// - If the returned price by a Chainlink aggregator is <= 0, the call is forwarded to a fallbackOracle -/// - Owned by the Aave governance system, allowed to add sources for assets, replace them -/// and change the fallbackOracle -contract AaveOracleV2 is IPriceOracleGetter, Ownable { - using SafeERC20 for IERC20; - - event QuoteCurrencySet(address indexed quoteCurrency, uint256 quoteUnit); - event AssetSourceUpdated(address indexed asset, address indexed source); - event FallbackOracleUpdated(address indexed fallbackOracle); - - mapping(address => IChainlinkAggregator) private assetsSources; - IPriceOracleGetter private _fallbackOracle; - address public immutable QUOTE_CURRENCY; - uint256 public immutable QUOTE_CURRENCY_UNIT; - - /// @notice Constructor - /// @param assets The addresses of the assets - /// @param sources The address of the source of each asset - /// @param fallbackOracle The address of the fallback oracle to use if the data of an - /// aggregator is not consistent - constructor( - address[] memory assets, - address[] memory sources, - address fallbackOracle, - address quoteCurrency, - uint256 quoteCurrencyUnits - ) public { - _setFallbackOracle(fallbackOracle); - _setAssetsSources(assets, sources); - QUOTE_CURRENCY = quoteCurrency; - QUOTE_CURRENCY_UNIT = quoteCurrencyUnits; - emit QuoteCurrencySet(quoteCurrency, quoteCurrencyUnits); - } - - /// @notice External function called by the Aave governance to set or replace sources of assets - /// @param assets The addresses of the assets - /// @param sources The address of the source of each asset - function setAssetSources(address[] calldata assets, address[] calldata sources) - external - onlyOwner - { - _setAssetsSources(assets, sources); - } - - /// @notice Sets the fallbackOracle - /// - Callable only by the Aave governance - /// @param fallbackOracle The address of the fallbackOracle - function setFallbackOracle(address fallbackOracle) external onlyOwner { - _setFallbackOracle(fallbackOracle); - } - - /// @notice Internal function to set the sources for each asset - /// @param assets The addresses of the assets - /// @param sources The address of the source of each asset - function _setAssetsSources(address[] memory assets, address[] memory sources) internal { - require(assets.length == sources.length, 'INCONSISTENT_PARAMS_LENGTH'); - for (uint256 i = 0; i < assets.length; i++) { - assetsSources[assets[i]] = IChainlinkAggregator(sources[i]); - emit AssetSourceUpdated(assets[i], sources[i]); - } - } - - /// @notice Internal function to set the fallbackOracle - /// @param fallbackOracle The address of the fallbackOracle - function _setFallbackOracle(address fallbackOracle) internal { - _fallbackOracle = IPriceOracleGetter(fallbackOracle); - emit FallbackOracleUpdated(fallbackOracle); - } - - /// @notice Gets an asset price by address - /// @param asset The asset address - function getAssetPrice(address asset) public view override returns (uint256) { - IChainlinkAggregator source = assetsSources[asset]; - - if (asset == QUOTE_CURRENCY) { - return QUOTE_CURRENCY_UNIT; - } else if (address(source) == address(0)) { - return _fallbackOracle.getAssetPrice(asset); - } else { - int256 price = IChainlinkAggregator(source).latestAnswer(); - if (price > 0) { - return uint256(price); - } else { - return _fallbackOracle.getAssetPrice(asset); - } - } - } - - /// @notice Gets a list of prices from a list of assets addresses - /// @param assets The list of assets addresses - function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) { - uint256[] memory prices = new uint256[](assets.length); - for (uint256 i = 0; i < assets.length; i++) { - prices[i] = getAssetPrice(assets[i]); - } - return prices; - } - - /// @notice Gets the address of the source for an asset address - /// @param asset The address of the asset - /// @return address The address of the source - function getSourceOfAsset(address asset) external view returns (address) { - return address(assetsSources[asset]); - } - - /// @notice Gets the address of the fallback oracle - /// @return address The addres of the fallback oracle - function getFallbackOracle() external view returns (address) { - return address(_fallbackOracle); - } -} diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index ef8c729e..ef60441e 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -48,7 +48,6 @@ import { WETH9MockedFactory, WETHGatewayFactory, FlashLiquidationAdapterFactory, - AaveOracleV2Factory, } from '../types'; import { withSaveAndVerify, @@ -225,7 +224,7 @@ export const deployMockAggregator = async (price: tStringTokenSmallUnits, verify ); export const deployAaveOracle = async ( - args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress], + args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress, string], verify?: boolean ) => withSaveAndVerify( @@ -235,17 +234,6 @@ export const deployAaveOracle = async ( verify ); -export const deployAaveOracleV2 = async ( - args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress, string], - verify?: boolean -) => - withSaveAndVerify( - await new AaveOracleV2Factory(await getFirstSigner()).deploy(...args), - eContractid.AaveOracleV2, - args, - verify - ); - export const deployLendingPoolCollateralManager = async (verify?: boolean) => { const collateralManagerImpl = await new LendingPoolCollateralManagerFactory( await getFirstSigner() diff --git a/helpers/types.ts b/helpers/types.ts index 53338c21..c4912437 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -96,7 +96,6 @@ export enum eContractid { UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter', UniswapRepayAdapter = 'UniswapRepayAdapter', FlashLiquidationAdapter = 'FlashLiquidationAdapter', - AaveOracleV2 = 'AaveOracleV2', } /* diff --git a/tasks/dev/4_oracles.ts b/tasks/dev/4_oracles.ts index 44a657af..3fa8fe96 100644 --- a/tasks/dev/4_oracles.ts +++ b/tasks/dev/4_oracles.ts @@ -1,7 +1,7 @@ import { task } from 'hardhat/config'; import { deployPriceOracle, - deployAaveOracleV2, + deployAaveOracle, deployLendingRateOracle, } from '../../helpers/contracts-deployments'; import { @@ -12,12 +12,7 @@ import { import { ICommonConfiguration, iAssetBase, TokenContractId } from '../../helpers/types'; import { waitForTx } from '../../helpers/misc-utils'; import { getAllAggregatorsAddresses, getAllTokenAddresses } from '../../helpers/mock-helpers'; -import { - ConfigNames, - loadPoolConfig, - getWethAddress, - getQuoteCurrency, -} from '../../helpers/configuration'; +import { ConfigNames, loadPoolConfig, getQuoteCurrency } from '../../helpers/configuration'; import { getAllMockedTokens, getLendingPoolAddressesProvider, @@ -35,6 +30,7 @@ task('dev:deploy-oracles', 'Deploy oracles for dev environment') ProtocolGlobalParams: { UsdAddress, MockUsdPriceInWei }, LendingRateOracleRatesCommon, OracleQuoteCurrency, + OracleQuoteUnit, } = poolConfig as ICommonConfiguration; const defaultTokenList = { @@ -64,13 +60,13 @@ task('dev:deploy-oracles', 'Deploy oracles for dev environment') OracleQuoteCurrency ); - await deployAaveOracleV2( + await deployAaveOracle( [ tokens, aggregators, fallbackOracle.address, await getQuoteCurrency(poolConfig), - pool.OracleQuoteUnit, + OracleQuoteUnit, ], verify ); diff --git a/tasks/full/3_oracles.ts b/tasks/full/3_oracles.ts index 740cf1df..823f4138 100644 --- a/tasks/full/3_oracles.ts +++ b/tasks/full/3_oracles.ts @@ -1,13 +1,12 @@ import { task } from 'hardhat/config'; import { getParamPerNetwork } from '../../helpers/contracts-helpers'; -import { deployAaveOracleV2, deployLendingRateOracle } from '../../helpers/contracts-deployments'; +import { deployAaveOracle, deployLendingRateOracle } from '../../helpers/contracts-deployments'; import { setInitialMarketRatesInRatesOracleByHelper } from '../../helpers/oracles-helpers'; import { ICommonConfiguration, eNetwork, SymbolMap } from '../../helpers/types'; import { waitForTx, notFalsyOrZeroAddress } from '../../helpers/misc-utils'; import { ConfigNames, loadPoolConfig, - getWethAddress, getGenesisPoolAdmin, getLendingRateOracles, getQuoteCurrency, @@ -18,8 +17,7 @@ import { getLendingRateOracle, getPairsTokenAggregator, } from '../../helpers/contracts-getters'; -import { AaveOracle, AaveOracleV2, LendingRateOracle } from '../../types'; -import { isAddress } from 'ethers/lib/utils'; +import { AaveOracle, LendingRateOracle } from '../../types'; task('full:deploy-oracles', 'Deploy oracles for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -54,14 +52,14 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') poolConfig.OracleQuoteCurrency ); - let aaveOracle: AaveOracle | AaveOracleV2; + let aaveOracle: AaveOracle; let lendingRateOracle: LendingRateOracle; if (notFalsyOrZeroAddress(aaveOracleAddress)) { aaveOracle = await await getAaveOracle(aaveOracleAddress); await waitForTx(await aaveOracle.setAssetSources(tokens, aggregators)); } else { - aaveOracle = await deployAaveOracleV2( + aaveOracle = await deployAaveOracle( [ tokens, aggregators, diff --git a/tasks/migrations/aave.dev.ts b/tasks/migrations/aave.dev.ts index 86608c75..53618baa 100644 --- a/tasks/migrations/aave.dev.ts +++ b/tasks/migrations/aave.dev.ts @@ -24,7 +24,7 @@ task('aave:dev', 'Deploy development enviroment') await localBRE.run('dev:deploy-address-provider', { verify }); console.log('3. Deploy lending pool'); - await localBRE.run('dev:deploy-lending-pool', { verify }); + await localBRE.run('dev:deploy-lending-pool', { verify, pool: POOL_NAME }); console.log('4. Deploy oracles'); await localBRE.run('dev:deploy-oracles', { verify, pool: POOL_NAME }); From 8d359e1fd2c2c5a2f5d19f68d31389a42d46d061 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 21 Jul 2021 11:38:55 +0200 Subject: [PATCH 27/62] feat: Add fixes to the avalanche deployment --- helpers/contracts-helpers.ts | 2 +- markets/avalanche/commons.ts | 3 +++ tasks/deployments/add-market-to-registry.ts | 2 +- tasks/deployments/deploy-UiPoolDataProvider.ts | 6 +++++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index fd310e90..cd79c9a5 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -192,7 +192,7 @@ export const getOptionalParamAddressPerNetwork = ( return getParamPerNetwork(param, network); }; -export const getParamPerPool = ({ proto, amm, matic }: iParamsPerPool, pool: AavePools) => { +export const getParamPerPool = ({ proto, amm, matic, avalanche }: iParamsPerPool, pool: AavePools) => { switch (pool) { case AavePools.proto: return proto; diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index f3e47e3d..ac373d53 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -5,6 +5,7 @@ import { RAY, ZERO_ADDRESS, MOCK_CHAINLINK_AGGREGATORS_PRICES, + oneUsd, } from '../../helpers/constants'; import { ICommonConfiguration, eAvalancheNetwork } from '../../helpers/types'; @@ -19,6 +20,8 @@ export const CommonsConfig: ICommonConfiguration = { VariableDebtTokenNamePrefix: 'Aave Avalanche Market variable debt', SymbolPrefix: '', // TODO: add a symbol? ProviderId: 0, // Overriden in index.ts + OracleQuoteCurrency: 'USD', + OracleQuoteUnit: oneUsd.toString(), ProtocolGlobalParams: { TokenDistributorPercentageBase: '10000', MockUsdPriceInWei: '5848466240000000', diff --git a/tasks/deployments/add-market-to-registry.ts b/tasks/deployments/add-market-to-registry.ts index 0e1d4b68..38ff5eb6 100644 --- a/tasks/deployments/add-market-to-registry.ts +++ b/tasks/deployments/add-market-to-registry.ts @@ -40,7 +40,7 @@ task('add-market-to-registry', 'Adds address provider to registry') ) { console.log('- Deploying a new Address Providers Registry:'); - await DRE.run('full:deploy-address-provider-registry', { verify }); + await DRE.run('full:deploy-address-provider-registry', { verify, pool }); providerRegistryAddress = (await getLendingPoolAddressesProviderRegistry()).address; providerRegistryOwner = await (await getFirstSigner()).getAddress(); diff --git a/tasks/deployments/deploy-UiPoolDataProvider.ts b/tasks/deployments/deploy-UiPoolDataProvider.ts index 9e360db3..1f24a892 100644 --- a/tasks/deployments/deploy-UiPoolDataProvider.ts +++ b/tasks/deployments/deploy-UiPoolDataProvider.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config'; -import { eContractid, eEthereumNetwork, eNetwork, ePolygonNetwork } from '../../helpers/types'; +import { eAvalancheNetwork, eContractid, eEthereumNetwork, eNetwork, ePolygonNetwork } from '../../helpers/types'; import { deployUiPoolDataProvider } from '../../helpers/contracts-deployments'; import { exit } from 'process'; @@ -31,6 +31,10 @@ task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider incentivesController: '0xd41aE58e803Edf4304334acCE4DC4Ec34a63C644', aaveOracle: '0xC365C653f7229894F93994CD0b30947Ab69Ff1D5', }, + [eAvalancheNetwork.fuji]: { + incentivesController: '0x0000000000000000000000000000000000000000', + aaveOracle: '0xF8a88cE4bd99dcae4634D1b11bBf4554b1B9EaCf', + }, }; const supportedNetworks = Object.keys(addressesByNetwork); From 9982cdd7f87bd873bb79fc70b5be1aaf62a22dfa Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 21 Jul 2021 11:39:37 +0200 Subject: [PATCH 28/62] feat: Update latest addresses of Avalanche market --- markets/avalanche/commons.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index ac373d53..172e36f6 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -81,7 +81,7 @@ export const CommonsConfig: ICommonConfiguration = { }, ProviderRegistry: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x3C50d48864d0866B854120fd5B6e1CC7783BB92c' + [eAvalancheNetwork.fuji]: '0x2e4c88B23A52Af210619E9FFA4371708E3Bfc286' }, ProviderRegistryOwner: { [eAvalancheNetwork.avalanche]: '', @@ -89,15 +89,15 @@ export const CommonsConfig: ICommonConfiguration = { }, LendingRateOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x82493D29a6CD24cF6C3865Ad5Ef728A6A8920194' + [eAvalancheNetwork.fuji]: '0x0BA6fa6D6800dc900dB82d58D135fD0e0DA1a77A' }, LendingPoolCollateralManager: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x67abd0a85e1a2eAf10995820C23A455De7E164Af' + [eAvalancheNetwork.fuji]: '0x102035669D37a48689859A9F1cf03F294c8b7f56' }, LendingPoolConfigurator: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '0x4de9ee3d1F33676e505CA3747993929c29802293' }, LendingPool: { [eAvalancheNetwork.avalanche]: '', @@ -105,7 +105,7 @@ export const CommonsConfig: ICommonConfiguration = { }, WethGateway: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' }, TokenDistributor: { [eAvalancheNetwork.avalanche]: '', @@ -113,7 +113,7 @@ export const CommonsConfig: ICommonConfiguration = { }, AaveOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '0x7cb1a6663D864eBD5cB0cDA6063FBf5e3A9285eC' }, FallbackOracle: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, @@ -121,13 +121,13 @@ export const CommonsConfig: ICommonConfiguration = { }, ChainlinkAggregator: { [eAvalancheNetwork.avalanche]: { - WETH: '', - DAI: '', + WETH: '0x976B3D034E162d8bD72D6b9C989d545b839003b0', + DAI: '0x51D7180edA2260cc4F6e4EebB82FEF5c3c2B8300', USDC: '', - USDT: '', + USDT: '0xEBE676ee90Fe1112671f19b6B7459bC678B67e8a', AAVE: '', - WBTC: ' ', - AVAX: '', + WBTC: '0x2779D32d5166BAaa2B2b658333bA7e6Ec0C65743', + AVAX: '0x0A77230d17318075983913bC2145DB16C7366156', }, [eAvalancheNetwork.fuji]: { WETH: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA', @@ -150,12 +150,12 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.fuji]: '' }, WETH: { - [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // TODO: Add WETH address - [eAvalancheNetwork.fuji]: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA' + [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // TODO: ETH Address + [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0' // TODO: Mock ETH }, WrappedNativeToken: { - [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', - [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // TODO: Add WAVAX address? + [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // Official WAVAX + [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // Official WAVAX }, ReserveFactorTreasuryAddress: { [eAvalancheNetwork.avalanche]: '0x652e2Ac6b072Ba8bF7BEF2B11B092447dBc40bde', // TODO: Deploy Treasury From 025a988a13208f3a84b1ed926465fb4f5a1e3fe2 Mon Sep 17 00:00:00 2001 From: andyk Date: Mon, 26 Jul 2021 18:06:36 +0200 Subject: [PATCH 29/62] add poligon related temp hacks --- contracts/misc/UiPoolDataProvider.sol | 14 +++++++------- contracts/misc/interfaces/IUiPoolDataProvider.sol | 2 ++ helper-hardhat-config.ts | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 5be19954..e9f40fe5 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -25,7 +25,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { using UserConfiguration for DataTypes.UserConfigurationMap; address public constant MOCK_USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96; - IAaveIncentivesController public immutable incentivesController; + IAaveIncentivesController public immutable override incentivesController; IPriceOracleGetter public immutable oracle; constructor(IAaveIncentivesController _incentivesController, IPriceOracleGetter _oracle) public { @@ -138,23 +138,23 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // incentives if (address(0) != address(incentivesController)) { ( - reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, - reserveData.aIncentivesLastUpdateTimestamp + reserveData.aIncentivesLastUpdateTimestamp, + reserveData.aTokenIncentivesIndex // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.aTokenAddress); ( - reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, - reserveData.sIncentivesLastUpdateTimestamp + reserveData.sIncentivesLastUpdateTimestamp, + reserveData.sTokenIncentivesIndex // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( - reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, - reserveData.vIncentivesLastUpdateTimestamp + reserveData.vIncentivesLastUpdateTimestamp, + reserveData.vTokenIncentivesIndex // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } diff --git a/contracts/misc/interfaces/IUiPoolDataProvider.sol b/contracts/misc/interfaces/IUiPoolDataProvider.sol index 998e79ed..db7f3093 100644 --- a/contracts/misc/interfaces/IUiPoolDataProvider.sol +++ b/contracts/misc/interfaces/IUiPoolDataProvider.sol @@ -78,6 +78,8 @@ interface IUiPoolDataProvider { view returns (address[] memory); + function incentivesController() external view returns (IAaveIncentivesController); + function getSimpleReservesData(ILendingPoolAddressesProvider provider) external view diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index 3df38000..2b1e9d01 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -47,7 +47,10 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { [eEthereumNetwork.buidlerevm]: 'http://localhost:8545', [eEthereumNetwork.tenderlyMain]: `https://rpc.tenderly.co/fork/${TENDERLY_FORK_ID}`, [ePolygonNetwork.mumbai]: 'https://rpc-mumbai.maticvigil.com', - [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', + [ePolygonNetwork.matic]: + // 'https://rpc-mainnet.maticvigil.com/v1/e616b9ddc7598ffae92629f8145614d55094c722', + 'https://polygon-mainnet.g.alchemy.com/v2/6NUmfWDZw6lC3RPAphj0p_2vm7ElOn2U', + // [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', [eXDaiNetwork.xdai]: 'https://rpc.xdaichain.com/', }; From 9959589c0f78724654d1e70e9dc7414deff04857 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Fri, 30 Jul 2021 14:59:24 +0200 Subject: [PATCH 30/62] feat: Add latest changes --- helpers/constants.ts | 2 +- markets/avalanche/commons.ts | 4 ++-- package.json | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/helpers/constants.ts b/helpers/constants.ts index c1defc3c..7d562f5e 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -31,7 +31,7 @@ export const MOCK_USD_PRICE_IN_WEI = '5848466240000000'; export const USD_ADDRESS = '0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96'; export const AAVE_REFERRAL = '0'; -export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { +export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { // Update to USD-based price feeds AAVE: oneEther.multipliedBy('0.003620948469').toFixed(), BAT: oneEther.multipliedBy('0.00137893825230').toFixed(), BUSD: oneEther.multipliedBy('0.00736484').toFixed(), diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 172e36f6..e01b338a 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -123,9 +123,9 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.avalanche]: { WETH: '0x976B3D034E162d8bD72D6b9C989d545b839003b0', DAI: '0x51D7180edA2260cc4F6e4EebB82FEF5c3c2B8300', - USDC: '', + USDC: ' 0xF096872672F44d6EBA71458D74fe67F9a77a23B9', USDT: '0xEBE676ee90Fe1112671f19b6B7459bC678B67e8a', - AAVE: '', + AAVE: '0x3CA13391E9fb38a75330fb28f8cc2eB3D9ceceED', WBTC: '0x2779D32d5166BAaa2B2b658333bA7e6Ec0C65743', AVAX: '0x0A77230d17318075983913bC2145DB16C7366156', }, diff --git a/package.json b/package.json index e404b482..52260d55 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "matic:mumbai:full:migration:add-registry": "npm run compile && npm run hardhat:mumbai sidechain:mainnet -- --pool Matic", "matic:matic:full:migration:add-registry": "npm run compile && npm run hardhat:matic sidechain:mainnet -- --pool Matic", "amm:kovan:full:migration:add-registry": "npm run compile && npm run hardhat:kovan -- amm:mainnet", + "avalanche:fuji:full:migration:add-registry": "npm run compile && npm run hardhat:fuji avalanche:mainnet -- --pool Avalanche", "aave:docker:add-market-to-registry-from-config": "npm run compile && npm run hardhat:docker -- add-market-to-registry --pool Aave", "aave:kovan:add-market-to-registry-from-config": "npm run compile && npm run hardhat:kovan -- add-market-to-registry --pool Aave", "matic:mumbai:add-market-to-registry-from-config": "npm run compile && npm run hardhat:mumbai add-market-to-registry --pool Matic", @@ -73,6 +74,7 @@ "main:deployUIProvider": "hardhat --network main deploy-UiPoolDataProvider --verify", "matic:deployUIProvider": "hardhat --network matic deploy-UiPoolDataProvider", "mumbai:deployUIProvider": "hardhat --network mumbai deploy-UiPoolDataProvider", + "fuji:deployUIProvider": "hardhat --network fuji deploy-UiPoolDataProvider", "dev:deployUniswapRepayAdapter": "hardhat --network kovan deploy-UniswapRepayAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c", "dev:UniswapLiquiditySwapAdapter": "hardhat --network kovan deploy-UniswapLiquiditySwapAdapter --provider 0x88757f2f99175387aB4C6a4b3067c77A695b0349 --router 0xfcd87315f0e4067070ade8682fcdbc3006631441 --weth 0xd0a1e359811322d97991e03f863a0c30c2cf029c", "main:deployUniswapRepayAdapter": "hardhat --network main deploy-UniswapRepayAdapter --provider 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 --router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D --weth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", From 3119882c91056b68141dae4c89be586f49a52011 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 17 Aug 2021 13:19:29 +0200 Subject: [PATCH 31/62] fix: Disable USDT as collateral --- markets/avalanche/reservesConfigs.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/markets/avalanche/reservesConfigs.ts b/markets/avalanche/reservesConfigs.ts index f80e5a8b..136fe54c 100644 --- a/markets/avalanche/reservesConfigs.ts +++ b/markets/avalanche/reservesConfigs.ts @@ -35,9 +35,9 @@ export const strategyUSDC: IReserveParams = { export const strategyUSDT: IReserveParams = { strategy: rateStrategyStableThree, - baseLTVAsCollateral: '8000', - liquidationThreshold: '8500', - liquidationBonus: '10500', + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', borrowingEnabled: true, stableBorrowRateEnabled: true, reserveDecimals: '6', From 19cc58f30dd2b93211cfb9f9b8649d48be361092 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 17 Aug 2021 18:37:21 +0200 Subject: [PATCH 32/62] fix: Fix harcoded gas limit value on helpers --- hardhat.config.ts | 2 +- helpers/init-helpers.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 5b263e36..131f328e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -30,7 +30,7 @@ import 'solidity-coverage'; import { fork } from 'child_process'; const SKIP_LOAD = process.env.SKIP_LOAD === 'true'; -const DEFAULT_BLOCK_GAS_LIMIT = 12450000; +const DEFAULT_BLOCK_GAS_LIMIT = 8000000; const DEFAULT_GAS_MUL = 5; const HARDFORK = 'istanbul'; const ETHERSCAN_KEY = process.env.ETHERSCAN_KEY || ''; diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index 6f1de0ab..01e26bd8 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -270,9 +270,7 @@ export const configureReservesByHelper = async ( console.log(`- Configure reserves in ${chunkedInputParams.length} txs`); for (let chunkIndex = 0; chunkIndex < chunkedInputParams.length; chunkIndex++) { await waitForTx( - await atokenAndRatesDeployer.configureReserves(chunkedInputParams[chunkIndex], { - gasLimit: 8000000, // TODO: Change this - }) + await atokenAndRatesDeployer.configureReserves(chunkedInputParams[chunkIndex]) ); console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); } From a000ed9134548091b7cf21a71dd0b8247ec0a6fe Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 17 Aug 2021 18:38:56 +0200 Subject: [PATCH 33/62] fix: Fix comments and ts style warnings --- helpers/contracts-deployments.ts | 2 -- helpers/types.ts | 7 +++---- markets/avalanche/commons.ts | 6 +++--- markets/avalanche/index.ts | 2 +- test-suites/test-aave/__setup.spec.ts | 4 ++-- test-suites/test-amm/__setup.spec.ts | 4 ++-- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index ef60441e..700f1a43 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -666,8 +666,6 @@ export const deployATokenImplementations = async ( }, new Set()), ]; - console.log(aTokenImplementations); - for (let x = 0; x < aTokenImplementations.length; x++) { const aTokenAddress = getOptionalParamAddressPerNetwork( poolConfig[aTokenImplementations[x].toString()], diff --git a/helpers/types.ts b/helpers/types.ts index c4912437..5f9cdebf 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -38,15 +38,14 @@ export enum EthereumNetworkNames { mumbai = 'mumbai', xdai = 'xdai', avalanche = 'avalanche', - fuji = 'fuji' - + fuji = 'fuji', } export enum AavePools { proto = 'proto', matic = 'matic', amm = 'amm', - avalanche = 'avalanche' + avalanche = 'avalanche', } export enum eContractid { @@ -367,7 +366,7 @@ export enum TokenContractId { WMATIC = 'WMATIC', STAKE = 'STAKE', xSUSHI = 'xSUSHI', - AVAX = 'AVAX' + AVAX = 'AVAX', } export interface IReserveParams extends IReserveBorrowParams, IReserveCollateralParams { diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index e01b338a..eeed73ce 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -117,7 +117,7 @@ export const CommonsConfig: ICommonConfiguration = { }, FallbackOracle: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, - [eAvalancheNetwork.fuji]: ZERO_ADDRESS // TODO: Deploy? + [eAvalancheNetwork.fuji]: ZERO_ADDRESS }, ChainlinkAggregator: { [eAvalancheNetwork.avalanche]: { @@ -150,8 +150,8 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.fuji]: '' }, WETH: { - [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // TODO: ETH Address - [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0' // TODO: Mock ETH + [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // WETH Address + [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0' // MintableERC20 WETH }, WrappedNativeToken: { [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // Official WAVAX diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts index 4c27bfca..ec2105c9 100644 --- a/markets/avalanche/index.ts +++ b/markets/avalanche/index.ts @@ -39,7 +39,7 @@ export const AvalancheConfig: IAvalancheConfiguration = { WBTC: '0x408D4cD0ADb7ceBd1F1A1C33A0Ba2098E1295bAB', // AVAX: '' // TODO: Use WAVAX? }, - [eAvalancheNetwork.fuji]: { // TODO: Deploy Mock tokens + [eAvalancheNetwork.fuji]: { // MintableERC20 tokens WETH: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0', // DAI: '0x51BC2DfB9D12d9dB50C855A5330fBA0faF761D15', // USDC: '0x7804D7f48f6E5749AF5c8Fa87b20702C34a7f5c2', diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index 463435ea..afaf711b 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -13,7 +13,6 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -29,6 +28,7 @@ import { deployFlashLiquidationAdapter, authorizeWETHGateway, deployATokenImplementations, + deployAaveOracle, } from '../../helpers/contracts-deployments'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; @@ -221,7 +221,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { config.OracleQuoteCurrency ); - await deployAaveOracleV2([ + await deployAaveOracle([ tokens, aggregators, fallbackOracle.address, diff --git a/test-suites/test-amm/__setup.spec.ts b/test-suites/test-amm/__setup.spec.ts index ef398214..448ea7fd 100644 --- a/test-suites/test-amm/__setup.spec.ts +++ b/test-suites/test-amm/__setup.spec.ts @@ -13,7 +13,6 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - deployAaveOracleV2, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, @@ -29,6 +28,7 @@ import { deployFlashLiquidationAdapter, authorizeWETHGateway, deployATokenImplementations, + deployAaveOracle, } from '../../helpers/contracts-deployments'; import { Signer } from 'ethers'; import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../../helpers/types'; @@ -226,7 +226,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { config.OracleQuoteCurrency ); - await deployAaveOracleV2([ + await deployAaveOracle([ tokens, aggregators, fallbackOracle.address, From d9f7cafed3c79b24f7cc34c6f5e25d0551e5271a Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 17 Aug 2021 18:58:06 +0200 Subject: [PATCH 34/62] fix: Update avalanche market addreses --- markets/avalanche/commons.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index eeed73ce..71008b00 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -81,31 +81,31 @@ export const CommonsConfig: ICommonConfiguration = { }, ProviderRegistry: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x2e4c88B23A52Af210619E9FFA4371708E3Bfc286' + [eAvalancheNetwork.fuji]: '0xEDb9d071dA6c292656C4BC1ADCb70e13f0CdC3b1' }, ProviderRegistryOwner: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xA68E2f643e0fa7062A78DFB6C629577aE21ad829' + [eAvalancheNetwork.fuji]: '0x1128d177BdaA74Ae68EB06e693f4CbA6BF427a5e' }, LendingRateOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x0BA6fa6D6800dc900dB82d58D135fD0e0DA1a77A' + [eAvalancheNetwork.fuji]: '0xa10cA0221BC857413eD0c792d1AFfCFB12381e22' }, LendingPoolCollateralManager: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x102035669D37a48689859A9F1cf03F294c8b7f56' + [eAvalancheNetwork.fuji]: '0x7a9f468bF0a9B781BB1fdB7D3B9D479aD4aFEA13' }, LendingPoolConfigurator: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x4de9ee3d1F33676e505CA3747993929c29802293' + [eAvalancheNetwork.fuji]: '0x257B5C93d0736be3abA7D297Aa4A62CB5a932352' }, LendingPool: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '0xaFb8283e2B34eD6C2E383337Fd92c3A47D00f2b4' }, WethGateway: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' + [eAvalancheNetwork.fuji]: '0x4Dc3A7c0Aba87280a3dBdD947cda4D2C55b2c539' }, TokenDistributor: { [eAvalancheNetwork.avalanche]: '', @@ -113,7 +113,7 @@ export const CommonsConfig: ICommonConfiguration = { }, AaveOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x7cb1a6663D864eBD5cB0cDA6063FBf5e3A9285eC' + [eAvalancheNetwork.fuji]: '0xf18C4eFEE87dBa5776F218De3f1e4672C6E07D70' }, FallbackOracle: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, @@ -158,8 +158,8 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // Official WAVAX }, ReserveFactorTreasuryAddress: { - [eAvalancheNetwork.avalanche]: '0x652e2Ac6b072Ba8bF7BEF2B11B092447dBc40bde', // TODO: Deploy Treasury - [eAvalancheNetwork.fuji]: '0x652e2Ac6b072Ba8bF7BEF2B11B092447dBc40bde' + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288' // Self-controlled EOA }, IncentivesController: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, From 90d51338f47fee56021ec5599a3ca7707eb3767a Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 18 Aug 2021 08:42:45 +0200 Subject: [PATCH 35/62] fix: Fix package json script for market deployment --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52260d55..5e963a7d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "aave:kovan:full:migration": "npm run compile && npm run hardhat:kovan -- aave:mainnet --skip-registry", "matic:mumbai:full:migration": "npm run compile && npm run hardhat:mumbai sidechain:mainnet -- --pool Matic --skip-registry", "matic:matic:full:migration": "npm run compile && npm run hardhat:matic sidechain:mainnet -- --pool Matic --skip-registry", - "avalanche:fuji:full:migration": "npm run compile && npm run hardhat:fuji avalanche:mainnet -- --pool Avalanche --skip-registry", + "avalanche:fuji:full:migration": "npm run compile && npm run hardhat:fuji avalanche:mainnet -- --pool Avalanche", "amm:kovan:full:migration": "npm run compile && npm run hardhat:kovan -- amm:mainnet --skip-registry", "aave:docker:full:migration:add-registry": "npm run compile && npm run hardhat:docker -- aave:mainnet", "aave:kovan:full:migration:add-registry": "npm run compile && npm run hardhat:kovan -- aave:mainnet", From 6d7be2f559f729243d04cdf4a88589881fd2fb8e Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 24 Aug 2021 10:38:24 +0200 Subject: [PATCH 36/62] fix: Fix Avalanche deployment params --- markets/avalanche/commons.ts | 2 +- markets/avalanche/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 71008b00..62581f94 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -18,7 +18,7 @@ export const CommonsConfig: ICommonConfiguration = { ATokenNamePrefix: 'Aave Avalanche Market', StableDebtTokenNamePrefix: 'Aave Avalanche Market stable debt', VariableDebtTokenNamePrefix: 'Aave Avalanche Market variable debt', - SymbolPrefix: '', // TODO: add a symbol? + SymbolPrefix: 'ava', ProviderId: 0, // Overriden in index.ts OracleQuoteCurrency: 'USD', OracleQuoteUnit: oneUsd.toString(), diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts index ec2105c9..a492589a 100644 --- a/markets/avalanche/index.ts +++ b/markets/avalanche/index.ts @@ -19,7 +19,7 @@ import { export const AvalancheConfig: IAvalancheConfiguration = { ...CommonsConfig, MarketId: 'Avalanche market', - ProviderId: 5, // TODO: What is this? + ProviderId: 4, ReservesConfig: { WETH: strategyWETH, DAI: strategyDAI, From e82ea5afed17c8fb59f403f323be3f3a66856d02 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 24 Aug 2021 10:39:11 +0200 Subject: [PATCH 37/62] feat: Add AVAX token to Fuji deployment --- markets/avalanche/commons.ts | 2 +- markets/avalanche/index.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 62581f94..e6af12d4 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -136,7 +136,7 @@ export const CommonsConfig: ICommonConfiguration = { USDT: '0x7898AcCC83587C3C55116c5230C17a6Cd9C71bad', // AAVE: '', WBTC: '0x31CF013A08c6Ac228C94551d535d5BAfE19c602a', - // AVAX: '0x5498BB86BC934c8D34FDA08E81D444153d0D06aD', + AVAX: '0x5498BB86BC934c8D34FDA08E81D444153d0D06aD', USD: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA' }, }, diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts index a492589a..a0d4ab13 100644 --- a/markets/avalanche/index.ts +++ b/markets/avalanche/index.ts @@ -9,7 +9,7 @@ import { strategyUSDT, strategyAAVE, strategyWBTC, - strategyAVAX + strategyAVAX, } from './reservesConfigs'; // ---------------- @@ -39,14 +39,14 @@ export const AvalancheConfig: IAvalancheConfiguration = { WBTC: '0x408D4cD0ADb7ceBd1F1A1C33A0Ba2098E1295bAB', // AVAX: '' // TODO: Use WAVAX? }, - [eAvalancheNetwork.fuji]: { // MintableERC20 tokens - WETH: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0', + [eAvalancheNetwork.fuji]: { + WETH: '0x9668f5f55f2712Dd2dfa316256609b516292D554', // MintableERC20 token // DAI: '0x51BC2DfB9D12d9dB50C855A5330fBA0faF761D15', // USDC: '0x7804D7f48f6E5749AF5c8Fa87b20702C34a7f5c2', - USDT: '0x533AE347203DD2aa2bc710E93cafE7650E1bC4e2', + USDT: '0x02823f9B469960Bb3b1de0B3746D4b95B7E35543', // MintableERC20 token // AAVE: '0x47183584aCbc1C45608d7B61cce1C562Ee180E7e', - WBTC: '0xDc880858bFE85F41deadBbB1CA1e6fFCe25f5B66', - // AVAX: '0x28575C264f7bf17e8C91f80585765D92d4B9d113' + WBTC: '0x9C1DCacB57ADa1E9e2D3a8280B7cfC7EB936186F', // MintableERC20 token + AVAX: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // Official WAVAX }, }, }; From 8e3df61e6af3958e46bae6142c5d6b3d3e8a5504 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 24 Aug 2021 10:39:40 +0200 Subject: [PATCH 38/62] feat: Add FUJI Incentives Controller Address --- markets/avalanche/commons.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index e6af12d4..e4fe5a7c 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -163,6 +163,6 @@ export const CommonsConfig: ICommonConfiguration = { }, IncentivesController: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, - [eAvalancheNetwork.fuji]: ZERO_ADDRESS + [eAvalancheNetwork.fuji]: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55' // AVAX Incentives Controller }, }; From df64cbef19556c176e34da6d65d3345c658f9af4 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Tue, 24 Aug 2021 10:40:22 +0200 Subject: [PATCH 39/62] feat: Add latest FUJI deployment addresses --- markets/avalanche/commons.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index e4fe5a7c..84b482ec 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -81,7 +81,7 @@ export const CommonsConfig: ICommonConfiguration = { }, ProviderRegistry: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xEDb9d071dA6c292656C4BC1ADCb70e13f0CdC3b1' + [eAvalancheNetwork.fuji]: '0x06eC0BDC3997EE32Cb5B66a1B9C11d92e2C27Aab' }, ProviderRegistryOwner: { [eAvalancheNetwork.avalanche]: '', @@ -89,23 +89,23 @@ export const CommonsConfig: ICommonConfiguration = { }, LendingRateOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xa10cA0221BC857413eD0c792d1AFfCFB12381e22' + [eAvalancheNetwork.fuji]: '0xEbBD998B7Dc2a8E675F0859d907c8Fa6027aBc7b' }, LendingPoolCollateralManager: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x7a9f468bF0a9B781BB1fdB7D3B9D479aD4aFEA13' + [eAvalancheNetwork.fuji]: '0x6242bE2fB5591FA1e81a99e6DD55Ff667fa82a71' }, LendingPoolConfigurator: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x257B5C93d0736be3abA7D297Aa4A62CB5a932352' + [eAvalancheNetwork.fuji]: '' }, LendingPool: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xaFb8283e2B34eD6C2E383337Fd92c3A47D00f2b4' + [eAvalancheNetwork.fuji]: '0x5f3968A2E41C95A95329333d44AB989de6c43f8E' }, WethGateway: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x4Dc3A7c0Aba87280a3dBdD947cda4D2C55b2c539' + [eAvalancheNetwork.fuji]: '0x62AF6258d26838f33BADFbb33cf1De8FaB8EB19f' }, TokenDistributor: { [eAvalancheNetwork.avalanche]: '', @@ -113,7 +113,7 @@ export const CommonsConfig: ICommonConfiguration = { }, AaveOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xf18C4eFEE87dBa5776F218De3f1e4672C6E07D70' + [eAvalancheNetwork.fuji]: '0xD217DdD9f0Af84644dEFe84a0b634621D4617a29' }, FallbackOracle: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, From 2d3bcf29f90e22bdabbe83b6e3d7b1a10fab88d8 Mon Sep 17 00:00:00 2001 From: karotjal Date: Tue, 24 Aug 2021 13:31:43 +0200 Subject: [PATCH 40/62] feat: update uipooldataprovider task config --- tasks/deployments/deploy-UiPoolDataProvider.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tasks/deployments/deploy-UiPoolDataProvider.ts b/tasks/deployments/deploy-UiPoolDataProvider.ts index 1f24a892..37c82320 100644 --- a/tasks/deployments/deploy-UiPoolDataProvider.ts +++ b/tasks/deployments/deploy-UiPoolDataProvider.ts @@ -1,5 +1,11 @@ import { task } from 'hardhat/config'; -import { eAvalancheNetwork, eContractid, eEthereumNetwork, eNetwork, ePolygonNetwork } from '../../helpers/types'; +import { + eAvalancheNetwork, + eContractid, + eEthereumNetwork, + eNetwork, + ePolygonNetwork, +} from '../../helpers/types'; import { deployUiPoolDataProvider } from '../../helpers/contracts-deployments'; import { exit } from 'process'; @@ -32,8 +38,8 @@ task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider aaveOracle: '0xC365C653f7229894F93994CD0b30947Ab69Ff1D5', }, [eAvalancheNetwork.fuji]: { - incentivesController: '0x0000000000000000000000000000000000000000', - aaveOracle: '0xF8a88cE4bd99dcae4634D1b11bBf4554b1B9EaCf', + incentivesController: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55', + aaveOracle: '0xD217DdD9f0Af84644dEFe84a0b634621D4617a29', }, }; const supportedNetworks = Object.keys(addressesByNetwork); From 984e19cdf3fb64c8a9a29e0879cdd77c05c6dce3 Mon Sep 17 00:00:00 2001 From: David Racero Date: Fri, 27 Aug 2021 13:22:07 +0200 Subject: [PATCH 41/62] config: revised risk config --- helpers/constants.ts | 5 +- helpers/types.ts | 6 +- markets/avalanche/commons.ts | 59 +++++----- markets/avalanche/index.ts | 36 +++--- markets/avalanche/rateStrategies.ts | 98 ++-------------- markets/avalanche/reservesConfigs.ts | 155 ++++++++++++-------------- test-suites/test-aave/__setup.spec.ts | 2 +- 7 files changed, 137 insertions(+), 224 deletions(-) diff --git a/helpers/constants.ts b/helpers/constants.ts index 7d562f5e..fe743fa2 100644 --- a/helpers/constants.ts +++ b/helpers/constants.ts @@ -31,7 +31,8 @@ export const MOCK_USD_PRICE_IN_WEI = '5848466240000000'; export const USD_ADDRESS = '0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96'; export const AAVE_REFERRAL = '0'; -export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { // Update to USD-based price feeds +export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { + // Update to USD-based price feeds AAVE: oneEther.multipliedBy('0.003620948469').toFixed(), BAT: oneEther.multipliedBy('0.00137893825230').toFixed(), BUSD: oneEther.multipliedBy('0.00736484').toFixed(), @@ -71,6 +72,6 @@ export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { // Update to USD-based price WMATIC: oneEther.multipliedBy('0.003620948469').toFixed(), STAKE: oneEther.multipliedBy('0.003620948469').toFixed(), xSUSHI: oneEther.multipliedBy('0.00913428586').toFixed(), - AVAX: oneEther.multipliedBy('0.006051936629').toFixed(), + WAVAX: oneEther.multipliedBy('0.006051936629').toFixed(), USD: '5848466240000000', }; diff --git a/helpers/types.ts b/helpers/types.ts index 5f9cdebf..f0a39994 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -247,7 +247,7 @@ export interface iAssetBase { WMATIC: T; STAKE: T; xSUSHI: T; - AVAX: T; + WAVAX: T; } export type iAssetsWithoutETH = Omit, 'ETH'>; @@ -316,7 +316,7 @@ export type iXDAIPoolAssets = Pick< export type iAvalanchePoolAssets = Pick< iAssetsWithoutUSD, - 'WETH' | 'DAI' | 'USDC' | 'USDT' | 'AAVE' | 'WBTC' | 'AVAX' + 'WETH' | 'DAI' | 'USDT' | 'AAVE' | 'WBTC' | 'WAVAX' | 'USDC' >; export type iMultiPoolsAssets = iAssetCommon | iAavePoolAssets; @@ -366,7 +366,7 @@ export enum TokenContractId { WMATIC = 'WMATIC', STAKE = 'STAKE', xSUSHI = 'xSUSHI', - AVAX = 'AVAX', + WAVAX = 'WAVAX', } export interface IReserveParams extends IReserveBorrowParams, IReserveCollateralParams { diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 84b482ec..47682fd3 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -18,7 +18,7 @@ export const CommonsConfig: ICommonConfiguration = { ATokenNamePrefix: 'Aave Avalanche Market', StableDebtTokenNamePrefix: 'Aave Avalanche Market stable debt', VariableDebtTokenNamePrefix: 'Aave Avalanche Market variable debt', - SymbolPrefix: 'ava', + SymbolPrefix: 'v', ProviderId: 0, // Overriden in index.ts OracleQuoteCurrency: 'USD', OracleQuoteUnit: oneUsd.toString(), @@ -60,9 +60,9 @@ export const CommonsConfig: ICommonConfiguration = { WBTC: { borrowRate: oneRay.multipliedBy(0.03).toFixed(), }, - AVAX: { + WAVAX: { borrowRate: oneRay.multipliedBy(0.05).toFixed(), // TODO: fix borrowRate? - } + }, }, // ---------------- // COMMON PROTOCOL ADDRESSES ACROSS POOLS @@ -71,98 +71,95 @@ export const CommonsConfig: ICommonConfiguration = { // If PoolAdmin/emergencyAdmin is set, will take priority over PoolAdminIndex/emergencyAdminIndex PoolAdmin: { [eAvalancheNetwork.avalanche]: undefined, - [eAvalancheNetwork.fuji]: undefined + [eAvalancheNetwork.fuji]: undefined, }, PoolAdminIndex: 0, EmergencyAdminIndex: 0, EmergencyAdmin: { [eAvalancheNetwork.avalanche]: undefined, - [eAvalancheNetwork.fuji]: undefined + [eAvalancheNetwork.fuji]: undefined, }, ProviderRegistry: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x06eC0BDC3997EE32Cb5B66a1B9C11d92e2C27Aab' + [eAvalancheNetwork.fuji]: '0x06eC0BDC3997EE32Cb5B66a1B9C11d92e2C27Aab', }, ProviderRegistryOwner: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x1128d177BdaA74Ae68EB06e693f4CbA6BF427a5e' + [eAvalancheNetwork.fuji]: '0x1128d177BdaA74Ae68EB06e693f4CbA6BF427a5e', }, LendingRateOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xEbBD998B7Dc2a8E675F0859d907c8Fa6027aBc7b' + [eAvalancheNetwork.fuji]: '0xEbBD998B7Dc2a8E675F0859d907c8Fa6027aBc7b', }, LendingPoolCollateralManager: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x6242bE2fB5591FA1e81a99e6DD55Ff667fa82a71' + [eAvalancheNetwork.fuji]: '0x6242bE2fB5591FA1e81a99e6DD55Ff667fa82a71', }, LendingPoolConfigurator: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '', }, LendingPool: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x5f3968A2E41C95A95329333d44AB989de6c43f8E' + [eAvalancheNetwork.fuji]: '0x5f3968A2E41C95A95329333d44AB989de6c43f8E', }, WethGateway: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0x62AF6258d26838f33BADFbb33cf1De8FaB8EB19f' + [eAvalancheNetwork.fuji]: '0x62AF6258d26838f33BADFbb33cf1De8FaB8EB19f', }, TokenDistributor: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '', }, AaveOracle: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xD217DdD9f0Af84644dEFe84a0b634621D4617a29' + [eAvalancheNetwork.fuji]: '0xD217DdD9f0Af84644dEFe84a0b634621D4617a29', }, FallbackOracle: { [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, - [eAvalancheNetwork.fuji]: ZERO_ADDRESS + [eAvalancheNetwork.fuji]: ZERO_ADDRESS, }, ChainlinkAggregator: { [eAvalancheNetwork.avalanche]: { WETH: '0x976B3D034E162d8bD72D6b9C989d545b839003b0', DAI: '0x51D7180edA2260cc4F6e4EebB82FEF5c3c2B8300', - USDC: ' 0xF096872672F44d6EBA71458D74fe67F9a77a23B9', + USDC: '0xF096872672F44d6EBA71458D74fe67F9a77a23B9', USDT: '0xEBE676ee90Fe1112671f19b6B7459bC678B67e8a', AAVE: '0x3CA13391E9fb38a75330fb28f8cc2eB3D9ceceED', WBTC: '0x2779D32d5166BAaa2B2b658333bA7e6Ec0C65743', - AVAX: '0x0A77230d17318075983913bC2145DB16C7366156', + WAVAX: '0x0A77230d17318075983913bC2145DB16C7366156', }, [eAvalancheNetwork.fuji]: { WETH: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA', - // DAI: '', - // USDC: '', USDT: '0x7898AcCC83587C3C55116c5230C17a6Cd9C71bad', - // AAVE: '', WBTC: '0x31CF013A08c6Ac228C94551d535d5BAfE19c602a', - AVAX: '0x5498BB86BC934c8D34FDA08E81D444153d0D06aD', - USD: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA' + WAVAX: '0x5498BB86BC934c8D34FDA08E81D444153d0D06aD', + USD: '0x86d67c3D38D2bCeE722E601025C25a575021c6EA', }, }, ReserveAssets: { [eAvalancheNetwork.avalanche]: {}, - [eAvalancheNetwork.fuji]: {} + [eAvalancheNetwork.fuji]: {}, }, ReservesConfig: {}, ATokenDomainSeparator: { [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '' + [eAvalancheNetwork.fuji]: '', }, WETH: { [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // WETH Address - [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0' // MintableERC20 WETH + [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0', // MintableERC20 WETH }, WrappedNativeToken: { - [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // Official WAVAX - [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // Official WAVAX + [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // Official WAVAX + [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c', // Official WAVAX }, ReserveFactorTreasuryAddress: { - [eAvalancheNetwork.avalanche]: '', - [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288' // Self-controlled EOA + [eAvalancheNetwork.avalanche]: '0xBDEE917d2BDE529eDEc5b20e0B770F56EDFE8e74', // Not Final, only for test purposes + [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288', // Self-controlled EOA }, IncentivesController: { - [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, - [eAvalancheNetwork.fuji]: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55' // AVAX Incentives Controller + [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, // Not final, no incentives proxy for test purposes + [eAvalancheNetwork.fuji]: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55', // WAVAX Incentives Controller }, }; diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts index a0d4ab13..381c2b8d 100644 --- a/markets/avalanche/index.ts +++ b/markets/avalanche/index.ts @@ -1,5 +1,10 @@ import { oneRay, ZERO_ADDRESS } from '../../helpers/constants'; -import { IAaveConfiguration, eEthereumNetwork, eAvalancheNetwork, IAvalancheConfiguration } from '../../helpers/types'; +import { + IAaveConfiguration, + eEthereumNetwork, + eAvalancheNetwork, + IAvalancheConfiguration, +} from '../../helpers/types'; import { CommonsConfig } from './commons'; import { @@ -9,7 +14,7 @@ import { strategyUSDT, strategyAAVE, strategyWBTC, - strategyAVAX, + strategyWAVAX, } from './reservesConfigs'; // ---------------- @@ -23,30 +28,29 @@ export const AvalancheConfig: IAvalancheConfiguration = { ReservesConfig: { WETH: strategyWETH, DAI: strategyDAI, - USDC: strategyUSDC, USDT: strategyUSDT, + USDC: strategyUSDC, AAVE: strategyAAVE, WBTC: strategyWBTC, - AVAX: strategyAVAX, + WAVAX: strategyWAVAX, }, ReserveAssets: { - [eAvalancheNetwork.avalanche]: { // TODO: Check this - WETH: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', - // DAI: '0xbA7dEebBFC5fA1100Fb055a87773e1E99Cd3507a', - // USDC: '', // TODO: Not yet deployed by Circle - USDT: '0xde3A24028580884448a5397872046a019649b084', - // AAVE: '0x8cE2Dee54bB9921a2AE0A63dBb2DF8eD88B91dD9', // TODO: What we are going to do? - WBTC: '0x408D4cD0ADb7ceBd1F1A1C33A0Ba2098E1295bAB', - // AVAX: '' // TODO: Use WAVAX? + [eAvalancheNetwork.avalanche]: { + WETH: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab', + DAI: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', + USDT: '0xc7198437980c041c805a1edcba50c1ce5db95118', + USDC: '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', + AAVE: '0x63a72806098bd3d9520cc43356dd78afe5d386d9', + WBTC: '0x50b7545627a5162f82a992c33b87adc75187b218', + WAVAX: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', }, [eAvalancheNetwork.fuji]: { WETH: '0x9668f5f55f2712Dd2dfa316256609b516292D554', // MintableERC20 token - // DAI: '0x51BC2DfB9D12d9dB50C855A5330fBA0faF761D15', - // USDC: '0x7804D7f48f6E5749AF5c8Fa87b20702C34a7f5c2', + DAI: '0x51BC2DfB9D12d9dB50C855A5330fBA0faF761D15', USDT: '0x02823f9B469960Bb3b1de0B3746D4b95B7E35543', // MintableERC20 token - // AAVE: '0x47183584aCbc1C45608d7B61cce1C562Ee180E7e', + AAVE: '0x47183584aCbc1C45608d7B61cce1C562Ee180E7e', WBTC: '0x9C1DCacB57ADa1E9e2D3a8280B7cfC7EB936186F', // MintableERC20 token - AVAX: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c' // Official WAVAX + WAVAX: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c', // Official WAVAX }, }, }; diff --git a/markets/avalanche/rateStrategies.ts b/markets/avalanche/rateStrategies.ts index 4a7125dd..18a16632 100644 --- a/markets/avalanche/rateStrategies.ts +++ b/markets/avalanche/rateStrategies.ts @@ -2,104 +2,22 @@ import BigNumber from 'bignumber.js'; import { oneRay } from '../../helpers/constants'; import { IInterestRateStrategyParams } from '../../helpers/types'; -// BUSD SUSD -export const rateStrategyStableOne: IInterestRateStrategyParams = { - name: "rateStrategyStableOne", - optimalUtilizationRate: new BigNumber(0.8).multipliedBy(oneRay).toFixed(), +export const rateStrategyVolatileOne: IInterestRateStrategyParams = { + name: 'rateStrategyVolatileOne', + optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), + variableRateSlope1: new BigNumber(0.07).multipliedBy(oneRay).toFixed(), + variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), stableRateSlope1: '0', stableRateSlope2: '0', }; -// DAI TUSD -export const rateStrategyStableTwo: IInterestRateStrategyParams = { - name: "rateStrategyStableTwo", +export const rateStrategyStableOne: IInterestRateStrategyParams = { + name: 'rateStrategyStableOne', optimalUtilizationRate: new BigNumber(0.8).multipliedBy(oneRay).toFixed(), baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), variableRateSlope2: new BigNumber(0.75).multipliedBy(oneRay).toFixed(), stableRateSlope1: new BigNumber(0.02).multipliedBy(oneRay).toFixed(), stableRateSlope2: new BigNumber(0.75).multipliedBy(oneRay).toFixed(), -} - -// USDC USDT -export const rateStrategyStableThree: IInterestRateStrategyParams = { - name: "rateStrategyStableThree", - optimalUtilizationRate: new BigNumber(0.9).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.04).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(0.60).multipliedBy(oneRay).toFixed(), - stableRateSlope1: new BigNumber(0.02).multipliedBy(oneRay).toFixed(), - stableRateSlope2: new BigNumber(0.60).multipliedBy(oneRay).toFixed(), -} - -// WETH -export const rateStrategyWETH: IInterestRateStrategyParams = { - name: "rateStrategyWETH", - optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), - stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), - stableRateSlope2: new BigNumber(1).multipliedBy(oneRay).toFixed(), -} - -// AAVE -export const rateStrategyAAVE: IInterestRateStrategyParams = { - name: "rateStrategyAAVE", - optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: '0', - variableRateSlope1: '0', - variableRateSlope2: '0', - stableRateSlope1: '0', - stableRateSlope2: '0', -} - -// BAT ENJ LINK MANA MKR REN YFI ZRX -export const rateStrategyVolatileOne: IInterestRateStrategyParams = { - name: "rateStrategyVolatileOne", - optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.07).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), - stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), - stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), -} - -// KNC WBTC -export const rateStrategyVolatileTwo: IInterestRateStrategyParams = { - name: "rateStrategyVolatileTwo", - optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), - stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), - stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), -} - -// SNX -export const rateStrategyVolatileThree: IInterestRateStrategyParams = { - name: "rateStrategyVolatileThree", - optimalUtilizationRate: new BigNumber(0.65).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: new BigNumber(0).multipliedBy(oneRay).toFixed(), - variableRateSlope1: new BigNumber(0.08).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), - stableRateSlope1: new BigNumber(0.1).multipliedBy(oneRay).toFixed(), - stableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), -} - - -export const rateStrategyVolatileFour: IInterestRateStrategyParams = { - name: "rateStrategyVolatileFour", - optimalUtilizationRate: new BigNumber(0.45).multipliedBy(oneRay).toFixed(), - baseVariableBorrowRate: '0', - variableRateSlope1: new BigNumber(0.07).multipliedBy(oneRay).toFixed(), - variableRateSlope2: new BigNumber(3).multipliedBy(oneRay).toFixed(), - stableRateSlope1: '0', - stableRateSlope2: '0', -} - - - +}; diff --git a/markets/avalanche/reservesConfigs.ts b/markets/avalanche/reservesConfigs.ts index 136fe54c..2599754c 100644 --- a/markets/avalanche/reservesConfigs.ts +++ b/markets/avalanche/reservesConfigs.ts @@ -1,87 +1,8 @@ import { eContractid, IReserveParams } from '../../helpers/types'; -import { - rateStrategyStableTwo, - rateStrategyStableThree, - rateStrategyWETH, - rateStrategyAAVE, - rateStrategyVolatileOne, - rateStrategyVolatileTwo, -} from './rateStrategies'; +import { rateStrategyStableOne, rateStrategyVolatileOne } from './rateStrategies'; -export const strategyDAI: IReserveParams = { - strategy: rateStrategyStableTwo, - baseLTVAsCollateral: '7500', - liquidationThreshold: '8000', - liquidationBonus: '10500', - borrowingEnabled: true, - stableBorrowRateEnabled: true, - reserveDecimals: '18', - aTokenImpl: eContractid.AToken, - reserveFactor: '1000' -}; - -export const strategyUSDC: IReserveParams = { - strategy: rateStrategyStableThree, - baseLTVAsCollateral: '8000', - liquidationThreshold: '8500', - liquidationBonus: '10500', - borrowingEnabled: true, - stableBorrowRateEnabled: true, - reserveDecimals: '6', - aTokenImpl: eContractid.AToken, - reserveFactor: '1000' -}; - -export const strategyUSDT: IReserveParams = { - strategy: rateStrategyStableThree, - baseLTVAsCollateral: '0', - liquidationThreshold: '0', - liquidationBonus: '0', - borrowingEnabled: true, - stableBorrowRateEnabled: true, - reserveDecimals: '6', - aTokenImpl: eContractid.AToken, - reserveFactor: '1000' -}; - -export const strategyAAVE: IReserveParams = { - strategy: rateStrategyAAVE, - baseLTVAsCollateral: '5000', - liquidationThreshold: '6500', - liquidationBonus: '11000', - borrowingEnabled: false, - stableBorrowRateEnabled: false, - reserveDecimals: '18', - aTokenImpl: eContractid.AToken, - reserveFactor: '0' -}; - -export const strategyWETH: IReserveParams = { - strategy: rateStrategyWETH, - baseLTVAsCollateral: '8000', - liquidationThreshold: '8250', - liquidationBonus: '10500', - borrowingEnabled: true, - stableBorrowRateEnabled: true, - reserveDecimals: '18', - aTokenImpl: eContractid.AToken, - reserveFactor: '1000' -}; - -export const strategyWBTC: IReserveParams = { - strategy: rateStrategyVolatileTwo, - baseLTVAsCollateral: '7000', - liquidationThreshold: '7500', - liquidationBonus: '11000', - borrowingEnabled: true, - stableBorrowRateEnabled: true, - reserveDecimals: '8', - aTokenImpl: eContractid.AToken, - reserveFactor: '2000' -}; - -export const strategyAVAX: IReserveParams = { +export const strategyWAVAX: IReserveParams = { strategy: rateStrategyVolatileOne, baseLTVAsCollateral: '5000', liquidationThreshold: '6500', @@ -92,3 +13,75 @@ export const strategyAVAX: IReserveParams = { aTokenImpl: eContractid.AToken, reserveFactor: '2000', }; + +export const strategyWETH: IReserveParams = { + strategy: rateStrategyVolatileOne, + baseLTVAsCollateral: '8000', + liquidationThreshold: '8250', + liquidationBonus: '10500', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '1000', +}; + +export const strategyWBTC: IReserveParams = { + strategy: rateStrategyVolatileOne, + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '8', + aTokenImpl: eContractid.AToken, + reserveFactor: '0', +}; + +export const strategyAAVE: IReserveParams = { + strategy: rateStrategyVolatileOne, + baseLTVAsCollateral: '5000', + liquidationThreshold: '6500', + liquidationBonus: '11000', + borrowingEnabled: false, + stableBorrowRateEnabled: false, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '0', +}; + +export const strategyDAI: IReserveParams = { + strategy: rateStrategyStableOne, + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '18', + aTokenImpl: eContractid.AToken, + reserveFactor: '0', +}; + +export const strategyUSDT: IReserveParams = { + strategy: rateStrategyStableOne, + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '6', + aTokenImpl: eContractid.AToken, + reserveFactor: '0', +}; + +export const strategyUSDC: IReserveParams = { + strategy: rateStrategyStableOne, + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', + borrowingEnabled: true, + stableBorrowRateEnabled: false, + reserveDecimals: '6', + aTokenImpl: eContractid.AToken, + reserveFactor: '0', +}; diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index afaf711b..cc9bee13 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -194,7 +194,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { USD: USD_ADDRESS, STAKE: mockTokens.STAKE.address, xSUSHI: mockTokens.xSUSHI.address, - AVAX: mockTokens.AVAX.address + WAVAX: mockTokens.WAVAX.address, }, fallbackOracle ); From a7a54b51aec207aa56a6b76ff1a45712a5d84d0f Mon Sep 17 00:00:00 2001 From: David Racero Date: Fri, 27 Aug 2021 13:49:28 +0200 Subject: [PATCH 42/62] fix: fix RPC url for avalanche mainnet --- helper-hardhat-config.ts | 10 +++++----- package.json | 1 + tasks/full/0_address_provider_registry.ts | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index a9bdf5cc..9e949fd7 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -53,8 +53,8 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { 'https://polygon-mainnet.g.alchemy.com/v2/6NUmfWDZw6lC3RPAphj0p_2vm7ElOn2U', // [ePolygonNetwork.matic]: 'https://rpc-mainnet.matic.network', [eXDaiNetwork.xdai]: 'https://rpc.xdaichain.com/', - [eAvalancheNetwork.avalanche]: 'https://cchain.explorer.avax.network/', - [eAvalancheNetwork.fuji]: 'https://api.avax-test.network/ext/bc/C/rpc' + [eAvalancheNetwork.avalanche]: 'https://api.avax.network/ext/bc/C/rpc', + [eAvalancheNetwork.fuji]: 'https://api.avax-test.network/ext/bc/C/rpc', }; export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { @@ -68,8 +68,8 @@ export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { [ePolygonNetwork.mumbai]: 1 * GWEI, [ePolygonNetwork.matic]: 1 * GWEI, [eXDaiNetwork.xdai]: 1 * GWEI, - [eAvalancheNetwork.avalanche]: 255 * GWEI, - [eAvalancheNetwork.fuji]: 255 * GWEI + [eAvalancheNetwork.avalanche]: 85 * GWEI, + [eAvalancheNetwork.fuji]: 85 * GWEI, }; export const BLOCK_TO_FORK: iParamsPerNetwork = { @@ -84,5 +84,5 @@ export const BLOCK_TO_FORK: iParamsPerNetwork = { [ePolygonNetwork.matic]: undefined, [eXDaiNetwork.xdai]: undefined, [eAvalancheNetwork.avalanche]: undefined, - [eAvalancheNetwork.fuji]: undefined + [eAvalancheNetwork.fuji]: undefined, }; diff --git a/package.json b/package.json index 5e963a7d..f5e98227 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "matic:matic:full:migration:add-registry": "npm run compile && npm run hardhat:matic sidechain:mainnet -- --pool Matic", "amm:kovan:full:migration:add-registry": "npm run compile && npm run hardhat:kovan -- amm:mainnet", "avalanche:fuji:full:migration:add-registry": "npm run compile && npm run hardhat:fuji avalanche:mainnet -- --pool Avalanche", + "avalanche:mainnet:full:migration:add-registry": "npm run compile && npm run hardhat:avalanche avalanche:mainnet -- --pool Avalanche", "aave:docker:add-market-to-registry-from-config": "npm run compile && npm run hardhat:docker -- add-market-to-registry --pool Aave", "aave:kovan:add-market-to-registry-from-config": "npm run compile && npm run hardhat:kovan -- add-market-to-registry --pool Aave", "matic:mumbai:add-market-to-registry-from-config": "npm run compile && npm run hardhat:mumbai add-market-to-registry --pool Matic", diff --git a/tasks/full/0_address_provider_registry.ts b/tasks/full/0_address_provider_registry.ts index 853088eb..27077c46 100644 --- a/tasks/full/0_address_provider_registry.ts +++ b/tasks/full/0_address_provider_registry.ts @@ -11,11 +11,14 @@ task('full:deploy-address-provider-registry', 'Deploy address provider registry' .addFlag('verify', 'Verify contracts at Etherscan') .addParam('pool', `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`) .setAction(async ({ verify, pool }, DRE) => { + console.log('prior dre'); await DRE.run('set-DRE'); const poolConfig = loadPoolConfig(pool); const network = DRE.network.name; const signer = await getFirstSigner(); + console.log('Deployer:', await signer.getAddress(), formatEther(await signer.getBalance())); + const providerRegistryAddress = getParamPerNetwork(poolConfig.ProviderRegistry, network); console.log('Signer', await signer.getAddress()); From 242850241f9f2a81ce3ca731394ef7c41c8d7a67 Mon Sep 17 00:00:00 2001 From: karotjal Date: Mon, 20 Sep 2021 10:59:13 +0200 Subject: [PATCH 43/62] feat: Revised Avalanche configs. Add UiPoolDataProvider helper to deployment scripts. --- markets/avalanche/commons.ts | 12 ++++++------ markets/avalanche/index.ts | 8 +------- tasks/full/6-initialize.ts | 17 ++++++++++------- tasks/verifications/1_general.ts | 9 ++++----- tasks/verifications/2_tokens.ts | 7 +------ 5 files changed, 22 insertions(+), 31 deletions(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 47682fd3..3ce0b8e8 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -147,19 +147,19 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.fuji]: '', }, WETH: { - [eAvalancheNetwork.avalanche]: '0xf20d962a6c8f70c731bd838a3a388D7d48fA6e15', // WETH Address - [eAvalancheNetwork.fuji]: '0x3b8b3fc85ccA720809Af2dA4B58cF4ce84bcbdd0', // MintableERC20 WETH + [eAvalancheNetwork.avalanche]: '', + [eAvalancheNetwork.fuji]: '', }, WrappedNativeToken: { [eAvalancheNetwork.avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // Official WAVAX [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c', // Official WAVAX }, ReserveFactorTreasuryAddress: { - [eAvalancheNetwork.avalanche]: '0xBDEE917d2BDE529eDEc5b20e0B770F56EDFE8e74', // Not Final, only for test purposes - [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288', // Self-controlled EOA + [eAvalancheNetwork.avalanche]: '', // TO BE DEPLOYED + [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288', // Self-controlled EOA for testing }, IncentivesController: { - [eAvalancheNetwork.avalanche]: ZERO_ADDRESS, // Not final, no incentives proxy for test purposes - [eAvalancheNetwork.fuji]: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55', // WAVAX Incentives Controller + [eAvalancheNetwork.avalanche]: '0x01D83Fe6A10D2f2B7AF17034343746188272cAc9', + [eAvalancheNetwork.fuji]: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55', }, }; diff --git a/markets/avalanche/index.ts b/markets/avalanche/index.ts index 381c2b8d..417f68a0 100644 --- a/markets/avalanche/index.ts +++ b/markets/avalanche/index.ts @@ -1,10 +1,4 @@ -import { oneRay, ZERO_ADDRESS } from '../../helpers/constants'; -import { - IAaveConfiguration, - eEthereumNetwork, - eAvalancheNetwork, - IAvalancheConfiguration, -} from '../../helpers/types'; +import { eAvalancheNetwork, IAvalancheConfiguration } from '../../helpers/types'; import { CommonsConfig } from './commons'; import { diff --git a/tasks/full/6-initialize.ts b/tasks/full/6-initialize.ts index f315f36b..fc93600d 100644 --- a/tasks/full/6-initialize.ts +++ b/tasks/full/6-initialize.ts @@ -3,15 +3,10 @@ import { getParamPerNetwork } from '../../helpers/contracts-helpers'; import { deployLendingPoolCollateralManager, deployWalletBalancerProvider, - deployWETHGateway, authorizeWETHGateway, + deployUiPoolDataProvider, } from '../../helpers/contracts-deployments'; -import { - loadPoolConfig, - ConfigNames, - getWethAddress, - getTreasuryAddress, -} from '../../helpers/configuration'; +import { loadPoolConfig, ConfigNames, getTreasuryAddress } from '../../helpers/configuration'; import { getWETHGateway } from '../../helpers/contracts-getters'; import { eNetwork, ICommonConfiguration } from '../../helpers/types'; import { notFalsyOrZeroAddress, waitForTx } from '../../helpers/misc-utils'; @@ -50,6 +45,8 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') const testHelpers = await getAaveProtocolDataProvider(); const admin = await addressesProvider.getPoolAdmin(); + const oracle = await addressesProvider.getPriceOracle(); + if (!reserveAssets) { throw 'Reserve assets is undefined. Check ReserveAssets configuration at config directory'; } @@ -103,6 +100,12 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') await deployWalletBalancerProvider(verify); + const uiPoolDataProvider = await deployUiPoolDataProvider( + [incentivesController, oracle], + verify + ); + console.log('UiPoolDataProvider deployed at:', uiPoolDataProvider.address); + const lendingPoolAddress = await addressesProvider.getLendingPool(); let gateWay = getParamPerNetwork(WethGateway, network); diff --git a/tasks/verifications/1_general.ts b/tasks/verifications/1_general.ts index b2b3bcb7..c7c7d233 100644 --- a/tasks/verifications/1_general.ts +++ b/tasks/verifications/1_general.ts @@ -1,11 +1,9 @@ -import { error } from 'console'; -import { zeroAddress } from 'ethereumjs-util'; import { task } from 'hardhat/config'; import { loadPoolConfig, ConfigNames, - getWethAddress, getTreasuryAddress, + getWrappedNativeTokenAddress, } from '../../helpers/configuration'; import { ZERO_ADDRESS } from '../../helpers/constants'; import { @@ -53,7 +51,8 @@ task('verify:general', 'Verify contracts at Etherscan') : await getLendingPoolAddressesProviderRegistry(); const lendingPoolAddress = await addressesProvider.getLendingPool(); const lendingPoolConfiguratorAddress = await addressesProvider.getLendingPoolConfigurator(); //getLendingPoolConfiguratorProxy(); - const lendingPoolCollateralManagerAddress = await addressesProvider.getLendingPoolCollateralManager(); + const lendingPoolCollateralManagerAddress = + await addressesProvider.getLendingPoolCollateralManager(); const lendingPoolProxy = await getProxy(lendingPoolAddress); const lendingPoolConfiguratorProxy = await getProxy(lendingPoolConfiguratorAddress); @@ -132,7 +131,7 @@ task('verify:general', 'Verify contracts at Etherscan') // WETHGateway console.log('\n- Verifying WETHGateway...\n'); await verifyContract(eContractid.WETHGateway, wethGateway, [ - await getWethAddress(poolConfig), + await getWrappedNativeTokenAddress(poolConfig), ]); } // Lending Pool proxy diff --git a/tasks/verifications/2_tokens.ts b/tasks/verifications/2_tokens.ts index eacc7f92..bbe5bbab 100644 --- a/tasks/verifications/2_tokens.ts +++ b/tasks/verifications/2_tokens.ts @@ -1,10 +1,5 @@ import { task } from 'hardhat/config'; -import { - loadPoolConfig, - ConfigNames, - getWethAddress, - getTreasuryAddress, -} from '../../helpers/configuration'; +import { loadPoolConfig, ConfigNames, getTreasuryAddress } from '../../helpers/configuration'; import { ZERO_ADDRESS } from '../../helpers/constants'; import { getAddressById, From a7337104b9440eaaca34f4d666e1673105976502 Mon Sep 17 00:00:00 2001 From: karotjal Date: Mon, 20 Sep 2021 12:21:12 +0200 Subject: [PATCH 44/62] config: adjusted risk parameters for avalanche --- markets/avalanche/reservesConfigs.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/markets/avalanche/reservesConfigs.ts b/markets/avalanche/reservesConfigs.ts index 2599754c..e5804cdf 100644 --- a/markets/avalanche/reservesConfigs.ts +++ b/markets/avalanche/reservesConfigs.ts @@ -35,31 +35,31 @@ export const strategyWBTC: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '8', aTokenImpl: eContractid.AToken, - reserveFactor: '0', + reserveFactor: '2000', }; export const strategyAAVE: IReserveParams = { strategy: rateStrategyVolatileOne, baseLTVAsCollateral: '5000', liquidationThreshold: '6500', - liquidationBonus: '11000', + liquidationBonus: '10800', borrowingEnabled: false, stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '0', + reserveFactor: '2000', }; export const strategyDAI: IReserveParams = { strategy: rateStrategyStableOne, - baseLTVAsCollateral: '0', - liquidationThreshold: '0', - liquidationBonus: '0', + baseLTVAsCollateral: '7500', + liquidationThreshold: '8000', + liquidationBonus: '10500', borrowingEnabled: true, stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '0', + reserveFactor: '1000', }; export const strategyUSDT: IReserveParams = { @@ -71,17 +71,17 @@ export const strategyUSDT: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '0', + reserveFactor: '1000', }; export const strategyUSDC: IReserveParams = { strategy: rateStrategyStableOne, - baseLTVAsCollateral: '0', - liquidationThreshold: '0', - liquidationBonus: '0', + baseLTVAsCollateral: '7500', + liquidationThreshold: '8000', + liquidationBonus: '10500', borrowingEnabled: true, stableBorrowRateEnabled: false, reserveDecimals: '6', aTokenImpl: eContractid.AToken, - reserveFactor: '0', + reserveFactor: '1000', }; From 153f8692718bb1e9fca9080d3218aa04d8a20079 Mon Sep 17 00:00:00 2001 From: karotjal Date: Mon, 20 Sep 2021 12:39:42 +0200 Subject: [PATCH 45/62] config: Added ReserveFactor address --- markets/avalanche/commons.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markets/avalanche/commons.ts b/markets/avalanche/commons.ts index 3ce0b8e8..3129d9e8 100644 --- a/markets/avalanche/commons.ts +++ b/markets/avalanche/commons.ts @@ -155,7 +155,7 @@ export const CommonsConfig: ICommonConfiguration = { [eAvalancheNetwork.fuji]: '0xd00ae08403B9bbb9124bB305C09058E32C39A48c', // Official WAVAX }, ReserveFactorTreasuryAddress: { - [eAvalancheNetwork.avalanche]: '', // TO BE DEPLOYED + [eAvalancheNetwork.avalanche]: '0x467b92aF281d14cB6809913AD016a607b5ba8A36', [eAvalancheNetwork.fuji]: '0xB45F5C501A22288dfdb897e5f73E189597e09288', // Self-controlled EOA for testing }, IncentivesController: { From c0caf657962b2b0808a90ef1e18d3c59f19a0248 Mon Sep 17 00:00:00 2001 From: karotjal Date: Mon, 20 Sep 2021 12:44:18 +0200 Subject: [PATCH 46/62] feat: pause Pool at deployment scripts --- tasks/full/2_lending_pool.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasks/full/2_lending_pool.ts b/tasks/full/2_lending_pool.ts index ac930251..e67dcaed 100644 --- a/tasks/full/2_lending_pool.ts +++ b/tasks/full/2_lending_pool.ts @@ -70,6 +70,10 @@ task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') eContractid.LendingPoolConfigurator, lendingPoolConfiguratorProxy.address ); + + // Pause market during deployment + await waitForTx(await lendingPoolConfiguratorProxy.setPoolPause(true)); + // Deploy deployment helpers await deployStableAndVariableTokensHelper( [lendingPoolProxy.address, addressesProvider.address], From 58556fc055a263e3f2ac1522a20062fa86a19315 Mon Sep 17 00:00:00 2001 From: kartojal Date: Tue, 28 Sep 2021 15:25:09 +0200 Subject: [PATCH 48/62] config: Update risk parameters Updated risk parameters following the accepted community proposal at Snapshot https://snapshot.org/#/aave.eth/proposal/QmbGh1VP1w51PfBWkEmNquD95NJhJ8Eaqma6PP8psP9HGy --- markets/avalanche/reservesConfigs.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/markets/avalanche/reservesConfigs.ts b/markets/avalanche/reservesConfigs.ts index e5804cdf..192ac890 100644 --- a/markets/avalanche/reservesConfigs.ts +++ b/markets/avalanche/reservesConfigs.ts @@ -11,7 +11,7 @@ export const strategyWAVAX: IReserveParams = { stableBorrowRateEnabled: false, reserveDecimals: '18', aTokenImpl: eContractid.AToken, - reserveFactor: '2000', + reserveFactor: '1500', }; export const strategyWETH: IReserveParams = { @@ -28,21 +28,21 @@ export const strategyWETH: IReserveParams = { export const strategyWBTC: IReserveParams = { strategy: rateStrategyVolatileOne, - baseLTVAsCollateral: '0', - liquidationThreshold: '0', - liquidationBonus: '0', + baseLTVAsCollateral: '6000', + liquidationThreshold: '7500', + liquidationBonus: '10500', borrowingEnabled: true, stableBorrowRateEnabled: false, reserveDecimals: '8', aTokenImpl: eContractid.AToken, - reserveFactor: '2000', + reserveFactor: '1000', }; export const strategyAAVE: IReserveParams = { strategy: rateStrategyVolatileOne, - baseLTVAsCollateral: '5000', + baseLTVAsCollateral: '4000', liquidationThreshold: '6500', - liquidationBonus: '10800', + liquidationBonus: '11000', borrowingEnabled: false, stableBorrowRateEnabled: false, reserveDecimals: '18', From 03c525314cf1c21a8855f0daab4fd6358eaf3055 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 29 Sep 2021 17:36:36 +0200 Subject: [PATCH 49/62] fix: Fix error at mumbai config --- markets/matic/commons.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 8a0274a0..5b261303 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -132,6 +132,7 @@ export const CommonsConfig: ICommonConfiguration = { USDT: ZERO_ADDRESS, WBTC: ZERO_ADDRESS, WMATIC: ZERO_ADDRESS, + USD: ZERO_ADDRESS, }, }, ReserveAssets: { From 69c826ba48d387ba245ad9e250f514561daf36e3 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 29 Sep 2021 17:52:44 +0200 Subject: [PATCH 50/62] fix: Add addresses to mumbai market config --- markets/matic/commons.ts | 18 +++++++++--------- markets/matic/index.ts | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 5b261303..49d2e0b1 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -77,27 +77,27 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: undefined, }, LendingPool: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0x9198F13B08E299d85E096929fA9781A1E3d5d827', [ePolygonNetwork.matic]: '', }, LendingPoolConfigurator: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0xc3c37E2aA3dc66464fa3C29ce2a6EC85beFC45e1', [ePolygonNetwork.matic]: '', }, ProviderRegistry: { - [ePolygonNetwork.mumbai]: ZERO_ADDRESS, + [ePolygonNetwork.mumbai]: '0xE6ef11C967898F9525D550014FDEdCFAB63536B5', [ePolygonNetwork.matic]: '0x3ac4e9aa29940770aeC38fe853a4bbabb2dA9C19', }, ProviderRegistryOwner: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0x943E44157dC0302a5CEb172374d1749018a00994', [ePolygonNetwork.matic]: '0xD7D86236d6c463521920fCC50A9CB56f8C8Bf008', }, LendingRateOracle: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0xC661e1445F9a8E5FD3C3dbCa0A0A2e8CBc79725D', [ePolygonNetwork.matic]: '0x17F73aEaD876CC4059089ff815EDA37052960dFB', }, LendingPoolCollateralManager: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0x2A7004B21c49253ca8DF923406Fed9a02AA86Ba0', [ePolygonNetwork.matic]: '', }, TokenDistributor: { @@ -105,11 +105,11 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: '', }, WethGateway: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0xee9eE614Ad26963bEc1Bec0D2c92879ae1F209fA', [ePolygonNetwork.matic]: '', }, AaveOracle: { - [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.mumbai]: '0xC365C653f7229894F93994CD0b30947Ab69Ff1D5', [ePolygonNetwork.matic]: '0x0229F777B0fAb107F9591a41d5F02E4e98dB6f2d', }, FallbackOracle: { @@ -157,7 +157,7 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: '0x7734280A4337F37Fbf4651073Db7c28C80B339e9', }, IncentivesController: { - [ePolygonNetwork.mumbai]: ZERO_ADDRESS, + [ePolygonNetwork.mumbai]: '0xd41aE58e803Edf4304334acCE4DC4Ec34a63C644', [ePolygonNetwork.matic]: '0x357D51124f59836DeD84c8a1730D72B749d8BC23', }, }; diff --git a/markets/matic/index.ts b/markets/matic/index.ts index e5bb55bf..ba89c313 100644 --- a/markets/matic/index.ts +++ b/markets/matic/index.ts @@ -40,11 +40,11 @@ export const MaticConfig: IMaticConfiguration = { }, [ePolygonNetwork.mumbai]: { // Mock tokens with a simple "mint" external function, except wmatic - DAI: '0x13b3fda609C1eeb23b4F4b69257840760dCa6C4a', - USDC: '0x52b63223994433FdE2F1350Ba69Dfd2779f06ABA', - USDT: '0xB3abd1912F586fDFFa13606882c28E27913853d2', - WBTC: '0x393E3512d45a956A628124665672312ea86930Ba', - WETH: '0x53CDb16B8C031B779e996406546614E5F05BC4Bf', + DAI: '0x001B3B4d0F3714Ca98ba10F6042DaEbF0B1B7b6F', + USDC: '0x2058A9D7613eEE744279e3856Ef0eAda5FCbaA7e', + USDT: '0xBD21A10F619BE90d6066c941b04e340841F1F989', + WBTC: '0x0d787a4a1548f673ed375445535a6c7A1EE56180', + WETH: '0x3C68CE8504087f89c640D02d133646d98e64ddd9', WMATIC: '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889', }, }, From 8238da70950c2a3adb8fbd4cb6cc2365c98e85b8 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Wed, 29 Sep 2021 17:53:07 +0200 Subject: [PATCH 51/62] fix: Fix matic market config details --- markets/aave/reservesConfigs.ts | 6 +++--- markets/matic/commons.ts | 8 ++++---- markets/matic/index.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/markets/aave/reservesConfigs.ts b/markets/aave/reservesConfigs.ts index a29e16d7..501d9e46 100644 --- a/markets/aave/reservesConfigs.ts +++ b/markets/aave/reservesConfigs.ts @@ -74,9 +74,9 @@ export const strategyUSDC: IReserveParams = { export const strategyUSDT: IReserveParams = { strategy: rateStrategyStableThree, - baseLTVAsCollateral: '8000', - liquidationThreshold: '8500', - liquidationBonus: '10500', + baseLTVAsCollateral: '0', + liquidationThreshold: '0', + liquidationBonus: '0', borrowingEnabled: true, stableBorrowRateEnabled: true, reserveDecimals: '6', diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 49d2e0b1..23173af5 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -78,11 +78,11 @@ export const CommonsConfig: ICommonConfiguration = { }, LendingPool: { [ePolygonNetwork.mumbai]: '0x9198F13B08E299d85E096929fA9781A1E3d5d827', - [ePolygonNetwork.matic]: '', + [ePolygonNetwork.matic]: '0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf', }, LendingPoolConfigurator: { [ePolygonNetwork.mumbai]: '0xc3c37E2aA3dc66464fa3C29ce2a6EC85beFC45e1', - [ePolygonNetwork.matic]: '', + [ePolygonNetwork.matic]: '0x26db2B833021583566323E3b8985999981b9F1F3', }, ProviderRegistry: { [ePolygonNetwork.mumbai]: '0xE6ef11C967898F9525D550014FDEdCFAB63536B5', @@ -98,7 +98,7 @@ export const CommonsConfig: ICommonConfiguration = { }, LendingPoolCollateralManager: { [ePolygonNetwork.mumbai]: '0x2A7004B21c49253ca8DF923406Fed9a02AA86Ba0', - [ePolygonNetwork.matic]: '', + [ePolygonNetwork.matic]: '0xA39599424642D9fD35e475EF802EddF798dc555B', }, TokenDistributor: { [ePolygonNetwork.mumbai]: '', @@ -106,7 +106,7 @@ export const CommonsConfig: ICommonConfiguration = { }, WethGateway: { [ePolygonNetwork.mumbai]: '0xee9eE614Ad26963bEc1Bec0D2c92879ae1F209fA', - [ePolygonNetwork.matic]: '', + [ePolygonNetwork.matic]: '0xbEadf48d62aCC944a06EEaE0A9054A90E5A7dc97', }, AaveOracle: { [ePolygonNetwork.mumbai]: '0xC365C653f7229894F93994CD0b30947Ab69Ff1D5', diff --git a/markets/matic/index.ts b/markets/matic/index.ts index ba89c313..d29564d9 100644 --- a/markets/matic/index.ts +++ b/markets/matic/index.ts @@ -18,7 +18,7 @@ import { export const MaticConfig: IMaticConfiguration = { ...CommonsConfig, MarketId: 'Matic Market', - ProviderId: 3, // Unknown? + ProviderId: 3, ReservesConfig: { DAI: strategyDAI, USDC: strategyUSDC, From b026a93552081efd316631b89bd2ce63285e3dfc Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Thu, 30 Sep 2021 17:43:06 +0200 Subject: [PATCH 52/62] fix: Fix mtic market config details --- markets/matic/commons.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/markets/matic/commons.ts b/markets/matic/commons.ts index 23173af5..c3e15404 100644 --- a/markets/matic/commons.ts +++ b/markets/matic/commons.ts @@ -77,12 +77,12 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: undefined, }, LendingPool: { - [ePolygonNetwork.mumbai]: '0x9198F13B08E299d85E096929fA9781A1E3d5d827', - [ePolygonNetwork.matic]: '0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf', + [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.matic]: '', }, LendingPoolConfigurator: { - [ePolygonNetwork.mumbai]: '0xc3c37E2aA3dc66464fa3C29ce2a6EC85beFC45e1', - [ePolygonNetwork.matic]: '0x26db2B833021583566323E3b8985999981b9F1F3', + [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.matic]: '', }, ProviderRegistry: { [ePolygonNetwork.mumbai]: '0xE6ef11C967898F9525D550014FDEdCFAB63536B5', @@ -105,12 +105,12 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: '', }, WethGateway: { - [ePolygonNetwork.mumbai]: '0xee9eE614Ad26963bEc1Bec0D2c92879ae1F209fA', - [ePolygonNetwork.matic]: '0xbEadf48d62aCC944a06EEaE0A9054A90E5A7dc97', + [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.matic]: '', }, AaveOracle: { - [ePolygonNetwork.mumbai]: '0xC365C653f7229894F93994CD0b30947Ab69Ff1D5', - [ePolygonNetwork.matic]: '0x0229F777B0fAb107F9591a41d5F02E4e98dB6f2d', + [ePolygonNetwork.mumbai]: '', + [ePolygonNetwork.matic]: '', }, FallbackOracle: { [ePolygonNetwork.mumbai]: ZERO_ADDRESS, @@ -149,7 +149,7 @@ export const CommonsConfig: ICommonConfiguration = { [ePolygonNetwork.matic]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', }, WrappedNativeToken: { - [ePolygonNetwork.mumbai]: ZERO_ADDRESS, + [ePolygonNetwork.mumbai]: '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889', [ePolygonNetwork.matic]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', }, ReserveFactorTreasuryAddress: { From 4dea9b369ad76330c19d7417c37c56d6e17ada45 Mon Sep 17 00:00:00 2001 From: sendra Date: Mon, 4 Oct 2021 17:46:54 +0200 Subject: [PATCH 53/62] feat: fixed underlying symbol for avalanche --- contracts/misc/UiPoolDataProvider.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index e9f40fe5..7ba53f9f 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -109,7 +109,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); reserveData.name = ''; ( @@ -286,7 +286,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); reserveData.name = ''; ( From d33b3c55a1617e86b2c2725b5c670bdda275bfe7 Mon Sep 17 00:00:00 2001 From: sendra Date: Mon, 4 Oct 2021 18:54:01 +0200 Subject: [PATCH 54/62] fix: fixed incentive controller order --- contracts/misc/UiPoolDataProvider.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index e9f40fe5..0963e2aa 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -315,22 +315,22 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // incentives if (address(0) != address(incentivesController)) { ( - reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, + reserveData.aTokenIncentivesIndex, reserveData.aIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.aTokenAddress); ( - reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, + reserveData.sTokenIncentivesIndex, reserveData.sIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( - reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, + reserveData.vTokenIncentivesIndex, reserveData.vIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.variableDebtTokenAddress); From 52e03fcd4502c3669613c9ed148b1f263a06f050 Mon Sep 17 00:00:00 2001 From: kartojal Date: Mon, 4 Oct 2021 18:56:39 +0200 Subject: [PATCH 55/62] feat: add config for ui pool data provider deployment --- tasks/deployments/deploy-UiPoolDataProvider.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasks/deployments/deploy-UiPoolDataProvider.ts b/tasks/deployments/deploy-UiPoolDataProvider.ts index 37c82320..407818b6 100644 --- a/tasks/deployments/deploy-UiPoolDataProvider.ts +++ b/tasks/deployments/deploy-UiPoolDataProvider.ts @@ -41,6 +41,10 @@ task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider incentivesController: '0xa1EF206fb9a8D8186157FC817fCddcC47727ED55', aaveOracle: '0xD217DdD9f0Af84644dEFe84a0b634621D4617a29', }, + [eAvalancheNetwork.avalanche]: { + incentivesController: '0x01D83Fe6A10D2f2B7AF17034343746188272cAc9', + aaveOracle: '0xdC336Cd4769f4cC7E9d726DA53e6d3fC710cEB89', + }, }; const supportedNetworks = Object.keys(addressesByNetwork); From de1ab95318fe700b2414a5ed96199fd70e27febe Mon Sep 17 00:00:00 2001 From: sendra Date: Mon, 4 Oct 2021 19:06:56 +0200 Subject: [PATCH 56/62] fix: fixed order --- contracts/misc/UiPoolDataProvider.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 2a15dc44..f52d8ff5 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -109,7 +109,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); reserveData.name = ''; ( @@ -139,22 +139,22 @@ contract UiPoolDataProvider is IUiPoolDataProvider { if (address(0) != address(incentivesController)) { ( reserveData.aEmissionPerSecond, - reserveData.aIncentivesLastUpdateTimestamp, reserveData.aTokenIncentivesIndex + reserveData.aIncentivesLastUpdateTimestamp, // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.aTokenAddress); ( reserveData.sEmissionPerSecond, - reserveData.sIncentivesLastUpdateTimestamp, reserveData.sTokenIncentivesIndex + reserveData.sIncentivesLastUpdateTimestamp, // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( reserveData.vEmissionPerSecond, - reserveData.vIncentivesLastUpdateTimestamp, reserveData.vTokenIncentivesIndex + reserveData.vIncentivesLastUpdateTimestamp, // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } @@ -286,7 +286,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); reserveData.name = ''; ( From c49bac2d937011478f8483b50f8d6468c30e9c65 Mon Sep 17 00:00:00 2001 From: kartojal Date: Mon, 4 Oct 2021 19:11:10 +0200 Subject: [PATCH 57/62] fix: missing commas at UiPoolDataProvider.sol --- contracts/misc/UiPoolDataProvider.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index f52d8ff5..65291dfc 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -139,22 +139,22 @@ contract UiPoolDataProvider is IUiPoolDataProvider { if (address(0) != address(incentivesController)) { ( reserveData.aEmissionPerSecond, - reserveData.aTokenIncentivesIndex - reserveData.aIncentivesLastUpdateTimestamp, + reserveData.aTokenIncentivesIndex, + reserveData.aIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.aTokenAddress); ( reserveData.sEmissionPerSecond, - reserveData.sTokenIncentivesIndex - reserveData.sIncentivesLastUpdateTimestamp, + reserveData.sTokenIncentivesIndex, + reserveData.sIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( reserveData.vEmissionPerSecond, - reserveData.vTokenIncentivesIndex - reserveData.vIncentivesLastUpdateTimestamp, + reserveData.vTokenIncentivesIndex, + reserveData.vIncentivesLastUpdateTimestamp // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } From de2e710ecb079d563617e0451f127ab85c4d4256 Mon Sep 17 00:00:00 2001 From: sendra Date: Mon, 4 Oct 2021 19:11:19 +0200 Subject: [PATCH 58/62] feat: new getter --- contracts/misc/UiPoolDataProvider.sol | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index f52d8ff5..0a0071b6 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -138,25 +138,25 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // incentives if (address(0) != address(incentivesController)) { ( - reserveData.aEmissionPerSecond, reserveData.aTokenIncentivesIndex + reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp, - // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.aTokenAddress); + ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.aTokenAddress); ( + reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, - reserveData.sTokenIncentivesIndex reserveData.sIncentivesLastUpdateTimestamp, - // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.stableDebtTokenAddress); + ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( + reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, - reserveData.vTokenIncentivesIndex reserveData.vIncentivesLastUpdateTimestamp, - // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.variableDebtTokenAddress); + ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } } @@ -315,25 +315,25 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // incentives if (address(0) != address(incentivesController)) { ( - reserveData.aEmissionPerSecond, reserveData.aTokenIncentivesIndex, + reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp - // ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.aTokenAddress); + ) = incentivesController.getAssetData(reserveData.aTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.aTokenAddress); ( - reserveData.sEmissionPerSecond, reserveData.sTokenIncentivesIndex, + reserveData.sEmissionPerSecond, reserveData.sIncentivesLastUpdateTimestamp - // ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.stableDebtTokenAddress); + ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.stableDebtTokenAddress); ( - reserveData.vEmissionPerSecond, reserveData.vTokenIncentivesIndex, + reserveData.vEmissionPerSecond, reserveData.vIncentivesLastUpdateTimestamp - // ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix - ) = incentivesController.assets(reserveData.variableDebtTokenAddress); + ) = incentivesController.getAssetData(reserveData.variableDebtTokenAddress); TODO: temp fix + // ) = incentivesController.assets(reserveData.variableDebtTokenAddress); } if (user != address(0)) { From 41b300a94d615650ff16487c42c8d1d2ac46a610 Mon Sep 17 00:00:00 2001 From: kartojal Date: Tue, 5 Oct 2021 10:06:22 +0200 Subject: [PATCH 59/62] config: adjust gas price for Avalanche --- helper-hardhat-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index 9e949fd7..c66da367 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -68,7 +68,7 @@ export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork = { [ePolygonNetwork.mumbai]: 1 * GWEI, [ePolygonNetwork.matic]: 1 * GWEI, [eXDaiNetwork.xdai]: 1 * GWEI, - [eAvalancheNetwork.avalanche]: 85 * GWEI, + [eAvalancheNetwork.avalanche]: 225 * GWEI, [eAvalancheNetwork.fuji]: 85 * GWEI, }; From 59ed7391728b54877526db9b15979b0ace53e036 Mon Sep 17 00:00:00 2001 From: sendra Date: Tue, 5 Oct 2021 10:11:15 +0200 Subject: [PATCH 60/62] added underlying symbol --- contracts/misc/UiPoolDataProvider.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 051ab266..8c01f81c 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -109,7 +109,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); reserveData.name = ''; ( @@ -142,13 +142,13 @@ contract UiPoolDataProvider is IUiPoolDataProvider { reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.aTokenAddress); - + ( reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, reserveData.sIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); - + ( reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, @@ -283,7 +283,7 @@ contract UiPoolDataProvider is IUiPoolDataProvider { // reserve configuration // we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed - reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol(); + reserveData.symbol = IERC20Detailed(reserveData.underlyingAsset).symbol(); reserveData.name = ''; ( @@ -315,14 +315,14 @@ contract UiPoolDataProvider is IUiPoolDataProvider { reserveData.aTokenIncentivesIndex, reserveData.aEmissionPerSecond, reserveData.aIncentivesLastUpdateTimestamp - ) = incentivesController.getAssetData(reserveData.aTokenAddress); - + ) = incentivesController.getAssetData(reserveData.aTokenAddress); + ( reserveData.sTokenIncentivesIndex, reserveData.sEmissionPerSecond, reserveData.sIncentivesLastUpdateTimestamp ) = incentivesController.getAssetData(reserveData.stableDebtTokenAddress); - + ( reserveData.vTokenIncentivesIndex, reserveData.vEmissionPerSecond, From a129c65dd3ac6f57959d88d972621ef298e311b4 Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 6 Oct 2021 13:21:35 +0200 Subject: [PATCH 61/62] ci: remove kovan step due doesnt support tx type 2 --- .github/workflows/node.js.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 68a54d05..bc4f0e70 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -40,10 +40,6 @@ jobs: run: npm run amm:fork:main env: ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }} - - name: Aave deployment at Kovan fork - run: npm run aave:fork:kovan - env: - ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }} # - name: Coverage # run: npm run coverage # - uses: codecov/codecov-action@v1 From fa1f1349b77950cee672273227e6089872af7c16 Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 6 Oct 2021 14:29:26 +0200 Subject: [PATCH 62/62] fix: load the EmergencyAdmin before pausing the pool at 2_lending_pool.ts deployment script --- tasks/full/2_lending_pool.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tasks/full/2_lending_pool.ts b/tasks/full/2_lending_pool.ts index e67dcaed..fdc86e74 100644 --- a/tasks/full/2_lending_pool.ts +++ b/tasks/full/2_lending_pool.ts @@ -15,7 +15,12 @@ import { getLendingPoolConfiguratorProxy, } from '../../helpers/contracts-getters'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { loadPoolConfig, ConfigNames } from '../../helpers/configuration'; +import { + loadPoolConfig, + ConfigNames, + getGenesisPoolAdmin, + getEmergencyAdmin, +} from '../../helpers/configuration'; task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -70,9 +75,9 @@ task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') eContractid.LendingPoolConfigurator, lendingPoolConfiguratorProxy.address ); - + const admin = await DRE.ethers.getSigner(await getEmergencyAdmin(poolConfig)); // Pause market during deployment - await waitForTx(await lendingPoolConfiguratorProxy.setPoolPause(true)); + await waitForTx(await lendingPoolConfiguratorProxy.connect(admin).setPoolPause(true)); // Deploy deployment helpers await deployStableAndVariableTokensHelper(