From 9f6430fceba59694480d1d533d17fb2875b98c49 Mon Sep 17 00:00:00 2001 From: Pol Sendra Date: Wed, 25 Aug 2021 17:36:00 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Added=20new=20configuration=20to=20not?= =?UTF-8?q?=20use=20hardcoded=20addresses.=20WIP:=20ch=E2=80=A6=20(#224)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Added new configuration to not use hardcoded addresses. WIP: changes added only for staking service * feat: WIP: still missing somme services * feat: Refactor complete * fix: updated lendingpool config to be network -> market * fix: fix linter * fix: added network check before initializing services * fix: added check on synthetix * fix: wip: refactor config object * fix: refactored so we dont have any blockers on initializing * fix: removed unused type import * fix: add comment * fix: removed comments. Added arbitrum and avalanche networks * fix: added optional notation to configs * fix: moved faucet to inside lending pool per market config * fix: fixed validator for faucet method * fix: changed order of accessors to faucet config * fix: added some logs * fix: removed unnecessary log * fix: add log * fix: refactor take enum * fix: fixed repay validator Co-authored-by: sakulstra --- CONTRIBUTING.md | 1 + src/tx-builder/config/defaultConfig.ts | 125 +++++++++ src/tx-builder/config/index.ts | 107 +------- src/tx-builder/config/v2/addresses.ts | 141 ---------- src/tx-builder/interfaces/TxBuilder.ts | 15 +- src/tx-builder/services/Faucet.ts | 23 +- .../services/IncentivesController.ts | 20 +- src/tx-builder/services/LTAMigrator.ts | 24 +- .../services/LiquiditySwapAdapterParaswap.ts | 16 +- .../services/RepayWithCollateralAdapter.ts | 17 +- src/tx-builder/services/Staking.ts | 50 ++-- src/tx-builder/services/SynthetixService.ts | 18 +- src/tx-builder/services/WETHGateway.ts | 14 +- .../services/v2/AaveGovernanceV2.ts | 22 +- src/tx-builder/services/v2/LendingPool.ts | 73 +++--- src/tx-builder/txBuilder.ts | 53 ++-- src/tx-builder/types/index.ts | 69 ++++- src/tx-builder/v2.ts | 101 ++++++-- src/tx-builder/validators/methodValidators.ts | 243 ++++++++++++++---- tsconfig.json | 1 + 20 files changed, 672 insertions(+), 461 deletions(-) create mode 100644 src/tx-builder/config/defaultConfig.ts delete mode 100644 src/tx-builder/config/v2/addresses.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ae7d2426..be151585 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,7 @@ Once the branch is merged to master a npm release will be published automaticall ```bash # make sure you're on latest master before doing this +git fetch # fetch latest tags git checkout -b yarn release:prod git push origin diff --git a/src/tx-builder/config/defaultConfig.ts b/src/tx-builder/config/defaultConfig.ts new file mode 100644 index 00000000..53820b17 --- /dev/null +++ b/src/tx-builder/config/defaultConfig.ts @@ -0,0 +1,125 @@ +import { TxBuilderConfig } from '../types'; + +export const defaultConfig: TxBuilderConfig = { + governance: { + mainnet: { + AAVE_GOVERNANCE_V2: '0xEC568fffba86c094cf06b22134B23074DFE2252c', + AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: + '0x61910EcD7e8e942136CE7Fe7943f956cea1CC2f7', + AAVE_GOVERNANCE_V2_EXECUTOR_LONG: + '0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', + AAVE_GOVERNANCE_V2_HELPER: '0x16ff7583ea21055bf5f929ec4b896d997ff35847', + }, + kovan: { + AAVE_GOVERNANCE_V2: '0xc2eBaB3Bac8f2f5028f5C7317027A41EBFCa31D2', + AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: + '0x462eD5dc919BE6C96639D5f31ab919EBA8F31831', + AAVE_GOVERNANCE_V2_EXECUTOR_LONG: + '0x7e5195b0A6a60b371Ba3276032CF6958eADFA652', + AAVE_GOVERNANCE_V2_HELPER: '0xffd5BEb5712952FC9a9DDC7499487422B29Fdda6', + }, + }, + lendingPool: { + mainnet: { + proto: { + LENDING_POOL: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9', + WETH_GATEWAY: '0xcc9a0B7c43DC2a5F023Bb9b738E45B0Ef6B06E04', + FLASH_LIQUIDATION_ADAPTER: '0xE377fB98512D7b04827e56BC84e1838804a8019D', + REPAY_WITH_COLLATERAL_ADAPTER: + '0x498c5431eb517101582988fbb36431ddaac8f4b1', + SWAP_COLLATERAL_ADAPTER: '0x135896DE8421be2ec868E0b811006171D9df802A', + }, + amm: { + LENDING_POOL: '0x7937d4799803fbbe595ed57278bc4ca21f3bffcb', + WETH_GATEWAY: '0xcc9a0B7c43DC2a5F023Bb9b738E45B0Ef6B06E04', + FLASH_LIQUIDATION_ADAPTER: '0xE377fB98512D7b04827e56BC84e1838804a8019D', + REPAY_WITH_COLLATERAL_ADAPTER: + '0x498c5431eb517101582988fbb36431ddaac8f4b1', + SWAP_COLLATERAL_ADAPTER: '0x135896DE8421be2ec868E0b811006171D9df802A', + }, + }, + kovan: { + proto: { + LENDING_POOL: '0xE0fBa4Fc209b4948668006B2bE61711b7f465bAe', + WETH_GATEWAY: '0xA61ca04DF33B72b235a8A28CfB535bb7A5271B70', + FLASH_LIQUIDATION_ADAPTER: '0x9D50F0b23b1805773f607F0B4678d724322B7AC2', + REPAY_WITH_COLLATERAL_ADAPTER: + '0xf86Be05f535EC2d217E4c6116B3fa147ee5C05A1', + SWAP_COLLATERAL_ADAPTER: '0xC18451d36aA370fDACe8d45839bF975F48f7AEa1', + FAUCET: '0x600103d518cC5E8f3319D532eB4e5C268D32e604', + }, + amm: { + LENDING_POOL: '0x762E2a3BBe729240ea44D31D5a81EAB44d34ef01', + WETH_GATEWAY: '0xA61ca04DF33B72b235a8A28CfB535bb7A5271B70', + FLASH_LIQUIDATION_ADAPTER: '0x9D50F0b23b1805773f607F0B4678d724322B7AC2', + REPAY_WITH_COLLATERAL_ADAPTER: + '0xf86Be05f535EC2d217E4c6116B3fa147ee5C05A1', + SWAP_COLLATERAL_ADAPTER: '0xC18451d36aA370fDACe8d45839bF975F48f7AEa1', + FAUCET: '0x600103d518cC5E8f3319D532eB4e5C268D32e604', + }, + }, + polygon: { + proto: { + LENDING_POOL: '0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf', + WETH_GATEWAY: '0xbEadf48d62aCC944a06EEaE0A9054A90E5A7dc97', + SWAP_COLLATERAL_ADAPTER: '0x35784a624D4FfBC3594f4d16fA3801FeF063241c', + }, + }, + mumbai: { + proto: { + LENDING_POOL: '0x9198F13B08E299d85E096929fA9781A1E3d5d827', + WETH_GATEWAY: '0xee9eE614Ad26963bEc1Bec0D2c92879ae1F209fA', + FAUCET: '0x0b3C23243106A69449e79C14c58BB49E358f9B10', + }, + }, + }, + staking: { + mainnet: { + aave: { + TOKEN_STAKING: '0x4da27a545c0c5b758a6ba100e3a049001de870f5', + STAKING_REWARD_TOKEN: '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + STAKING_HELPER: '0xce0424653fb2fd48ed1b621bdbd60db16b2e388a', + }, + balancer: { + TOKEN_STAKING: '0xa1116930326D21fB917d5A27F1E9943A9595fb47', + STAKING_REWARD_TOKEN: '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + }, + }, + kovan: { + aave: { + TOKEN_STAKING: '0xf2fbf9A6710AfDa1c4AaB2E922DE9D69E0C97fd2', + STAKING_REWARD_TOKEN: '0xb597cd8d3217ea6477232f9217fa70837ff667af', + STAKING_HELPER: '0xf267aCc8BF1D8b41c89b6dc1a0aD8439dfbc890c', + }, + balancer: { + TOKEN_STAKING: '0x31ce45Ab6E26C72c47C52c27498D460099545ef2', + STAKING_REWARD_TOKEN: '0xb597cd8d3217ea6477232f9217fa70837ff667af', + }, + }, + }, + incentives: { + mainnet: { + INCENTIVES_CONTROLLER: '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5', + INCENTIVES_CONTROLLER_REWARD_TOKEN: + '0x4da27a545c0c5b758a6ba100e3a049001de870f5', + }, + polygon: { + INCENTIVES_CONTROLLER: '0x357d51124f59836ded84c8a1730d72b749d8bc23', + INCENTIVES_CONTROLLER_REWARD_TOKEN: + '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + }, + mumbai: { + INCENTIVES_CONTROLLER: '0xd41aE58e803Edf4304334acCE4DC4Ec34a63C644', + INCENTIVES_CONTROLLER_REWARD_TOKEN: + '0x9c3c9283d3e44854697cd22d3faa240cfb032889', + }, + }, + migrator: { + mainnet: { + LEND_TO_AAVE_MIGRATOR: '0x317625234562b1526ea2fac4030ea499c5291de4', + }, + kovan: { + LEND_TO_AAVE_MIGRATOR: '0x8cC8965FEf45a448bdbe3C749683b280eF2E17Ea', + }, + }, +}; diff --git a/src/tx-builder/config/index.ts b/src/tx-builder/config/index.ts index 3d192bfc..97ba426b 100644 --- a/src/tx-builder/config/index.ts +++ b/src/tx-builder/config/index.ts @@ -1,12 +1,9 @@ import { BigNumber, constants } from 'ethers'; import { - EnabledNetworksType, + ConstantAddressesByNetwork, GasRecommendationType, - Market, Network, ProtocolAction, - Stake, - StakingConfigType, } from '../types'; export const DEFAULT_NULL_VALUE_ON_TX = BigNumber.from(0).toHexString(); @@ -63,104 +60,8 @@ export const gasLimitRecommendations: GasRecommendationType = { }, }; -export const distinctStakingAddressesBetweenTokens: StakingConfigType = { - [Stake.Aave]: { - [Network.kovan]: { - canUsePermit: true, - TOKEN_STAKING_ADDRESS: '0xf2fbf9A6710AfDa1c4AaB2E922DE9D69E0C97fd2', - STAKING_REWARD_TOKEN_ADDRESS: - '0xb597cd8d3217ea6477232f9217fa70837ff667af', - STAKING_HELPER_ADDRESS: '0xf267aCc8BF1D8b41c89b6dc1a0aD8439dfbc890c', - }, - [Network.ropsten]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, - [Network.mainnet]: { - canUsePermit: true, - TOKEN_STAKING_ADDRESS: '0x4da27a545c0c5b758a6ba100e3a049001de870f5', - STAKING_REWARD_TOKEN_ADDRESS: - '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', - STAKING_HELPER_ADDRESS: '0xce0424653fb2fd48ed1b621bdbd60db16b2e388a', - }, - [Network.polygon]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, - [Network.mumbai]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, +export const cosntantAddressesByNetwork: ConstantAddressesByNetwork = { + [Network.mainnet]: { + SYNTHETIX_PROXY_ADDRESS: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', }, - [Stake.Balancer]: { - [Network.kovan]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '0x31ce45Ab6E26C72c47C52c27498D460099545ef2', - STAKING_REWARD_TOKEN_ADDRESS: - '0xb597cd8d3217ea6477232f9217fa70837ff667af', - STAKING_HELPER_ADDRESS: '', - }, - [Network.ropsten]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, - [Network.mainnet]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '0xa1116930326D21fB917d5A27F1E9943A9595fb47', - STAKING_REWARD_TOKEN_ADDRESS: - '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', - STAKING_HELPER_ADDRESS: '', - }, - [Network.polygon]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, - [Network.mumbai]: { - canUsePermit: false, - TOKEN_STAKING_ADDRESS: '', - STAKING_REWARD_TOKEN_ADDRESS: '', - STAKING_HELPER_ADDRESS: '', - }, - }, -}; - -export const enabledNetworksByService: EnabledNetworksType = { - staking: { - [Stake.Balancer]: [Network.kovan, Network.mainnet], - [Stake.Aave]: [Network.kovan, Network.mainnet], - }, - lendingPool: { - [Market.Proto]: [ - Network.kovan, - Network.mainnet, - Network.polygon, - Network.mumbai, - ], - [Market.AMM]: [Network.kovan, Network.mainnet], - }, - governance: [Network.kovan, Network.mainnet], - wethGateway: [ - Network.kovan, - Network.mainnet, - Network.polygon, - Network.mumbai, - ], - faucet: [Network.kovan, Network.mumbai], - liquiditySwapAdapter: [Network.mainnet, Network.polygon], - repayWithCollateralAdapter: [Network.kovan, Network.mainnet], - aaveGovernanceV2: [Network.kovan, Network.mainnet], - ltaMigrator: [Network.kovan, Network.mainnet], - incentivesController: [Network.polygon, Network.mumbai, Network.mainnet], }; - -export * from './v2/addresses'; diff --git a/src/tx-builder/config/v2/addresses.ts b/src/tx-builder/config/v2/addresses.ts deleted file mode 100644 index 172b2350..00000000 --- a/src/tx-builder/config/v2/addresses.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - CommonConfigType, - GovernanceConfigType, - LendingPoolConfigType, - Market, - Network, -} from '../../types'; - -export const commonContractAddressBetweenMarketsV2: CommonConfigType = { - [Network.kovan]: { - SYNTHETIX_PROXY_ADDRESS: '', - GOVERNANCE_PROTO_CONTRACT: '0x8134929c3dcb1b8b82f27f53424b959fb82182f2', - LEND_TO_AAVE_MIGRATOR: '0x8cC8965FEf45a448bdbe3C749683b280eF2E17Ea', - WETH_GATEWAY: '0xA61ca04DF33B72b235a8A28CfB535bb7A5271B70', - FAUCET: '0x600103d518cC5E8f3319D532eB4e5C268D32e604', - SWAP_COLLATERAL_ADAPTER: '0xC18451d36aA370fDACe8d45839bF975F48f7AEa1', - REPAY_WITH_COLLATERAL_ADAPTER: '0xf86Be05f535EC2d217E4c6116B3fa147ee5C05A1', - FLASHLIQUIDATION: '0x9D50F0b23b1805773f607F0B4678d724322B7AC2', - INCENTIVES_CONTROLLER: '', - INCENTIVES_CONTROLLER_REWARD_TOKEN: '', - }, - [Network.ropsten]: { - SYNTHETIX_PROXY_ADDRESS: '', - GOVERNANCE_PROTO_CONTRACT: '', - LEND_TO_AAVE_MIGRATOR: '', - WETH_GATEWAY: '', - FAUCET: '0xcCB8f5183065AF6C40d3A13ae669FB8F92A11C05', - SWAP_COLLATERAL_ADAPTER: '', - REPAY_WITH_COLLATERAL_ADAPTER: '', - FLASHLIQUIDATION: '', - INCENTIVES_CONTROLLER: '', - INCENTIVES_CONTROLLER_REWARD_TOKEN: '', - }, - [Network.mainnet]: { - SYNTHETIX_PROXY_ADDRESS: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', - GOVERNANCE_PROTO_CONTRACT: '0x8a2efd9a790199f4c94c6effe210fce0b4724f52', - LEND_TO_AAVE_MIGRATOR: '0x317625234562b1526ea2fac4030ea499c5291de4', - WETH_GATEWAY: '0xcc9a0B7c43DC2a5F023Bb9b738E45B0Ef6B06E04', - FAUCET: '', - SWAP_COLLATERAL_ADAPTER: '0x135896DE8421be2ec868E0b811006171D9df802A', - REPAY_WITH_COLLATERAL_ADAPTER: '0x498c5431eb517101582988fbb36431ddaac8f4b1', - FLASHLIQUIDATION: '0xE377fB98512D7b04827e56BC84e1838804a8019D', - INCENTIVES_CONTROLLER: '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5', - INCENTIVES_CONTROLLER_REWARD_TOKEN: - '0x4da27a545c0c5b758a6ba100e3a049001de870f5', - }, - [Network.polygon]: { - SYNTHETIX_PROXY_ADDRESS: '', - GOVERNANCE_PROTO_CONTRACT: '', - LEND_TO_AAVE_MIGRATOR: '', - WETH_GATEWAY: '0xbEadf48d62aCC944a06EEaE0A9054A90E5A7dc97', - FAUCET: '', - SWAP_COLLATERAL_ADAPTER: '0x35784a624D4FfBC3594f4d16fA3801FeF063241c', - REPAY_WITH_COLLATERAL_ADAPTER: '', - FLASHLIQUIDATION: '', - INCENTIVES_CONTROLLER: '0x357d51124f59836ded84c8a1730d72b749d8bc23', - INCENTIVES_CONTROLLER_REWARD_TOKEN: - '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - }, - [Network.mumbai]: { - SYNTHETIX_PROXY_ADDRESS: '', - GOVERNANCE_PROTO_CONTRACT: '', - LEND_TO_AAVE_MIGRATOR: '', - WETH_GATEWAY: '0xee9eE614Ad26963bEc1Bec0D2c92879ae1F209fA', - FAUCET: '0x0b3C23243106A69449e79C14c58BB49E358f9B10', - SWAP_COLLATERAL_ADAPTER: '', - REPAY_WITH_COLLATERAL_ADAPTER: '', - FLASHLIQUIDATION: '', - INCENTIVES_CONTROLLER: '0xd41aE58e803Edf4304334acCE4DC4Ec34a63C644', - INCENTIVES_CONTROLLER_REWARD_TOKEN: - '0x9c3c9283d3e44854697cd22d3faa240cfb032889', - }, -}; - -export const distinctContractAddressBetweenMarketsV2: LendingPoolConfigType = { - [Market.Proto]: { - [Network.kovan]: { - LENDINGPOOL_ADDRESS: '0xE0fBa4Fc209b4948668006B2bE61711b7f465bAe', - }, - [Network.ropsten]: { - LENDINGPOOL_ADDRESS: '', - }, - [Network.mainnet]: { - LENDINGPOOL_ADDRESS: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9', - }, - [Network.polygon]: { - LENDINGPOOL_ADDRESS: '0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf', - }, - [Network.mumbai]: { - LENDINGPOOL_ADDRESS: '0x9198F13B08E299d85E096929fA9781A1E3d5d827', - }, - }, - [Market.AMM]: { - [Network.kovan]: { - LENDINGPOOL_ADDRESS: '0x762E2a3BBe729240ea44D31D5a81EAB44d34ef01', - }, - [Network.ropsten]: { - LENDINGPOOL_ADDRESS: '', - }, - [Network.mainnet]: { - LENDINGPOOL_ADDRESS: '0x7937d4799803fbbe595ed57278bc4ca21f3bffcb', - }, - }, -}; - -export const aaveGovernanceV2Addresses: GovernanceConfigType = { - [Network.kovan]: { - AAVE_GOVERNANCE_V2: '0xc2eBaB3Bac8f2f5028f5C7317027A41EBFCa31D2', - AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: - '0x462eD5dc919BE6C96639D5f31ab919EBA8F31831', // executor for testing - AAVE_GOVERNANCE_V2_EXECUTOR_LONG: - '0x7e5195b0A6a60b371Ba3276032CF6958eADFA652', - AAVE_GOVERNANCE_V2_HELPER: '0xffd5BEb5712952FC9a9DDC7499487422B29Fdda6', - }, - [Network.ropsten]: { - AAVE_GOVERNANCE_V2: '', - AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: '', - AAVE_GOVERNANCE_V2_EXECUTOR_LONG: '', - AAVE_GOVERNANCE_V2_HELPER: '', - }, - [Network.mainnet]: { - AAVE_GOVERNANCE_V2: '0xEC568fffba86c094cf06b22134B23074DFE2252c', - AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: - '0x61910EcD7e8e942136CE7Fe7943f956cea1CC2f7', - AAVE_GOVERNANCE_V2_EXECUTOR_LONG: - '0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', - AAVE_GOVERNANCE_V2_HELPER: '0x16ff7583ea21055bf5f929ec4b896d997ff35847', - }, - [Network.polygon]: { - AAVE_GOVERNANCE_V2: '', - AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: '', - AAVE_GOVERNANCE_V2_EXECUTOR_LONG: '', - AAVE_GOVERNANCE_V2_HELPER: '', - }, - [Network.mumbai]: { - AAVE_GOVERNANCE_V2: '', - AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: '', - AAVE_GOVERNANCE_V2_EXECUTOR_LONG: '', - AAVE_GOVERNANCE_V2_HELPER: '', - }, -}; diff --git a/src/tx-builder/interfaces/TxBuilder.ts b/src/tx-builder/interfaces/TxBuilder.ts index 37e2fa3e..35110e0c 100644 --- a/src/tx-builder/interfaces/TxBuilder.ts +++ b/src/tx-builder/interfaces/TxBuilder.ts @@ -1,4 +1,3 @@ -import { Market, Stake } from '../types'; import IERC20ServiceInterface from './ERC20'; import LendingPoolInterfaceV2 from './v2/LendingPool'; import SynthetixInterface from './Synthetix'; @@ -9,16 +8,22 @@ import FaucetInterface from './Faucet'; import AaveGovernanceV2Interface from './v2/AaveGovernanceV2'; import GovernanceDelegationTokenInterface from './v2/GovernanceDelegationToken'; import { IncentivesControllerInterface } from '../services/IncentivesController'; +import RepayWithCollateralAdapterInterface from './RepayWithCollateralAdapter'; +import LiquiditySwapAdapterInterface from './LiquiditySwapAdapterParaswap'; export default interface TxBuilderInterface { erc20Service: IERC20ServiceInterface; synthetixService: SynthetixInterface; ltaMigratorService: LTAMigratorInterface; - wethGatewayService: WETHGatewayInterface; - faucetService: FaucetInterface; incentiveService: IncentivesControllerInterface; aaveGovernanceV2Service: AaveGovernanceV2Interface; governanceDelegationTokenService: GovernanceDelegationTokenInterface; - getLendingPool: (market: Market) => LendingPoolInterfaceV2; - getStaking: (stake: Stake) => StakingInterface; + getLendingPool: (market: string) => LendingPoolInterfaceV2; + getStaking: (stake: string) => StakingInterface; + getWethGateway: (market: string) => WETHGatewayInterface; + getRepayWithCollateralAdapter: ( + market: string + ) => RepayWithCollateralAdapterInterface; + getSwapCollateralAdapter: (market: string) => LiquiditySwapAdapterInterface; + getFaucet: (market: string) => FaucetInterface; } diff --git a/src/tx-builder/services/Faucet.ts b/src/tx-builder/services/Faucet.ts index 7705e182..020369b9 100644 --- a/src/tx-builder/services/Faucet.ts +++ b/src/tx-builder/services/Faucet.ts @@ -1,8 +1,4 @@ -import { - commonContractAddressBetweenMarketsV2, - DEFAULT_NULL_VALUE_ON_TX, - enabledNetworksByService, -} from '../config'; +import { DEFAULT_NULL_VALUE_ON_TX } from '../config'; import { IFaucet, IMinter, @@ -14,6 +10,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, + LendingPoolMarketConfig, transactionType, } from '../types'; import { FaucetParamsType } from '../types/FaucetMethodTypes'; @@ -29,15 +26,21 @@ export default class FaucetService readonly faucetContract: IFaucet; - constructor(config: Configuration) { + readonly faucetConfig: LendingPoolMarketConfig | undefined; + + constructor( + config: Configuration, + faucetConfig: LendingPoolMarketConfig | undefined + ) { super(config, IMinter__factory); - const { provider, network } = this.config; + this.faucetConfig = faucetConfig; + + const { provider } = this.config; - const { FAUCET } = commonContractAddressBetweenMarketsV2[network]; - this.faucetAddress = FAUCET; + this.faucetAddress = this.faucetConfig?.FAUCET || ''; - if (enabledNetworksByService.faucet.indexOf(network) > -1) { + if (this.faucetAddress !== '') { this.faucetContract = IFaucet__factory.connect( this.faucetAddress, provider diff --git a/src/tx-builder/services/IncentivesController.ts b/src/tx-builder/services/IncentivesController.ts index f3bedeb1..326759fe 100644 --- a/src/tx-builder/services/IncentivesController.ts +++ b/src/tx-builder/services/IncentivesController.ts @@ -1,5 +1,4 @@ import { constants } from 'ethers'; -import { commonContractAddressBetweenMarketsV2 } from '../config'; import { IAaveIncentivesController, IAaveIncentivesController__factory, @@ -8,6 +7,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, + IncentivesConfig, tEthereumAddress, transactionType, } from '../types'; @@ -34,13 +34,21 @@ export default class IncentivesController public readonly incentivesControllerRewardTokenAddress: tEthereumAddress; readonly incentivesControllerAddress: string; - constructor(config: Configuration) { + readonly incentivesConfig: IncentivesConfig | undefined; + + constructor( + config: Configuration, + incentivesConfig: IncentivesConfig | undefined + ) { super(config, IAaveIncentivesController__factory); - const { network } = this.config; - const addresses = commonContractAddressBetweenMarketsV2[network]; - this.incentivesControllerAddress = addresses.INCENTIVES_CONTROLLER; + this.incentivesConfig = incentivesConfig; + + const { INCENTIVES_CONTROLLER, INCENTIVES_CONTROLLER_REWARD_TOKEN } = + this.incentivesConfig || {}; + + this.incentivesControllerAddress = INCENTIVES_CONTROLLER || ''; this.incentivesControllerRewardTokenAddress = - addresses.INCENTIVES_CONTROLLER_REWARD_TOKEN; + INCENTIVES_CONTROLLER_REWARD_TOKEN || ''; } @IncentivesValidator diff --git a/src/tx-builder/services/LTAMigrator.ts b/src/tx-builder/services/LTAMigrator.ts index 5a4f40cd..094aa916 100644 --- a/src/tx-builder/services/LTAMigrator.ts +++ b/src/tx-builder/services/LTAMigrator.ts @@ -1,8 +1,5 @@ import IERC20ServiceInterface from '../interfaces/ERC20'; -import { - commonContractAddressBetweenMarketsV2, - DEFAULT_APPROVE_AMOUNT, -} from '../config'; +import { DEFAULT_APPROVE_AMOUNT } from '../config'; import { ILendToAaveMigrator, ILendToAaveMigrator__factory, @@ -12,7 +9,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, - Network, + MigratorConfig, tEthereumAddress, transactionType, tStringCurrencyUnits, @@ -29,13 +26,18 @@ export default class LTAMigratorService readonly migratorAddress: string; - constructor(config: Configuration, erc20Service: IERC20ServiceInterface) { + readonly migratorConfig: MigratorConfig | undefined; + + constructor( + config: Configuration, + erc20Service: IERC20ServiceInterface, + migratorConfig: MigratorConfig | undefined + ) { super(config, ILendToAaveMigrator__factory); this.erc20Service = erc20Service; - const { network }: Configuration = this.config; + this.migratorConfig = migratorConfig; - this.migratorAddress = - commonContractAddressBetweenMarketsV2[network].LEND_TO_AAVE_MIGRATOR; + this.migratorAddress = this.migratorConfig?.LEND_TO_AAVE_MIGRATOR || ''; } @LTAMigratorValidator @@ -44,10 +46,6 @@ export default class LTAMigratorService @IsPositiveAmount() amount: tStringCurrencyUnits ): Promise { const txs: EthereumTransactionTypeExtended[] = []; - // TODO: delete conditional when mainnet address - if (this.config.network === Network.ropsten) { - return txs; - } const { isApproved, approve, decimalsOf } = this.erc20Service; diff --git a/src/tx-builder/services/LiquiditySwapAdapterParaswap.ts b/src/tx-builder/services/LiquiditySwapAdapterParaswap.ts index 9c39021d..9284fb10 100644 --- a/src/tx-builder/services/LiquiditySwapAdapterParaswap.ts +++ b/src/tx-builder/services/LiquiditySwapAdapterParaswap.ts @@ -1,4 +1,3 @@ -import { commonContractAddressBetweenMarketsV2 } from '../config'; import { IParaSwapLiquiditySwapAdapter__factory, IParaSwapLiquiditySwapAdapter, @@ -8,6 +7,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, + LendingPoolMarketConfig, transactionType, } from '../types'; import { SwapAndDepositMethodType } from '../types/LiquiditySwapAdapterParaswapMethodTypes'; @@ -37,13 +37,17 @@ export default class LiquiditySwapAdapterService implements LiquiditySwapAdapterInterface { readonly liquiditySwapAdapterAddress: string; - constructor(config: Configuration) { + readonly swapCollateralConfig: LendingPoolMarketConfig | undefined; + + constructor( + config: Configuration, + swapCollateralConfig: LendingPoolMarketConfig | undefined + ) { super(config, IParaSwapLiquiditySwapAdapter__factory); + this.swapCollateralConfig = swapCollateralConfig; - const { SWAP_COLLATERAL_ADAPTER } = commonContractAddressBetweenMarketsV2[ - this.config.network - ]; - this.liquiditySwapAdapterAddress = SWAP_COLLATERAL_ADAPTER; + this.liquiditySwapAdapterAddress = + this.swapCollateralConfig?.SWAP_COLLATERAL_ADAPTER || ''; } @LiquiditySwapValidator diff --git a/src/tx-builder/services/RepayWithCollateralAdapter.ts b/src/tx-builder/services/RepayWithCollateralAdapter.ts index e0fb2ad2..c34f486a 100644 --- a/src/tx-builder/services/RepayWithCollateralAdapter.ts +++ b/src/tx-builder/services/RepayWithCollateralAdapter.ts @@ -1,4 +1,3 @@ -import { commonContractAddressBetweenMarketsV2 } from '../config'; import { IRepayWithCollateral, IRepayWithCollateral__factory, @@ -8,6 +7,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, + LendingPoolMarketConfig, transactionType, } from '../types'; import { RepayWithCollateralType } from '../types/RepayWithCollateralMethodTypes'; @@ -20,14 +20,17 @@ export default class RepayWithCollateralAdapterService implements RepayWithCollateralAdapterInterface { readonly repayWithCollateralAddress: string; - constructor(config: Configuration) { - super(config, IRepayWithCollateral__factory); + readonly repayWithCollateralConfig: LendingPoolMarketConfig | undefined; - const { - REPAY_WITH_COLLATERAL_ADAPTER, - } = commonContractAddressBetweenMarketsV2[this.config.network]; + constructor( + config: Configuration, + repayWithCollateralConfig: LendingPoolMarketConfig | undefined + ) { + super(config, IRepayWithCollateral__factory); + this.repayWithCollateralConfig = repayWithCollateralConfig; - this.repayWithCollateralAddress = REPAY_WITH_COLLATERAL_ADAPTER; + this.repayWithCollateralAddress = + this.repayWithCollateralConfig?.REPAY_WITH_COLLATERAL_ADAPTER || ''; } @RepayWithCollateralValidator diff --git a/src/tx-builder/services/Staking.ts b/src/tx-builder/services/Staking.ts index 32ff176d..212f988a 100644 --- a/src/tx-builder/services/Staking.ts +++ b/src/tx-builder/services/Staking.ts @@ -1,10 +1,6 @@ import { constants, utils, Signature } from 'ethers'; import IERC20ServiceInterface from '../interfaces/ERC20'; -import { - DEFAULT_APPROVE_AMOUNT, - distinctStakingAddressesBetweenTokens, - MAX_UINT_AMOUNT, -} from '../config'; +import { DEFAULT_APPROVE_AMOUNT, MAX_UINT_AMOUNT } from '../config'; import { IStakedToken, IAaveStakingHelper, @@ -17,14 +13,17 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, - Stake, + StakingNetworkConfig, tEthereumAddress, transactionType, tStringCurrencyUnits, tStringDecimalUnits, } from '../types'; import { parseNumber } from '../utils/parsings'; -import { StakingValidator } from '../validators/methodValidators'; +import { + SignStakingValidator, + StakingValidator, +} from '../validators/methodValidators'; import { IsEthAddress, IsPositiveAmount, @@ -42,52 +41,49 @@ export default class StakingService public readonly stakingRewardTokenContractAddress: tEthereumAddress; - readonly stakingHelperContractAddress: string; + readonly stakingHelperContractAddress: tEthereumAddress | undefined; readonly erc20Service: IERC20ServiceInterface; - readonly tokenStake: Stake; + readonly tokenStake: string; - readonly canUsePermit: boolean; + readonly stakingConfig: StakingNetworkConfig | undefined; constructor( config: Configuration, erc20Service: IERC20ServiceInterface, - tokenStake: Stake + tokenStake: string, + stakingConfig: StakingNetworkConfig | undefined ) { super(config, IStakedToken__factory); + this.stakingConfig = stakingConfig; this.tokenStake = tokenStake; this.erc20Service = erc20Service; - const { provider, network } = this.config; + const { provider } = this.config; - const { - TOKEN_STAKING_ADDRESS, - STAKING_REWARD_TOKEN_ADDRESS, - STAKING_HELPER_ADDRESS, - canUsePermit, - } = distinctStakingAddressesBetweenTokens[this.tokenStake][network]; + const { TOKEN_STAKING, STAKING_REWARD_TOKEN, STAKING_HELPER } = + this.stakingConfig || {}; - this.stakingContractAddress = TOKEN_STAKING_ADDRESS; - this.stakingRewardTokenContractAddress = STAKING_REWARD_TOKEN_ADDRESS; - this.stakingHelperContractAddress = STAKING_HELPER_ADDRESS; - this.canUsePermit = canUsePermit; + this.stakingContractAddress = TOKEN_STAKING || ''; + this.stakingRewardTokenContractAddress = STAKING_REWARD_TOKEN || ''; + this.stakingHelperContractAddress = STAKING_HELPER; - if (this.canUsePermit) { + if (this.stakingHelperContractAddress) { this.stakingHelperContract = IAaveStakingHelper__factory.connect( - STAKING_HELPER_ADDRESS, + this.stakingHelperContractAddress, provider ); } } - @StakingValidator + @SignStakingValidator public async signStaking( @IsEthAddress() user: tEthereumAddress, @IsPositiveAmount() amount: tStringCurrencyUnits, nonce: string ): Promise { - if (!this.canUsePermit) return ''; + if (!this.stakingHelperContractAddress) return ''; const { getTokenData } = this.erc20Service; const stakingContract: IStakedToken = this.getContractInstance( @@ -138,7 +134,7 @@ export default class StakingService @IsPositiveAmount() amount: tStringCurrencyUnits, signature: string ): Promise { - if (!this.canUsePermit) return []; + if (!this.stakingHelperContractAddress) return []; const txs: EthereumTransactionTypeExtended[] = []; const { decimalsOf } = this.erc20Service; diff --git a/src/tx-builder/services/SynthetixService.ts b/src/tx-builder/services/SynthetixService.ts index 62d0a185..35be9bc6 100644 --- a/src/tx-builder/services/SynthetixService.ts +++ b/src/tx-builder/services/SynthetixService.ts @@ -3,13 +3,18 @@ import BaseService from './BaseService'; import { Configuration, tStringDecimalUnits } from '../types'; import { ISynthetix, ISynthetix__factory } from '../contract-types'; import SynthetixInterface from '../interfaces/Synthetix'; -import { commonContractAddressBetweenMarketsV2 } from '../config'; +import { cosntantAddressesByNetwork } from '../config'; export default class SynthetixService extends BaseService implements SynthetixInterface { + readonly synthAddress: string; constructor(config: Configuration) { super(config, ISynthetix__factory); + const { network } = this.config; + + this.synthAddress = + cosntantAddressesByNetwork[network]?.SYNTHETIX_PROXY_ADDRESS || ''; } public synthetixValidation = async ( @@ -17,11 +22,7 @@ export default class SynthetixService reserve: string, amount: tStringDecimalUnits ): Promise => { - const synthAddress = - commonContractAddressBetweenMarketsV2[this.config.network] - .SYNTHETIX_PROXY_ADDRESS; - - if (reserve.toUpperCase() === synthAddress.toUpperCase()) { + if (reserve.toUpperCase() === this.synthAddress.toUpperCase()) { return this.isSnxTransferable(userAddress, amount); } return true; @@ -31,10 +32,7 @@ export default class SynthetixService userAddress: string, amount: tStringDecimalUnits ): Promise => { - const synthContract = this.getContractInstance( - commonContractAddressBetweenMarketsV2[this.config.network] - .SYNTHETIX_PROXY_ADDRESS - ); + const synthContract = this.getContractInstance(this.synthAddress); const transferableAmount: BigNumber = await synthContract.transferableSynthetix( userAddress diff --git a/src/tx-builder/services/WETHGateway.ts b/src/tx-builder/services/WETHGateway.ts index 05e5aa62..8a8cc850 100644 --- a/src/tx-builder/services/WETHGateway.ts +++ b/src/tx-builder/services/WETHGateway.ts @@ -1,5 +1,4 @@ import { constants } from 'ethers'; -import { commonContractAddressBetweenMarketsV2 } from '../config'; import { IWETHGateway, IWETHGateway__factory } from '../contract-types'; import BaseDebtTokenInterface from '../interfaces/BaseDebtToken'; import IERC20ServiceInterface from '../interfaces/ERC20'; @@ -9,6 +8,7 @@ import { eEthereumTxType, EthereumTransactionTypeExtended, InterestRate, + LendingPoolMarketConfig, ProtocolAction, transactionType, tStringDecimalUnits, @@ -39,20 +39,20 @@ export default class WETHGatewayService readonly erc20Service: IERC20ServiceInterface; + readonly wethGatewayConfig: LendingPoolMarketConfig | undefined; + constructor( config: Configuration, baseDebtTokenService: BaseDebtTokenInterface, - erc20Service: IERC20ServiceInterface + erc20Service: IERC20ServiceInterface, + wethGatewayConfig: LendingPoolMarketConfig | undefined ) { super(config, IWETHGateway__factory); - this.config = config; + this.wethGatewayConfig = wethGatewayConfig; this.baseDebtTokenService = baseDebtTokenService; this.erc20Service = erc20Service; - const { network } = this.config; - const { WETH_GATEWAY } = commonContractAddressBetweenMarketsV2[network]; - - this.wethGatewayAddress = WETH_GATEWAY; + this.wethGatewayAddress = this.wethGatewayConfig?.WETH_GATEWAY || ''; } @WETHValidator diff --git a/src/tx-builder/services/v2/AaveGovernanceV2.ts b/src/tx-builder/services/v2/AaveGovernanceV2.ts index 3c1c75c9..4070714a 100644 --- a/src/tx-builder/services/v2/AaveGovernanceV2.ts +++ b/src/tx-builder/services/v2/AaveGovernanceV2.ts @@ -1,6 +1,5 @@ import { Signature, utils } from 'ethers'; import { formatEther } from 'ethers/lib/utils'; -import { aaveGovernanceV2Addresses } from '../../config'; import { IGovernanceStrategy, IGovernanceStrategy__factory, @@ -15,6 +14,7 @@ import { Configuration, eEthereumTxType, EthereumTransactionTypeExtended, + GovernanceConfig, tEthereumAddress, transactionType, } from '../../types'; @@ -117,21 +117,27 @@ export default class AaveGovernanceV2Service readonly executors: tEthereumAddress[] = []; - constructor(config: Configuration) { + readonly governanceConfig: GovernanceConfig | undefined; + + constructor( + config: Configuration, + governanceConfig: GovernanceConfig | undefined + ) { super(config, IAaveGovernanceV2__factory); + this.governanceConfig = governanceConfig; - const { network } = this.config; const { AAVE_GOVERNANCE_V2, AAVE_GOVERNANCE_V2_HELPER, AAVE_GOVERNANCE_V2_EXECUTOR_SHORT, AAVE_GOVERNANCE_V2_EXECUTOR_LONG, - } = aaveGovernanceV2Addresses[network]; + } = this.governanceConfig || {}; - this.aaveGovernanceV2Address = AAVE_GOVERNANCE_V2; - this.aaveGovernanceV2HelperAddress = AAVE_GOVERNANCE_V2_HELPER; - this.executors[ExecutorType.Short] = AAVE_GOVERNANCE_V2_EXECUTOR_SHORT; - this.executors[ExecutorType.Long] = AAVE_GOVERNANCE_V2_EXECUTOR_LONG; + this.aaveGovernanceV2Address = AAVE_GOVERNANCE_V2 || ''; + this.aaveGovernanceV2HelperAddress = AAVE_GOVERNANCE_V2_HELPER || ''; + this.executors[ExecutorType.Short] = + AAVE_GOVERNANCE_V2_EXECUTOR_SHORT || ''; + this.executors[ExecutorType.Long] = AAVE_GOVERNANCE_V2_EXECUTOR_LONG || ''; } @GovValidator diff --git a/src/tx-builder/services/v2/LendingPool.ts b/src/tx-builder/services/v2/LendingPool.ts index afe77649..c8c23ccd 100644 --- a/src/tx-builder/services/v2/LendingPool.ts +++ b/src/tx-builder/services/v2/LendingPool.ts @@ -1,10 +1,8 @@ import { constants, utils, BigNumberish, BytesLike } from 'ethers'; import { API_ETH_MOCK_ADDRESS, - commonContractAddressBetweenMarketsV2, DEFAULT_APPROVE_AMOUNT, MAX_UINT_AMOUNT, - distinctContractAddressBetweenMarketsV2, SURPLUS, } from '../../config'; import { ILendingPool, ILendingPool__factory } from '../../contract-types'; @@ -16,15 +14,20 @@ import { eEthereumTxType, EthereumTransactionTypeExtended, InterestRate, - Market, ProtocolAction, TokenMetadataType, transactionType, tStringDecimalUnits, tEthereumAddress, + LendingPoolMarketConfig, } from '../../types'; import { getTxValue, parseNumber } from '../../utils/parsings'; -import { LPValidator } from '../../validators/methodValidators'; +import { + LPFlashLiquidationValidator, + LPRepayWithCollateralValidator, + LPSwapCollateralValidator, + LPValidator, +} from '../../validators/methodValidators'; import { LPBorrowParamsType, LPDepositParamsType, @@ -83,7 +86,7 @@ const buildParaSwapLiquiditySwapParams = ( export default class LendingPool extends BaseService implements LendingPoolInterface { - readonly market: Market; + readonly market: string; readonly erc20Service: IERC20ServiceInterface; @@ -97,6 +100,14 @@ export default class LendingPool readonly repayWithCollateralAdapterService: RepayWithCollateralAdapterInterface; + readonly lendingPoolConfig: LendingPoolMarketConfig | undefined; + + readonly flashLiquidationAddress: string; + + readonly swapCollateralAddress: string; + + readonly repayWithCollateralAddress: string; + constructor( config: Configuration, erc20Service: IERC20ServiceInterface, @@ -104,7 +115,8 @@ export default class LendingPool wethGatewayService: WETHGatewayInterface, liquiditySwapAdapterService: LiquiditySwapAdapterInterface, repayWithCollateralAdapterService: RepayWithCollateralAdapterInterface, - market: Market + market: string, + lendingPoolConfig: LendingPoolMarketConfig | undefined ) { super(config, ILendingPool__factory); this.erc20Service = erc20Service; @@ -113,12 +125,19 @@ export default class LendingPool this.liquiditySwapAdapterService = liquiditySwapAdapterService; this.repayWithCollateralAdapterService = repayWithCollateralAdapterService; this.market = market; + this.lendingPoolConfig = lendingPoolConfig; - const { network } = this.config; - this.lendingPoolAddress = - distinctContractAddressBetweenMarketsV2[this.market][ - network - ].LENDINGPOOL_ADDRESS; + const { + LENDING_POOL, + FLASH_LIQUIDATION_ADAPTER, + REPAY_WITH_COLLATERAL_ADAPTER, + SWAP_COLLATERAL_ADAPTER, + } = this.lendingPoolConfig || {}; + + this.lendingPoolAddress = LENDING_POOL || ''; + this.flashLiquidationAddress = FLASH_LIQUIDATION_ADAPTER || ''; + this.swapCollateralAddress = SWAP_COLLATERAL_ADAPTER || ''; + this.repayWithCollateralAddress = REPAY_WITH_COLLATERAL_ADAPTER || ''; } @LPValidator @@ -558,7 +577,7 @@ export default class LendingPool return txs; } - @LPValidator + @LPSwapCollateralValidator public async swapCollateral( @IsEthAddress('user') @IsEthAddress('fromAsset') @@ -594,14 +613,10 @@ export default class LendingPool s: '0x0000000000000000000000000000000000000000000000000000000000000000', }; - const { SWAP_COLLATERAL_ADAPTER } = commonContractAddressBetweenMarketsV2[ - this.config.network - ]; - const approved: boolean = await this.erc20Service.isApproved( fromAToken, user, - SWAP_COLLATERAL_ADAPTER, + this.swapCollateralAddress, fromAmount ); @@ -609,7 +624,7 @@ export default class LendingPool const approveTx: EthereumTransactionTypeExtended = this.erc20Service.approve( user, fromAToken, - SWAP_COLLATERAL_ADAPTER, + this.swapCollateralAddress, constants.MaxUint256.toString() ); @@ -661,7 +676,7 @@ export default class LendingPool { rawTxMethod: () => lendingPoolContract.populateTransaction.flashLoan( - SWAP_COLLATERAL_ADAPTER, + this.swapCollateralAddress, [fromAsset], swapAll ? [convertedAmountWithSurplus] : [convertedAmount], [0], // interest rate mode to NONE for flashloan to not open debt @@ -704,7 +719,7 @@ export default class LendingPool return txs; } - @LPValidator + @LPRepayWithCollateralValidator public async repayWithCollateral( @IsEthAddress('user') @IsEthAddress('fromAsset') @@ -739,14 +754,10 @@ export default class LendingPool s: '0x0000000000000000000000000000000000000000000000000000000000000000', }; - const { - REPAY_WITH_COLLATERAL_ADAPTER, - } = commonContractAddressBetweenMarketsV2[this.config.network]; - const approved: boolean = await this.erc20Service.isApproved( fromAToken, user, - REPAY_WITH_COLLATERAL_ADAPTER, + this.repayWithCollateralAddress, repayWithAmount ); @@ -754,7 +765,7 @@ export default class LendingPool const approveTx: EthereumTransactionTypeExtended = this.erc20Service.approve( user, fromAToken, - REPAY_WITH_COLLATERAL_ADAPTER, + this.repayWithCollateralAddress, constants.MaxUint256.toString() ); @@ -816,7 +827,7 @@ export default class LendingPool { rawTxMethod: () => lendingPoolContract.populateTransaction.flashLoan( - REPAY_WITH_COLLATERAL_ADAPTER, + this.repayWithCollateralAddress, [assetToRepay], [convertedRepayAmount], [0], // interest rate mode to NONE for flashloan to not open debt @@ -859,7 +870,7 @@ export default class LendingPool return txs; } - @LPValidator + @LPFlashLiquidationValidator public async flashLiquidation( @IsEthAddress('user') @IsEthAddress('collateralAsset') @@ -885,10 +896,6 @@ export default class LendingPool const txs: EthereumTransactionTypeExtended[] = []; - const { FLASHLIQUIDATION } = commonContractAddressBetweenMarketsV2[ - this.config.network - ]; - const lendingPoolContract: ILendingPool = this.getContractInstance( this.lendingPoolAddress ); @@ -921,7 +928,7 @@ export default class LendingPool const txCallback: () => Promise = this.generateTxCallback({ rawTxMethod: () => lendingPoolContract.populateTransaction.flashLoan( - FLASHLIQUIDATION, + this.flashLiquidationAddress, [borrowedAsset], [flashBorrowAmount], [0], diff --git a/src/tx-builder/txBuilder.ts b/src/tx-builder/txBuilder.ts index a41945cd..b94fd08d 100644 --- a/src/tx-builder/txBuilder.ts +++ b/src/tx-builder/txBuilder.ts @@ -14,11 +14,12 @@ import { Configuration, DefaultProviderKeys, Network, - Stake, + TxBuilderConfig, } from './types'; import IncentivesController, { IncentivesControllerInterface, } from './services/IncentivesController'; +import { defaultConfig } from './config/defaultConfig'; export default class BaseTxBuilder { readonly configuration: Configuration; @@ -29,19 +30,22 @@ export default class BaseTxBuilder { public ltaMigratorService: LTAMigratorInterface; - public faucetService: FaucetInterface; - public incentiveService: IncentivesControllerInterface; readonly stakings: { [stake: string]: StakingInterface }; + readonly faucets: { [market: string]: FaucetInterface }; + + readonly txBuilderConfig: TxBuilderConfig; + constructor( network: Network = Network.mainnet, injectedProvider?: providers.Provider | string | undefined, - defaultProviderKeys?: DefaultProviderKeys + defaultProviderKeys?: DefaultProviderKeys, + config: TxBuilderConfig = defaultConfig ) { + this.txBuilderConfig = config; let provider: providers.Provider; - // TODO: this is probably not enough as we use network down the road const chainId = ChainId[network]; @@ -67,26 +71,45 @@ export default class BaseTxBuilder { this.erc20Service = new ERC20Service(this.configuration); this.synthetixService = new SynthetixService(this.configuration); + this.ltaMigratorService = new LTAMigratorService( this.configuration, - this.erc20Service + this.erc20Service, + this.txBuilderConfig.migrator?.[network] + ); + + this.incentiveService = new IncentivesController( + this.configuration, + this.txBuilderConfig.incentives?.[network] ); - this.faucetService = new FaucetService(this.configuration); - this.incentiveService = new IncentivesController(this.configuration); this.stakings = {}; + this.faucets = {}; } - public getStaking = (stake?: Stake): StakingInterface => { - const stakeToken = stake || Stake.Aave; - if (!this.stakings[stakeToken]) { - this.stakings[stakeToken] = new StakingService( + public getFaucet = (market: string): FaucetInterface => { + if (!this.faucets[market]) { + const { network } = this.configuration; + this.faucets[market] = new FaucetService( this.configuration, - this.erc20Service, - stakeToken + this.txBuilderConfig.lendingPool?.[network]?.[market] ); } + return this.faucets[market]; + }; - return this.stakings[stakeToken]; + public getStaking = (stake: string): StakingInterface => { + if (!this.stakings[stake]) { + const { network } = this.configuration; + const stakingConfig = this.txBuilderConfig.staking?.[network]?.[stake]; + + this.stakings[stake] = new StakingService( + this.configuration, + this.erc20Service, + stake, + stakingConfig + ); + } + return this.stakings[stake]; }; } diff --git a/src/tx-builder/types/index.ts b/src/tx-builder/types/index.ts index 4af5e77a..d91ef559 100644 --- a/src/tx-builder/types/index.ts +++ b/src/tx-builder/types/index.ts @@ -25,6 +25,10 @@ export enum Network { fork = 'fork', mumbai = 'mumbai', polygon_fork = 'polygon_fork', + avalanche = 'avalanche', + fuji = 'fuji', // avalanche test network + arbitrum_one = 'arbitrum_one', + arbitrum_rinkeby = 'arbitrum_rinkeby', } export enum ChainId { @@ -35,7 +39,68 @@ export enum ChainId { fork = 1337, mumbai = 80001, polygon_fork = 1338, + avalanche = 43114, + fuji = 43113, // avalanche test network + arbitrum_one = 42161, + arbitrum_rinkeby = 421611, } +export type ConstantAddressesByNetwork = { + [network: string]: { + SYNTHETIX_PROXY_ADDRESS?: tEthereumAddress; + }; +}; +export type GovernanceConfig = { + AAVE_GOVERNANCE_V2: tEthereumAddress; + AAVE_GOVERNANCE_V2_EXECUTOR_SHORT: tEthereumAddress; + AAVE_GOVERNANCE_V2_EXECUTOR_LONG: tEthereumAddress; + AAVE_GOVERNANCE_V2_HELPER: tEthereumAddress; +}; + +export type IncentivesConfig = { + INCENTIVES_CONTROLLER: tEthereumAddress; + INCENTIVES_CONTROLLER_REWARD_TOKEN: tEthereumAddress; +}; + +export type MigratorConfig = { + LEND_TO_AAVE_MIGRATOR: tEthereumAddress; +}; + +export type LendingPoolMarketConfig = { + LENDING_POOL: tEthereumAddress; + WETH_GATEWAY?: tEthereumAddress; + FLASH_LIQUIDATION_ADAPTER?: tEthereumAddress; + REPAY_WITH_COLLATERAL_ADAPTER?: tEthereumAddress; + SWAP_COLLATERAL_ADAPTER?: tEthereumAddress; + FAUCET?: tEthereumAddress; +}; + +export type LendingPoolConfig = { + [network: string]: { + [market: string]: LendingPoolMarketConfig; + }; +}; + +export type StakingNetworkConfig = { + TOKEN_STAKING: tEthereumAddress; + STAKING_REWARD_TOKEN: tEthereumAddress; + STAKING_HELPER?: tEthereumAddress; +}; + +export type StakingConfig = { + [network: string]: { [stake: string]: StakingNetworkConfig }; +}; + +export type TxBuilderConfig = { + governance?: { + [network: string]: GovernanceConfig; + }; + incentives?: { + [network: string]: IncentivesConfig; + }; + migrator?: { [network: string]: MigratorConfig }; + lendingPool?: LendingPoolConfig; + staking?: StakingConfig; +}; export enum eEthereumTxType { ERC20_APPROVAL = 'ERC20_APPROVAL', @@ -68,8 +133,8 @@ export enum GovernanceVote { } export enum Stake { - Aave = 'Aave', - Balancer = 'Balancer', + aave = 'aave', + bpt = 'bpt', } export type GasRecommendationType = { diff --git a/src/tx-builder/v2.ts b/src/tx-builder/v2.ts index 5f8ad1a0..a4d4cf4e 100644 --- a/src/tx-builder/v2.ts +++ b/src/tx-builder/v2.ts @@ -1,5 +1,5 @@ import { providers } from 'ethers'; -import { Network, Market, DefaultProviderKeys } from './types'; +import { Network, DefaultProviderKeys, TxBuilderConfig } from './types'; import TxBuilderInterface from './interfaces/TxBuilder'; import LendingPoolInterface from './interfaces/v2/LendingPool'; import LendingPool from './services/v2/LendingPool'; @@ -24,59 +24,110 @@ export default class TxBuilder [market: string]: LendingPoolInterface; }; - readonly baseDebtTokenService: BaseDebtTokenInterface; + readonly wethGateways: { + [market: string]: WETHGatewayInterface; + }; + + readonly swapCollateralAdapters: { + [market: string]: LiquiditySwapAdapterInterface; + }; - readonly liquiditySwapAdapterService: LiquiditySwapAdapterInterface; + readonly repayWithCollateralAdapters: { + [market: string]: RepayWithCollateralAdapterInterface; + }; - readonly repayWithCollateralAdapterService: RepayWithCollateralAdapterInterface; + readonly baseDebtTokenService: BaseDebtTokenInterface; public aaveGovernanceV2Service: AaveGovernanceV2Interface; public governanceDelegationTokenService: GovernanceDelegationTokenInterface; - public wethGatewayService: WETHGatewayInterface; - constructor( network: Network = Network.mainnet, injectedProvider?: providers.Provider | string | undefined, - defaultProviderKeys?: DefaultProviderKeys + defaultProviderKeys?: DefaultProviderKeys, + config?: TxBuilderConfig ) { - super(network, injectedProvider, defaultProviderKeys); + super(network, injectedProvider, defaultProviderKeys, config); + this.wethGateways = {}; this.lendingPools = {}; + this.swapCollateralAdapters = {}; + this.repayWithCollateralAdapters = {}; this.baseDebtTokenService = new BaseDebtToken( this.configuration, this.erc20Service ); - this.wethGatewayService = new WETHGatewayService( - this.configuration, - this.baseDebtTokenService, - this.erc20Service - ); - this.liquiditySwapAdapterService = new LiquiditySwapAdapterService( - this.configuration - ); - this.repayWithCollateralAdapterService = new RepayWithCollateralAdapterService( - this.configuration - ); + this.aaveGovernanceV2Service = new AaveGovernanceV2Service( - this.configuration + this.configuration, + this.txBuilderConfig.governance?.[network] ); + this.governanceDelegationTokenService = new GovernanceDelegationTokenService( this.configuration ); } - public getLendingPool = (market: Market): LendingPoolInterface => { + public getRepayWithCollateralAdapter = ( + market: string + ): RepayWithCollateralAdapterInterface => { + const { network } = this.configuration; + + if (!this.repayWithCollateralAdapters[market]) { + this.repayWithCollateralAdapters[ + market + ] = new RepayWithCollateralAdapterService( + this.configuration, + this.txBuilderConfig.lendingPool?.[network]?.[market] + ); + } + + return this.repayWithCollateralAdapters[market]; + }; + + public getSwapCollateralAdapter = ( + market: string + ): LiquiditySwapAdapterInterface => { + const { network } = this.configuration; + + if (!this.swapCollateralAdapters[market]) { + this.swapCollateralAdapters[market] = new LiquiditySwapAdapterService( + this.configuration, + this.txBuilderConfig.lendingPool?.[network]?.[market] + ); + } + + return this.swapCollateralAdapters[market]; + }; + + public getWethGateway = (market: string): WETHGatewayInterface => { + const { network } = this.configuration; + if (!this.wethGateways[market]) { + this.wethGateways[market] = new WETHGatewayService( + this.configuration, + this.baseDebtTokenService, + this.erc20Service, + this.txBuilderConfig.lendingPool?.[network]?.[market] + ); + } + + return this.wethGateways[market]; + }; + + public getLendingPool = (market: string): LendingPoolInterface => { + const { network } = this.configuration; + console.log(this.txBuilderConfig.lendingPool, network, market); if (!this.lendingPools[market]) { this.lendingPools[market] = new LendingPool( this.configuration, this.erc20Service, this.synthetixService, - this.wethGatewayService, - this.liquiditySwapAdapterService, - this.repayWithCollateralAdapterService, - market + this.getWethGateway(market), + this.getSwapCollateralAdapter(market), + this.getRepayWithCollateralAdapter(market), + market, + this.txBuilderConfig.lendingPool?.[network]?.[market] ); } diff --git a/src/tx-builder/validators/methodValidators.ts b/src/tx-builder/validators/methodValidators.ts index 3821f495..9e011bf0 100644 --- a/src/tx-builder/validators/methodValidators.ts +++ b/src/tx-builder/validators/methodValidators.ts @@ -1,16 +1,113 @@ /* eslint-disable prefer-rest-params */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Network } from '../types'; import { amount0OrPositiveValidator, amountGtThan0OrMinus1, amountGtThan0Validator, - // isEthAddressArrayValidator, isEthAddressOrEnsValidator, isEthAddressValidator, optionalValidator, } from './validations'; -import { enabledNetworksByService } from '../config'; +import { utils } from 'ethers'; + +export function LPFlashLiquidationValidator( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + target: any, + propertyName: string, + descriptor: TypedPropertyDescriptor +): any { + const method = descriptor.value; + // eslint-disable-next-line no-param-reassign + descriptor.value = function () { + const { LENDING_POOL, FLASH_LIQUIDATION_ADAPTER } = + this.lendingPoolConfig || {}; + + if ( + !utils.isAddress(LENDING_POOL) || + !FLASH_LIQUIDATION_ADAPTER || + !utils.isAddress(FLASH_LIQUIDATION_ADAPTER) + ) { + console.error( + `[LPFlahsLiquidationValidator] You need to pass valid addresses` + ); + return []; + } + + isEthAddressValidator(target, propertyName, arguments); + + amountGtThan0Validator(target, propertyName, arguments); + + amountGtThan0OrMinus1(target, propertyName, arguments); + + return method?.apply(this, arguments); + }; +} + +export function LPRepayWithCollateralValidator( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + target: any, + propertyName: string, + descriptor: TypedPropertyDescriptor +): any { + const method = descriptor.value; + // eslint-disable-next-line no-param-reassign + descriptor.value = function () { + const { LENDING_POOL, REPAY_WITH_COLLATERAL_ADAPTER } = + this.lendingPoolConfig || {}; + + if ( + !utils.isAddress(LENDING_POOL) || + !REPAY_WITH_COLLATERAL_ADAPTER || + !utils.isAddress(REPAY_WITH_COLLATERAL_ADAPTER) + ) { + console.error( + `[LPRepayWithCollateralValidator] You need to pass valid addresses` + ); + return []; + } + + isEthAddressValidator(target, propertyName, arguments); + + amountGtThan0Validator(target, propertyName, arguments); + + amountGtThan0OrMinus1(target, propertyName, arguments); + + return method?.apply(this, arguments); + }; +} + +export function LPSwapCollateralValidator( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + target: any, + propertyName: string, + descriptor: TypedPropertyDescriptor +): any { + const method = descriptor.value; + // eslint-disable-next-line no-param-reassign + descriptor.value = function () { + const { LENDING_POOL, SWAP_COLLATERAL_ADAPTER } = + this.lendingPoolConfig || {}; + + if ( + !utils.isAddress(LENDING_POOL) || + !SWAP_COLLATERAL_ADAPTER || + !utils.isAddress(SWAP_COLLATERAL_ADAPTER) + ) { + console.error( + `[LPSwapCollateralValidator] You need to pass valid addresses` + ); + return []; + } + + isEthAddressValidator(target, propertyName, arguments); + + amountGtThan0Validator(target, propertyName, arguments); + + amountGtThan0OrMinus1(target, propertyName, arguments); + + return method?.apply(this, arguments); + }; +} export function LPValidator( // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types @@ -21,10 +118,10 @@ export function LPValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.lendingPool[this.market]; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const { LENDING_POOL } = this.lendingPoolConfig || {}; + + if (!utils.isAddress(LENDING_POOL)) { + console.error(`[LendingPoolValidator] You need to pass valid addresses`); return []; } @@ -47,9 +144,11 @@ export function LTAMigratorValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = enabledNetworksByService.ltaMigrator; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const LEND_TO_AAVE_MIGRATOR = + this.migratorConfig?.LEND_TO_AAVE_MIGRATOR || ''; + + if (!utils.isAddress(LEND_TO_AAVE_MIGRATOR)) { + console.error(`[MigratorValidator] You need to pass valid addresses`); return []; } @@ -70,10 +169,14 @@ export function IncentivesValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.incentivesController; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const { INCENTIVES_CONTROLLER, INCENTIVES_CONTROLLER_REWARD_TOKEN } = + this.incentivesConfig || {}; + + if ( + !utils.isAddress(INCENTIVES_CONTROLLER_REWARD_TOKEN) || + !utils.isAddress(INCENTIVES_CONTROLLER) + ) { + console.error(`[IncentivesValidator] You need to pass valid addresses`); return []; } @@ -94,10 +197,13 @@ export function LiquiditySwapValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.liquiditySwapAdapter; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const SWAP_COLLATERAL_ADAPTER = + this.swapCollateralConfig.SWAP_COLLATERAL_ADAPTER || ''; + + if (!utils.isAddress(SWAP_COLLATERAL_ADAPTER)) { + console.error( + `[LiquiditySwapValidator] You need to pass valid addresses` + ); return []; } @@ -120,10 +226,13 @@ export function RepayWithCollateralValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.repayWithCollateralAdapter; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const REPAY_WITH_COLLATERAL_ADAPTER = + this.repayWithCollateralConfig?.REPAY_WITH_COLLATERAL_ADAPTER || ''; + + if (!utils.isAddress(REPAY_WITH_COLLATERAL_ADAPTER)) { + console.error( + `[RepayWithCollateralValidator] You need to pass valid addresses` + ); return []; } @@ -146,10 +255,53 @@ export function StakingValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.staking[this.tokenStake]; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + // No need to check if addresses exist for network + // because this is checked at initialization and type checking of config + + const { TOKEN_STAKING, STAKING_REWARD_TOKEN } = this.stakingConfig || {}; + + // Check if addresses are valid. + if ( + !utils.isAddress(TOKEN_STAKING) || + !utils.isAddress(STAKING_REWARD_TOKEN) + ) { + console.error(`[StakingValidator] You need to pass valid addresses`); + return []; + } + + const isParamOptional = optionalValidator(target, propertyName, arguments); + + isEthAddressValidator(target, propertyName, arguments, isParamOptional); + + amountGtThan0Validator(target, propertyName, arguments, isParamOptional); + + return method?.apply(this, arguments); + }; +} + +export function SignStakingValidator( + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + target: any, + propertyName: string, + descriptor: TypedPropertyDescriptor +): any { + const method = descriptor.value; + // eslint-disable-next-line no-param-reassign + descriptor.value = function () { + // No need to check if addresses exist for network + // because this is checked at initialization and type checking of config + + const { TOKEN_STAKING, STAKING_REWARD_TOKEN, STAKING_HELPER } = + this.stakingConfig || {}; + + // Check if addresses are valid. + if ( + !utils.isAddress(TOKEN_STAKING) || + !utils.isAddress(STAKING_REWARD_TOKEN) || + !STAKING_HELPER || + !utils.isAddress(TOKEN_STAKING) + ) { + console.error(`[StakingValidator] You need to pass valid addresses`); return []; } @@ -172,9 +324,10 @@ export function FaucetValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = enabledNetworksByService.faucet; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const FAUCET = this.faucetConfig?.FAUCET; + + if (!FAUCET || (FAUCET && !utils.isAddress(FAUCET))) { + console.error(`[FaucetValidator] You need to pass valid addresses`); return []; } @@ -197,9 +350,10 @@ export function WETHValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = enabledNetworksByService.wethGateway; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const WETH_GATEWAY = this.wethGatewayConfig?.WETH_GATEWAY || ''; + + if (!utils.isAddress(WETH_GATEWAY)) { + console.error(`[WethGatewayValidator] You need to pass valid addresses`); return []; } @@ -222,10 +376,20 @@ export function GovValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.aaveGovernanceV2; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { + const { + AAVE_GOVERNANCE_V2, + AAVE_GOVERNANCE_V2_HELPER, + AAVE_GOVERNANCE_V2_EXECUTOR_SHORT, + AAVE_GOVERNANCE_V2_EXECUTOR_LONG, + } = this.governanceConfig || {}; + + if ( + !utils.isAddress(AAVE_GOVERNANCE_V2) || + !utils.isAddress(AAVE_GOVERNANCE_V2_HELPER) || + !utils.isAddress(AAVE_GOVERNANCE_V2_EXECUTOR_SHORT) || + !utils.isAddress(AAVE_GOVERNANCE_V2_EXECUTOR_LONG) + ) { + console.error(`[GovernanceValidator] You need to pass valid addresses`); return []; } @@ -246,13 +410,6 @@ export function GovDelegationValidator( const method = descriptor.value; // eslint-disable-next-line no-param-reassign descriptor.value = function () { - const currentNetwork = this.config.network; - const acceptedNetworks: Network[] = - enabledNetworksByService.aaveGovernanceV2; - if (acceptedNetworks.indexOf(currentNetwork) === -1) { - return []; - } - isEthAddressValidator(target, propertyName, arguments); isEthAddressOrEnsValidator(target, propertyName, arguments); amountGtThan0Validator(target, propertyName, arguments); diff --git a/tsconfig.json b/tsconfig.json index f44b8fd8..6cbcad8a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,7 @@ "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, + "resolveJsonModule": true, "moduleResolution": "node", "baseUrl": "./", "paths": {