From f4fc422f10508c555746e25976ae0e4399f5cf1b Mon Sep 17 00:00:00 2001 From: weizard Date: Fri, 24 Nov 2023 12:10:17 +0800 Subject: [PATCH] feat: add aave v2 into lending package --- packages/lending/src/protocol.type.ts | 1 - .../src/protocols/aave-v2/abis/AToken.json | 21 + .../src/protocols/aave-v2/abis/DebtToken.json | 44 ++ .../protocols/aave-v2/abis/ETHPriceFeed.json | 15 + .../protocols/aave-v2/abis/LendingPool.json | 147 ++++++ .../protocols/aave-v2/abis/PriceOracle.json | 40 ++ .../aave-v2/abis/ProtocolDataProvider.json | 223 ++++++++ .../lending/src/protocols/aave-v2/configs.ts | 488 ++++++++++++++++++ .../src/protocols/aave-v2/contracts/AToken.ts | 64 +++ .../protocols/aave-v2/contracts/DebtToken.ts | 104 ++++ .../aave-v2/contracts/ETHPriceFeed.ts | 64 +++ .../aave-v2/contracts/LendingPool.ts | 188 +++++++ .../protocols/aave-v2/contracts/PriceFeed.ts | 64 +++ .../aave-v2/contracts/PriceOracle.ts | 77 +++ .../aave-v2/contracts/ProtocolDataProvider.ts | 280 ++++++++++ .../src/protocols/aave-v2/contracts/common.ts | 30 ++ .../contracts/factories/AToken__factory.ts | 39 ++ .../contracts/factories/DebtToken__factory.ts | 62 +++ .../factories/ETHPriceFeed__factory.ts | 33 ++ .../factories/LendingPool__factory.ts | 165 ++++++ .../contracts/factories/PriceFeed__factory.ts | 33 ++ .../factories/PriceOracle__factory.ts | 58 +++ .../ProtocolDataProvider__factory.ts | 241 +++++++++ .../aave-v2/contracts/factories/index.ts | 9 + .../src/protocols/aave-v2/contracts/index.ts | 16 + .../lending/src/protocols/aave-v2/index.ts | 2 + .../src/protocols/aave-v2/lending-protocol.ts | 365 +++++++++++++ .../src/protocols/compound-v3/configs.ts | 2 +- packages/lending/test/hooks.ts | 2 + .../lending/test/transactions/zap-borrow.ts | 12 + .../lending/test/transactions/zap-repay.ts | 14 +- .../lending/test/transactions/zap-supply.ts | 20 +- .../lending/test/transactions/zap-withdraw.ts | 20 + 33 files changed, 2939 insertions(+), 4 deletions(-) create mode 100644 packages/lending/src/protocols/aave-v2/abis/AToken.json create mode 100644 packages/lending/src/protocols/aave-v2/abis/DebtToken.json create mode 100644 packages/lending/src/protocols/aave-v2/abis/ETHPriceFeed.json create mode 100644 packages/lending/src/protocols/aave-v2/abis/LendingPool.json create mode 100644 packages/lending/src/protocols/aave-v2/abis/PriceOracle.json create mode 100644 packages/lending/src/protocols/aave-v2/abis/ProtocolDataProvider.json create mode 100644 packages/lending/src/protocols/aave-v2/configs.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/AToken.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/DebtToken.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/ETHPriceFeed.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/LendingPool.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/PriceFeed.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/PriceOracle.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/ProtocolDataProvider.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/common.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/AToken__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/DebtToken__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/ETHPriceFeed__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/LendingPool__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/PriceFeed__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/PriceOracle__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/ProtocolDataProvider__factory.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/factories/index.ts create mode 100644 packages/lending/src/protocols/aave-v2/contracts/index.ts create mode 100644 packages/lending/src/protocols/aave-v2/index.ts create mode 100644 packages/lending/src/protocols/aave-v2/lending-protocol.ts diff --git a/packages/lending/src/protocol.type.ts b/packages/lending/src/protocol.type.ts index 9f5e5456..10d5091c 100644 --- a/packages/lending/src/protocol.type.ts +++ b/packages/lending/src/protocol.type.ts @@ -1,6 +1,5 @@ import * as common from '@protocolink/common'; import * as core from '@protocolink/core'; -import * as logics from '@protocolink/logics'; export interface Market { id: string; diff --git a/packages/lending/src/protocols/aave-v2/abis/AToken.json b/packages/lending/src/protocols/aave-v2/abis/AToken.json new file mode 100644 index 00000000..62b8ffb1 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/AToken.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "scaledBalanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/abis/DebtToken.json b/packages/lending/src/protocols/aave-v2/abis/DebtToken.json new file mode 100644 index 00000000..269b9394 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/DebtToken.json @@ -0,0 +1,44 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "delegatee", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approveDelegation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "fromUser", + "type": "address" + }, + { + "internalType": "address", + "name": "toUser", + "type": "address" + } + ], + "name": "borrowAllowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/abis/ETHPriceFeed.json b/packages/lending/src/protocols/aave-v2/abis/ETHPriceFeed.json new file mode 100644 index 00000000..d899a4e4 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/ETHPriceFeed.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "latestAnswer", + "outputs": [ + { + "internalType": "int256", + "name": "", + "type": "int256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/abis/LendingPool.json b/packages/lending/src/protocols/aave-v2/abis/LendingPool.json new file mode 100644 index 00000000..20caa08d --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/LendingPool.json @@ -0,0 +1,147 @@ +[ + { + "inputs": [], + "name": "FLASHLOAN_PREMIUM_TOTAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getReserveData", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + } + ], + "internalType": "struct DataTypes.ReserveConfigurationMap", + "name": "configuration", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "liquidityIndex", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "variableBorrowIndex", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "currentLiquidityRate", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "currentVariableBorrowRate", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "currentStableBorrowRate", + "type": "uint128" + }, + { + "internalType": "uint40", + "name": "lastUpdateTimestamp", + "type": "uint40" + }, + { + "internalType": "address", + "name": "aTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "stableDebtTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "variableDebtTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "interestRateStrategyAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "id", + "type": "uint8" + } + ], + "internalType": "struct DataTypes.ReserveData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getUserAccountData", + "outputs": [ + { + "internalType": "uint256", + "name": "totalCollateralETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalDebtETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableBorrowsETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentLiquidationThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ltv", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "healthFactor", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/abis/PriceOracle.json b/packages/lending/src/protocols/aave-v2/abis/PriceOracle.json new file mode 100644 index 00000000..386a1a88 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/PriceOracle.json @@ -0,0 +1,40 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getAssetPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "assets", + "type": "address[]" + } + ], + "name": "getAssetsPrices", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/abis/ProtocolDataProvider.json b/packages/lending/src/protocols/aave-v2/abis/ProtocolDataProvider.json new file mode 100644 index 00000000..4224092d --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/abis/ProtocolDataProvider.json @@ -0,0 +1,223 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getReserveConfigurationData", + "outputs": [ + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ltv", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationBonus", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveFactor", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "usageAsCollateralEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "borrowingEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "stableBorrowRateEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isFrozen", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getReserveTokensAddresses", + "outputs": [ + { + "internalType": "address", + "name": "aTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "stableDebtTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "variableDebtTokenAddress", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getReserveData", + "outputs": [ + { + "internalType": "uint256", + "name": "availableLiquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalStableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalVariableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidityRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "variableBorrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stableBorrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "averageStableBorrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidityIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "variableBorrowIndex", + "type": "uint256" + }, + { + "internalType": "uint40", + "name": "lastUpdateTimestamp", + "type": "uint40" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getUserReserveData", + "outputs": [ + { + "internalType": "uint256", + "name": "currentATokenBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentStableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentVariableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "principalStableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "scaledVariableDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stableBorrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidityRate", + "type": "uint256" + }, + { + "internalType": "uint40", + "name": "stableRateLastUpdated", + "type": "uint40" + }, + { + "internalType": "bool", + "name": "usageAsCollateralEnabled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/lending/src/protocols/aave-v2/configs.ts b/packages/lending/src/protocols/aave-v2/configs.ts new file mode 100644 index 00000000..5ba653e4 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/configs.ts @@ -0,0 +1,488 @@ +import * as common from '@protocolink/common'; +import { isNativeToken, unwrapToken, wrapToken } from 'src/helper'; +import * as logics from '@protocolink/logics'; + +export enum RateMode { + STABLE = 1, + VARIABLE, +} + +export interface Reserve { + asset: common.Token; + aToken: common.Token; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + used: { + deposit?: boolean; + withdraw?: boolean; + borrow?: boolean; + repay?: boolean; + flashLoan?: boolean; + }; +} + +type ContractName = 'LendingPool' | 'ProtocolDataProvider' | 'PriceOracle' | 'ETHPriceFeed'; + +interface Config { + chainId: number; + contractMap: Record; + reserves: Reserve[]; +} + +export const configs: Config[] = [ + // https://github.com/bgd-labs/aave-address-book/blob/main/src/AaveV2Ethereum.sol + { + chainId: common.ChainId.mainnet, + contractMap: { + LendingPool: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9', + ProtocolDataProvider: '0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d', + PriceOracle: '0xA50ba011c48153De246E5192C8f9258A2ba79Ca9', + ETHPriceFeed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419', + }, + reserves: [ + { + asset: logics.aavev2.mainnetTokens.AAVE, + aToken: logics.aavev2.mainnetTokens.aAAVE, + stableDebtTokenAddress: '0x079D6a3E844BcECf5720478A718Edb6575362C5f', + variableDebtTokenAddress: '0xF7DBA49d571745D9d7fcb56225B05BEA803EBf3C', + used: { deposit: true, withdraw: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.AMPL, + // aToken: logics.aavev2.mainnetTokens.aAMPL, + // stableDebtTokenAddress: '0x18152C9f77DAdc737006e9430dB913159645fa87', + // variableDebtTokenAddress: '0xf013D90E4e4E3Baf420dFea60735e75dbd42f1e1', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.BAL, + // aToken: logics.aavev2.mainnetTokens.aBAL, + // stableDebtTokenAddress: '0xe569d31590307d05DA3812964F1eDd551D665a0b', + // variableDebtTokenAddress: '0x13210D4Fe0d5402bd7Ecbc4B5bC5cFcA3b71adB0', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.BAT, + // aToken: logics.aavev2.mainnetTokens.aBAT, + // stableDebtTokenAddress: '0x277f8676FAcf4dAA5a6EA38ba511B7F65AA02f9F', + // variableDebtTokenAddress: '0xfc218A6Dfe6901CB34B1a5281FC6f1b8e7E56877', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.BUSD, + // aToken: logics.aavev2.mainnetTokens.aBUSD, + // stableDebtTokenAddress: '0x4A7A63909A72D268b1D8a93a9395d098688e0e5C', + // variableDebtTokenAddress: '0xbA429f7011c9fa04cDd46a2Da24dc0FF0aC6099c', + // used: { withdraw: true, repay: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.CRV, + aToken: logics.aavev2.mainnetTokens.aCRV, + stableDebtTokenAddress: '0x9288059a74f589C919c7Cf1Db433251CdFEB874B', + variableDebtTokenAddress: '0x00ad8eBF64F141f1C81e9f8f792d3d1631c6c684', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + { + asset: logics.aavev2.mainnetTokens.DAI, + aToken: logics.aavev2.mainnetTokens.aDAI, + stableDebtTokenAddress: '0x778A13D3eeb110A4f7bb6529F99c000119a08E92', + variableDebtTokenAddress: '0x6C3c78838c761c6Ac7bE9F59fe808ea2A6E4379d', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.DPI, + // aToken: logics.aavev2.mainnetTokens.aDPI, + // stableDebtTokenAddress: '0xa3953F07f389d719F99FC378ebDb9276177d8A6e', + // variableDebtTokenAddress: '0x4dDff5885a67E4EffeC55875a3977D7E60F82ae0', + // used: { deposit: true, withdraw: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.FEI, + // aToken: logics.aavev2.mainnetTokens.aFEI, + // stableDebtTokenAddress: '0xd89cF9E8A858F8B4b31Faf793505e112d6c17449', + // variableDebtTokenAddress: '0xC2e10006AccAb7B45D9184FcF5b7EC7763f5BaAe', + // used: { withdraw: true, repay: true }, + // }, + + // { + // asset: logics.aavev2.mainnetTokens.ENJ, + // aToken: logics.aavev2.mainnetTokens.aENJ, + // stableDebtTokenAddress: '0x943DcCA156b5312Aa24c1a08769D67FEce4ac14C', + // variableDebtTokenAddress: '0x38995F292a6E31b78203254fE1cdd5Ca1010A446', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.ENS, + // aToken: logics.aavev2.mainnetTokens.aENS, + // stableDebtTokenAddress: '0x34441FFD1948E49dC7a607882D0c38Efd0083815', + // variableDebtTokenAddress: '0x176808047cc9b7A2C9AE202c593ED42dDD7C0D13', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.ETH, + aToken: logics.aavev2.mainnetTokens.aWETH, + stableDebtTokenAddress: '0x4e977830ba4bd783C0BB7F15d3e243f73FF57121', + variableDebtTokenAddress: '0xF63B34710400CAd3e044cFfDcAb00a0f32E33eCf', + used: { deposit: true, withdraw: true, borrow: true, repay: true }, + }, + { + asset: logics.aavev2.mainnetTokens.FRAX, + aToken: logics.aavev2.mainnetTokens.aFRAX, + stableDebtTokenAddress: '0x3916e3B6c84b161df1b2733dFfc9569a1dA710c2', + variableDebtTokenAddress: '0xfE8F19B17fFeF0fDbfe2671F248903055AFAA8Ca', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + { + asset: logics.aavev2.mainnetTokens.GUSD, + aToken: logics.aavev2.mainnetTokens.aGUSD, + stableDebtTokenAddress: '0xf8aC64ec6Ff8E0028b37EB89772d21865321bCe0', + variableDebtTokenAddress: '0x279AF5b99540c1A3A7E3CDd326e19659401eF99e', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.KNCL, + // aToken: logics.aavev2.mainnetTokens.aKNCL, + // stableDebtTokenAddress: '0x9915dfb872778B2890a117DA1F35F335eb06B54f', + // variableDebtTokenAddress: '0x6B05D1c608015Ccb8e205A690cB86773A96F39f1', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.LINK, + // aToken: logics.aavev2.mainnetTokens.aLINK, + // stableDebtTokenAddress: '0xFB4AEc4Cc858F2539EBd3D37f2a43eAe5b15b98a', + // variableDebtTokenAddress: '0x0b8f12b1788BFdE65Aa1ca52E3e9F3Ba401be16D', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.LUSD, + aToken: logics.aavev2.mainnetTokens.aLUSD, + stableDebtTokenAddress: '0x39f010127274b2dBdB770B45e1de54d974974526', + variableDebtTokenAddress: '0x411066489AB40442d6Fc215aD7c64224120D33F2', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.MANA, + // aToken: logics.aavev2.mainnetTokens.aMANA, + // stableDebtTokenAddress: '0xD86C74eA2224f4B8591560652b50035E4e5c0a3b', + // variableDebtTokenAddress: '0x0A68976301e46Ca6Ce7410DB28883E309EA0D352', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.MKR, + // aToken: logics.aavev2.mainnetTokens.aMKR, + // stableDebtTokenAddress: '0xC01C8E4b12a89456a9fD4e4e75B72546Bf53f0B5', + // variableDebtTokenAddress: '0xba728eAd5e496BE00DCF66F650b6d7758eCB50f8', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.RAI, + // aToken: logics.aavev2.mainnetTokens.aRAI, + // stableDebtTokenAddress: '0x9C72B8476C33AE214ee3e8C20F0bc28496a62032', + // variableDebtTokenAddress: '0xB5385132EE8321977FfF44b60cDE9fE9AB0B4e6b', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.REN, + // aToken: logics.aavev2.mainnetTokens.aREN, + // stableDebtTokenAddress: '0x3356Ec1eFA75d9D150Da1EC7d944D9EDf73703B7', + // variableDebtTokenAddress: '0xcd9D82d33bd737De215cDac57FE2F7f04DF77FE0', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.SNX, + // aToken: logics.aavev2.mainnetTokens.aSNX, + // stableDebtTokenAddress: '0x8575c8ae70bDB71606A53AeA1c6789cB0fBF3166', + // variableDebtTokenAddress: '0x267EB8Cf715455517F9BD5834AeAE3CeA1EBdbD8', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.TUSD, + aToken: logics.aavev2.mainnetTokens.aTUSD, + stableDebtTokenAddress: '0x7f38d60D94652072b2C44a18c0e14A481EC3C0dd', + variableDebtTokenAddress: '0x01C0eb1f8c6F1C1bF74ae028697ce7AA2a8b0E92', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.UNI, + // aToken: logics.aavev2.mainnetTokens.aUNI, + // stableDebtTokenAddress: '0xD939F7430dC8D5a427f156dE1012A56C18AcB6Aa', + // variableDebtTokenAddress: '0x5BdB050A92CADcCfCDcCCBFC17204a1C9cC0Ab73', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.USDC, + aToken: logics.aavev2.mainnetTokens.aUSDC, + stableDebtTokenAddress: '0xE4922afAB0BbaDd8ab2a88E0C79d884Ad337fcA6', + variableDebtTokenAddress: '0x619beb58998eD2278e08620f97007e1116D5D25b', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + { + asset: logics.aavev2.mainnetTokens.USDT, + aToken: logics.aavev2.mainnetTokens.aUSDT, + stableDebtTokenAddress: '0xe91D55AB2240594855aBd11b3faAE801Fd4c4687', + variableDebtTokenAddress: '0x531842cEbbdD378f8ee36D171d6cC9C4fcf475Ec', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + { + asset: logics.aavev2.mainnetTokens.WETH, + aToken: logics.aavev2.mainnetTokens.aWETH, + stableDebtTokenAddress: '0x4e977830ba4bd783C0BB7F15d3e243f73FF57121', + variableDebtTokenAddress: '0xF63B34710400CAd3e044cFfDcAb00a0f32E33eCf', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + { + asset: logics.aavev2.mainnetTokens.WBTC, + aToken: logics.aavev2.mainnetTokens.aWBTC, + stableDebtTokenAddress: '0x51B039b9AFE64B78758f8Ef091211b5387eA717c', + variableDebtTokenAddress: '0x9c39809Dec7F95F5e0713634a4D0701329B3b4d2', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.YFI, + // aToken: logics.aavev2.mainnetTokens.aYFI, + // stableDebtTokenAddress: '0xca823F78C2Dd38993284bb42Ba9b14152082F7BD', + // variableDebtTokenAddress: '0x7EbD09022Be45AD993BAA1CEc61166Fcc8644d97', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.ZRX, + // aToken: logics.aavev2.mainnetTokens.aZRX, + // stableDebtTokenAddress: '0x071B4323a24E73A5afeEbe34118Cd21B8FAAF7C3', + // variableDebtTokenAddress: '0x85791D117A392097590bDeD3bD5abB8d5A20491A', + // used: { withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.renFIL, + // aToken: logics.aavev2.mainnetTokens.aRENFIL, + // stableDebtTokenAddress: '0xcAad05C49E14075077915cB5C820EB3245aFb950', + // variableDebtTokenAddress: '0x348e2eBD5E962854871874E444F4122399c02755', + // used: { withdraw: true, repay: true }, + // }, + { + asset: logics.aavev2.mainnetTokens.sUSD, + aToken: logics.aavev2.mainnetTokens.aSUSD, + stableDebtTokenAddress: '0x30B0f7324feDF89d8eff397275F8983397eFe4af', + variableDebtTokenAddress: '0xdC6a3Ab17299D9C2A412B0e0a4C1f55446AE0817', + used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + }, + // { + // asset: logics.aavev2.mainnetTokens.stETH, + // aToken: logics.aavev2.mainnetTokens.astETH, + // stableDebtTokenAddress: '0x66457616Dd8489dF5D0AFD8678F4A260088aAF55', + // variableDebtTokenAddress: '0xA9DEAc9f00Dc4310c35603FCD9D34d1A750f81Db', + // used: { deposit: true, withdraw: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.xSUSHI, + // aToken: logics.aavev2.mainnetTokens.aXSUSHI, + // stableDebtTokenAddress: '0x73Bfb81D7dbA75C904f430eA8BAe82DB0D41187B', + // variableDebtTokenAddress: '0xfAFEDF95E21184E3d880bd56D4806c4b8d31c69A', + // used: { deposit: true, withdraw: true, repay: true }, + // }, + // { + // asset: logics.aavev2.mainnetTokens.PAX, + // aToken: logics.aavev2.mainnetTokens.aUSDP, + // stableDebtTokenAddress: '0x2387119bc85A74e0BBcbe190d80676CB16F10D4F', + // variableDebtTokenAddress: '0xFDb93B3b10936cf81FA59A02A7523B6e2149b2B7', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + ], + }, + // https://github.com/bgd-labs/aave-address-book/blob/main/src/AaveV2Polygon.sol + // { + // chainId: common.ChainId.polygon, + // contractMap: { + // LendingPool: '0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf', + // ProtocolDataProvider: '0x7551b5D2763519d4e37e8B81929D336De671d46d', + // PriceOracle: '0x0229F777B0fAb107F9591a41d5F02E4e98dB6f2d', + // ETHPriceFeed: '0xF9680D99D6C9589e2a93a78A04A279e509205945', + // }, + // reserves: [ + // { + // asset: logics.aavev2.polygonTokens.AAVE, + // aToken: logics.aavev2.polygonTokens.amAAVE, + // stableDebtTokenAddress: '0x17912140e780B29Ba01381F088f21E8d75F954F9', + // variableDebtTokenAddress: '0x1c313e9d0d826662F5CE692134D938656F681350', + // used: { deposit: true, withdraw: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.BAL, + // aToken: logics.aavev2.polygonTokens.amBAL, + // stableDebtTokenAddress: '0xbC30bbe0472E0E86b6f395f9876B950A13B23923', + // variableDebtTokenAddress: '0x773E0e32e7b6a00b7cA9daa85dfba9D61B7f2574', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.CRV, + // aToken: logics.aavev2.polygonTokens.amCRV, + // stableDebtTokenAddress: '0x807c97744e6C9452e7C2914d78f49d171a9974a0', + // variableDebtTokenAddress: '0x780BbcBCda2cdb0d2c61fd9BC68c9046B18f3229', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.DAI, + // aToken: logics.aavev2.polygonTokens.amDAI, + // stableDebtTokenAddress: '0x2238101B7014C279aaF6b408A284E49cDBd5DB55', + // variableDebtTokenAddress: '0x75c4d1Fb84429023170086f06E682DcbBF537b7d', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.DPI, + // aToken: logics.aavev2.polygonTokens.amDPI, + // stableDebtTokenAddress: '0xA742710c0244a8Ebcf533368e3f0B956B6E53F7B', + // variableDebtTokenAddress: '0x43150AA0B7e19293D935A412C8607f9172d3d3f3', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.GHST, + // aToken: logics.aavev2.polygonTokens.amGHST, + // stableDebtTokenAddress: '0x6A01Db46Ae51B19A6B85be38f1AA102d8735d05b', + // variableDebtTokenAddress: '0x36e988a38542C3482013Bb54ee46aC1fb1efedcd', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.LINK, + // aToken: logics.aavev2.polygonTokens.amLINK, + // stableDebtTokenAddress: '0x9fb7F546E60DDFaA242CAeF146FA2f4172088117', + // variableDebtTokenAddress: '0xCC71e4A38c974e19bdBC6C0C19b63b8520b1Bb09', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.MATIC, + // aToken: logics.aavev2.polygonTokens.amWMATIC, + // stableDebtTokenAddress: '0xb9A6E29fB540C5F1243ef643EB39b0AcbC2e68E3', + // variableDebtTokenAddress: '0x59e8E9100cbfCBCBAdf86b9279fa61526bBB8765', + // used: { deposit: true, withdraw: true, borrow: true, repay: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.SUSHI, + // aToken: logics.aavev2.polygonTokens.amSUSHI, + // stableDebtTokenAddress: '0x7Ed588DCb30Ea11A54D8a5E9645960262A97cd54', + // variableDebtTokenAddress: '0x9CB9fEaFA73bF392C905eEbf5669ad3d073c3DFC', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.USDC, + // aToken: logics.aavev2.polygonTokens.amUSDC, + // stableDebtTokenAddress: '0xdeb05676dB0DB85cecafE8933c903466Bf20C572', + // variableDebtTokenAddress: '0x248960A9d75EdFa3de94F7193eae3161Eb349a12', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.USDT, + // aToken: logics.aavev2.polygonTokens.amUSDT, + // stableDebtTokenAddress: '0xe590cfca10e81FeD9B0e4496381f02256f5d2f61', + // variableDebtTokenAddress: '0x8038857FD47108A07d1f6Bf652ef1cBeC279A2f3', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.WBTC, + // aToken: logics.aavev2.polygonTokens.amWBTC, + // stableDebtTokenAddress: '0x2551B15dB740dB8348bFaDFe06830210eC2c2F13', + // variableDebtTokenAddress: '0xF664F50631A6f0D72ecdaa0e49b0c019Fa72a8dC', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.WETH, + // aToken: logics.aavev2.polygonTokens.amWETH, + // stableDebtTokenAddress: '0xc478cBbeB590C76b01ce658f8C4dda04f30e2C6f', + // variableDebtTokenAddress: '0xeDe17e9d79fc6f9fF9250D9EEfbdB88Cc18038b5', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // { + // asset: logics.aavev2.polygonTokens.WMATIC, + // aToken: logics.aavev2.polygonTokens.amWMATIC, + // stableDebtTokenAddress: '0xb9A6E29fB540C5F1243ef643EB39b0AcbC2e68E3', + // variableDebtTokenAddress: '0x59e8E9100cbfCBCBAdf86b9279fa61526bBB8765', + // used: { deposit: true, withdraw: true, borrow: true, repay: true, flashLoan: true }, + // }, + // ], + // }, +]; + +export const [ + supportedChainIds, + configMap, + reserveMap, + tokensForDepositMap, + aTokensForDepositMap, + tokensForWithdrawMap, + aTokensForWithdrawMap, + tokensForBorrowMap, + tokensForRepayMap, + tokensForFlashLoanMap, +] = configs.reduce( + (accumulator, config) => { + const { chainId, reserves } = config; + + accumulator[0].push(chainId); + accumulator[1][chainId] = config; + accumulator[2][chainId] = {}; + accumulator[3][chainId] = []; + accumulator[4][chainId] = []; + accumulator[5][chainId] = []; + accumulator[6][chainId] = []; + accumulator[7][chainId] = []; + accumulator[8][chainId] = []; + accumulator[9][chainId] = []; + for (const reserve of reserves) { + const { asset, aToken, stableDebtTokenAddress, variableDebtTokenAddress, used } = reserve; + if (!isNativeToken(chainId, asset)) { + accumulator[2][chainId][asset.address] = reserve; + if (aToken) accumulator[2][chainId][aToken.address] = reserve; + accumulator[2][chainId][stableDebtTokenAddress] = reserve; + accumulator[2][chainId][variableDebtTokenAddress] = reserve; + } + + if (used.deposit) { + accumulator[3][chainId].push(asset); + if (aToken) accumulator[4][chainId].push(aToken); + } + if (used.withdraw) { + accumulator[5][chainId].push(asset); + if (aToken) accumulator[6][chainId].push(aToken); + } + if (used.borrow) accumulator[7][chainId].push(asset); + if (used.repay) accumulator[8][chainId].push(asset); + if (used.flashLoan) accumulator[9][chainId].push(asset); + } + accumulator[6][chainId] = Array.from(new Set(accumulator[6][chainId])); // uniq aToken + + return accumulator; + }, + [[], {}, {}, {}, {}, {}, {}, {}, {}, {}] as [ + number[], + Record, + Record>, + Record, + Record, + Record, + Record, + Record, + Record, + Record + ] +); + +export function getContractAddress(chainId: number, name: ContractName) { + return configMap[chainId].contractMap[name]; +} + +export function toAToken(chainId: number, token: common.Token) { + return reserveMap[chainId][wrapToken(chainId, token).address].aToken; +} + +export function isAToken(chainId: number, token: common.Token): boolean { + const aToken = reserveMap[chainId][token.address].aToken; + return aToken.is(token); +} + +export function toToken(chainId: number, aToken: common.Token, unwrap = true) { + const asset = reserveMap[chainId][aToken.address].asset; + return unwrap ? unwrapToken(chainId, asset) : asset; +} + +export function getDebtTokenAddress(chainId: number, token: common.Token, rateMode: RateMode): string { + const reserve = reserveMap[chainId][wrapToken(chainId, token).address]; + return rateMode === RateMode.STABLE ? reserve.stableDebtTokenAddress : reserve.variableDebtTokenAddress; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/AToken.ts b/packages/lending/src/protocols/aave-v2/contracts/AToken.ts new file mode 100644 index 00000000..ef312a06 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/AToken.ts @@ -0,0 +1,64 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface ATokenInterface extends utils.Interface { + functions: { + 'scaledBalanceOf(address)': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'scaledBalanceOf'): FunctionFragment; + + encodeFunctionData(functionFragment: 'scaledBalanceOf', values: [string]): string; + + decodeFunctionResult(functionFragment: 'scaledBalanceOf', data: BytesLike): Result; + + events: {}; +} + +export interface AToken extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: ATokenInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + scaledBalanceOf(user: string, overrides?: CallOverrides): Promise<[BigNumber]>; + }; + + scaledBalanceOf(user: string, overrides?: CallOverrides): Promise; + + callStatic: { + scaledBalanceOf(user: string, overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + scaledBalanceOf(user: string, overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + scaledBalanceOf(user: string, overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/DebtToken.ts b/packages/lending/src/protocols/aave-v2/contracts/DebtToken.ts new file mode 100644 index 00000000..4ff065eb --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/DebtToken.ts @@ -0,0 +1,104 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumber, + BigNumberish, + BytesLike, + CallOverrides, + ContractTransaction, + Overrides, + PopulatedTransaction, + Signer, + utils, +} from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface DebtTokenInterface extends utils.Interface { + functions: { + 'approveDelegation(address,uint256)': FunctionFragment; + 'borrowAllowance(address,address)': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'approveDelegation' | 'borrowAllowance'): FunctionFragment; + + encodeFunctionData(functionFragment: 'approveDelegation', values: [string, BigNumberish]): string; + encodeFunctionData(functionFragment: 'borrowAllowance', values: [string, string]): string; + + decodeFunctionResult(functionFragment: 'approveDelegation', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'borrowAllowance', data: BytesLike): Result; + + events: {}; +} + +export interface DebtToken extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: DebtTokenInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + approveDelegation( + delegatee: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string } + ): Promise; + + borrowAllowance(fromUser: string, toUser: string, overrides?: CallOverrides): Promise<[BigNumber]>; + }; + + approveDelegation( + delegatee: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string } + ): Promise; + + borrowAllowance(fromUser: string, toUser: string, overrides?: CallOverrides): Promise; + + callStatic: { + approveDelegation(delegatee: string, amount: BigNumberish, overrides?: CallOverrides): Promise; + + borrowAllowance(fromUser: string, toUser: string, overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + approveDelegation( + delegatee: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string } + ): Promise; + + borrowAllowance(fromUser: string, toUser: string, overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + approveDelegation( + delegatee: string, + amount: BigNumberish, + overrides?: Overrides & { from?: string } + ): Promise; + + borrowAllowance(fromUser: string, toUser: string, overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/ETHPriceFeed.ts b/packages/lending/src/protocols/aave-v2/contracts/ETHPriceFeed.ts new file mode 100644 index 00000000..8c1bca17 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/ETHPriceFeed.ts @@ -0,0 +1,64 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface ETHPriceFeedInterface extends utils.Interface { + functions: { + 'latestAnswer()': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'latestAnswer'): FunctionFragment; + + encodeFunctionData(functionFragment: 'latestAnswer', values?: undefined): string; + + decodeFunctionResult(functionFragment: 'latestAnswer', data: BytesLike): Result; + + events: {}; +} + +export interface ETHPriceFeed extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: ETHPriceFeedInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + latestAnswer(overrides?: CallOverrides): Promise<[BigNumber]>; + }; + + latestAnswer(overrides?: CallOverrides): Promise; + + callStatic: { + latestAnswer(overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + latestAnswer(overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + latestAnswer(overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/LendingPool.ts b/packages/lending/src/protocols/aave-v2/contracts/LendingPool.ts new file mode 100644 index 00000000..21acb8a1 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/LendingPool.ts @@ -0,0 +1,188 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumber, + BigNumberish, + BytesLike, + CallOverrides, + PopulatedTransaction, + Signer, + utils, +} from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export declare namespace DataTypes { + export type ReserveConfigurationMapStruct = { data: BigNumberish }; + + export type ReserveConfigurationMapStructOutput = [BigNumber] & { + data: BigNumber; + }; + + export type ReserveDataStruct = { + configuration: DataTypes.ReserveConfigurationMapStruct; + liquidityIndex: BigNumberish; + variableBorrowIndex: BigNumberish; + currentLiquidityRate: BigNumberish; + currentVariableBorrowRate: BigNumberish; + currentStableBorrowRate: BigNumberish; + lastUpdateTimestamp: BigNumberish; + aTokenAddress: string; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + interestRateStrategyAddress: string; + id: BigNumberish; + }; + + export type ReserveDataStructOutput = [ + DataTypes.ReserveConfigurationMapStructOutput, + BigNumber, + BigNumber, + BigNumber, + BigNumber, + BigNumber, + number, + string, + string, + string, + string, + number + ] & { + configuration: DataTypes.ReserveConfigurationMapStructOutput; + liquidityIndex: BigNumber; + variableBorrowIndex: BigNumber; + currentLiquidityRate: BigNumber; + currentVariableBorrowRate: BigNumber; + currentStableBorrowRate: BigNumber; + lastUpdateTimestamp: number; + aTokenAddress: string; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + interestRateStrategyAddress: string; + id: number; + }; +} + +export interface LendingPoolInterface extends utils.Interface { + functions: { + 'FLASHLOAN_PREMIUM_TOTAL()': FunctionFragment; + 'getReserveData(address)': FunctionFragment; + 'getUserAccountData(address)': FunctionFragment; + }; + + getFunction( + nameOrSignatureOrTopic: 'FLASHLOAN_PREMIUM_TOTAL' | 'getReserveData' | 'getUserAccountData' + ): FunctionFragment; + + encodeFunctionData(functionFragment: 'FLASHLOAN_PREMIUM_TOTAL', values?: undefined): string; + encodeFunctionData(functionFragment: 'getReserveData', values: [string]): string; + encodeFunctionData(functionFragment: 'getUserAccountData', values: [string]): string; + + decodeFunctionResult(functionFragment: 'FLASHLOAN_PREMIUM_TOTAL', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getReserveData', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getUserAccountData', data: BytesLike): Result; + + events: {}; +} + +export interface LendingPool extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: LendingPoolInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + FLASHLOAN_PREMIUM_TOTAL(overrides?: CallOverrides): Promise<[BigNumber]>; + + getReserveData(asset: string, overrides?: CallOverrides): Promise<[DataTypes.ReserveDataStructOutput]>; + + getUserAccountData( + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber] & { + totalCollateralETH: BigNumber; + totalDebtETH: BigNumber; + availableBorrowsETH: BigNumber; + currentLiquidationThreshold: BigNumber; + ltv: BigNumber; + healthFactor: BigNumber; + } + >; + }; + + FLASHLOAN_PREMIUM_TOTAL(overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserAccountData( + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber] & { + totalCollateralETH: BigNumber; + totalDebtETH: BigNumber; + availableBorrowsETH: BigNumber; + currentLiquidationThreshold: BigNumber; + ltv: BigNumber; + healthFactor: BigNumber; + } + >; + + callStatic: { + FLASHLOAN_PREMIUM_TOTAL(overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserAccountData( + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber] & { + totalCollateralETH: BigNumber; + totalDebtETH: BigNumber; + availableBorrowsETH: BigNumber; + currentLiquidationThreshold: BigNumber; + ltv: BigNumber; + healthFactor: BigNumber; + } + >; + }; + + filters: {}; + + estimateGas: { + FLASHLOAN_PREMIUM_TOTAL(overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserAccountData(user: string, overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + FLASHLOAN_PREMIUM_TOTAL(overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserAccountData(user: string, overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/PriceFeed.ts b/packages/lending/src/protocols/aave-v2/contracts/PriceFeed.ts new file mode 100644 index 00000000..35c6312b --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/PriceFeed.ts @@ -0,0 +1,64 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface PriceFeedInterface extends utils.Interface { + functions: { + 'latestAnswer()': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'latestAnswer'): FunctionFragment; + + encodeFunctionData(functionFragment: 'latestAnswer', values?: undefined): string; + + decodeFunctionResult(functionFragment: 'latestAnswer', data: BytesLike): Result; + + events: {}; +} + +export interface PriceFeed extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: PriceFeedInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + latestAnswer(overrides?: CallOverrides): Promise<[BigNumber]>; + }; + + latestAnswer(overrides?: CallOverrides): Promise; + + callStatic: { + latestAnswer(overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + latestAnswer(overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + latestAnswer(overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/PriceOracle.ts b/packages/lending/src/protocols/aave-v2/contracts/PriceOracle.ts new file mode 100644 index 00000000..1fa1d863 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/PriceOracle.ts @@ -0,0 +1,77 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface PriceOracleInterface extends utils.Interface { + functions: { + 'getAssetPrice(address)': FunctionFragment; + 'getAssetsPrices(address[])': FunctionFragment; + }; + + getFunction(nameOrSignatureOrTopic: 'getAssetPrice' | 'getAssetsPrices'): FunctionFragment; + + encodeFunctionData(functionFragment: 'getAssetPrice', values: [string]): string; + encodeFunctionData(functionFragment: 'getAssetsPrices', values: [string[]]): string; + + decodeFunctionResult(functionFragment: 'getAssetPrice', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getAssetsPrices', data: BytesLike): Result; + + events: {}; +} + +export interface PriceOracle extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: PriceOracleInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + getAssetPrice(asset: string, overrides?: CallOverrides): Promise<[BigNumber]>; + + getAssetsPrices(assets: string[], overrides?: CallOverrides): Promise<[BigNumber[]]>; + }; + + getAssetPrice(asset: string, overrides?: CallOverrides): Promise; + + getAssetsPrices(assets: string[], overrides?: CallOverrides): Promise; + + callStatic: { + getAssetPrice(asset: string, overrides?: CallOverrides): Promise; + + getAssetsPrices(assets: string[], overrides?: CallOverrides): Promise; + }; + + filters: {}; + + estimateGas: { + getAssetPrice(asset: string, overrides?: CallOverrides): Promise; + + getAssetsPrices(assets: string[], overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + getAssetPrice(asset: string, overrides?: CallOverrides): Promise; + + getAssetsPrices(assets: string[], overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/ProtocolDataProvider.ts b/packages/lending/src/protocols/aave-v2/contracts/ProtocolDataProvider.ts new file mode 100644 index 00000000..680dbaf8 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/ProtocolDataProvider.ts @@ -0,0 +1,280 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { FunctionFragment, Result } from '@ethersproject/abi'; +import type { Listener, Provider } from '@ethersproject/providers'; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; + +export interface ProtocolDataProviderInterface extends utils.Interface { + functions: { + 'getReserveConfigurationData(address)': FunctionFragment; + 'getReserveTokensAddresses(address)': FunctionFragment; + 'getReserveData(address)': FunctionFragment; + 'getUserReserveData(address,address)': FunctionFragment; + }; + + getFunction( + nameOrSignatureOrTopic: + | 'getReserveConfigurationData' + | 'getReserveTokensAddresses' + | 'getReserveData' + | 'getUserReserveData' + ): FunctionFragment; + + encodeFunctionData(functionFragment: 'getReserveConfigurationData', values: [string]): string; + encodeFunctionData(functionFragment: 'getReserveTokensAddresses', values: [string]): string; + encodeFunctionData(functionFragment: 'getReserveData', values: [string]): string; + encodeFunctionData(functionFragment: 'getUserReserveData', values: [string, string]): string; + + decodeFunctionResult(functionFragment: 'getReserveConfigurationData', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getReserveTokensAddresses', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getReserveData', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getUserReserveData', data: BytesLike): Result; + + events: {}; +} + +export interface ProtocolDataProvider extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: ProtocolDataProviderInterface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + getReserveConfigurationData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, boolean, boolean, boolean, boolean, boolean] & { + decimals: BigNumber; + ltv: BigNumber; + liquidationThreshold: BigNumber; + liquidationBonus: BigNumber; + reserveFactor: BigNumber; + usageAsCollateralEnabled: boolean; + borrowingEnabled: boolean; + stableBorrowRateEnabled: boolean; + isActive: boolean; + isFrozen: boolean; + } + >; + + getReserveTokensAddresses( + asset: string, + overrides?: CallOverrides + ): Promise< + [string, string, string] & { + aTokenAddress: string; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + } + >; + + getReserveData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number] & { + availableLiquidity: BigNumber; + totalStableDebt: BigNumber; + totalVariableDebt: BigNumber; + liquidityRate: BigNumber; + variableBorrowRate: BigNumber; + stableBorrowRate: BigNumber; + averageStableBorrowRate: BigNumber; + liquidityIndex: BigNumber; + variableBorrowIndex: BigNumber; + lastUpdateTimestamp: number; + } + >; + + getUserReserveData( + asset: string, + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number, boolean] & { + currentATokenBalance: BigNumber; + currentStableDebt: BigNumber; + currentVariableDebt: BigNumber; + principalStableDebt: BigNumber; + scaledVariableDebt: BigNumber; + stableBorrowRate: BigNumber; + liquidityRate: BigNumber; + stableRateLastUpdated: number; + usageAsCollateralEnabled: boolean; + } + >; + }; + + getReserveConfigurationData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, boolean, boolean, boolean, boolean, boolean] & { + decimals: BigNumber; + ltv: BigNumber; + liquidationThreshold: BigNumber; + liquidationBonus: BigNumber; + reserveFactor: BigNumber; + usageAsCollateralEnabled: boolean; + borrowingEnabled: boolean; + stableBorrowRateEnabled: boolean; + isActive: boolean; + isFrozen: boolean; + } + >; + + getReserveTokensAddresses( + asset: string, + overrides?: CallOverrides + ): Promise< + [string, string, string] & { + aTokenAddress: string; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + } + >; + + getReserveData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number] & { + availableLiquidity: BigNumber; + totalStableDebt: BigNumber; + totalVariableDebt: BigNumber; + liquidityRate: BigNumber; + variableBorrowRate: BigNumber; + stableBorrowRate: BigNumber; + averageStableBorrowRate: BigNumber; + liquidityIndex: BigNumber; + variableBorrowIndex: BigNumber; + lastUpdateTimestamp: number; + } + >; + + getUserReserveData( + asset: string, + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number, boolean] & { + currentATokenBalance: BigNumber; + currentStableDebt: BigNumber; + currentVariableDebt: BigNumber; + principalStableDebt: BigNumber; + scaledVariableDebt: BigNumber; + stableBorrowRate: BigNumber; + liquidityRate: BigNumber; + stableRateLastUpdated: number; + usageAsCollateralEnabled: boolean; + } + >; + + callStatic: { + getReserveConfigurationData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, boolean, boolean, boolean, boolean, boolean] & { + decimals: BigNumber; + ltv: BigNumber; + liquidationThreshold: BigNumber; + liquidationBonus: BigNumber; + reserveFactor: BigNumber; + usageAsCollateralEnabled: boolean; + borrowingEnabled: boolean; + stableBorrowRateEnabled: boolean; + isActive: boolean; + isFrozen: boolean; + } + >; + + getReserveTokensAddresses( + asset: string, + overrides?: CallOverrides + ): Promise< + [string, string, string] & { + aTokenAddress: string; + stableDebtTokenAddress: string; + variableDebtTokenAddress: string; + } + >; + + getReserveData( + asset: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number] & { + availableLiquidity: BigNumber; + totalStableDebt: BigNumber; + totalVariableDebt: BigNumber; + liquidityRate: BigNumber; + variableBorrowRate: BigNumber; + stableBorrowRate: BigNumber; + averageStableBorrowRate: BigNumber; + liquidityIndex: BigNumber; + variableBorrowIndex: BigNumber; + lastUpdateTimestamp: number; + } + >; + + getUserReserveData( + asset: string, + user: string, + overrides?: CallOverrides + ): Promise< + [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, number, boolean] & { + currentATokenBalance: BigNumber; + currentStableDebt: BigNumber; + currentVariableDebt: BigNumber; + principalStableDebt: BigNumber; + scaledVariableDebt: BigNumber; + stableBorrowRate: BigNumber; + liquidityRate: BigNumber; + stableRateLastUpdated: number; + usageAsCollateralEnabled: boolean; + } + >; + }; + + filters: {}; + + estimateGas: { + getReserveConfigurationData(asset: string, overrides?: CallOverrides): Promise; + + getReserveTokensAddresses(asset: string, overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserReserveData(asset: string, user: string, overrides?: CallOverrides): Promise; + }; + + populateTransaction: { + getReserveConfigurationData(asset: string, overrides?: CallOverrides): Promise; + + getReserveTokensAddresses(asset: string, overrides?: CallOverrides): Promise; + + getReserveData(asset: string, overrides?: CallOverrides): Promise; + + getUserReserveData(asset: string, user: string, overrides?: CallOverrides): Promise; + }; +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/common.ts b/packages/lending/src/protocols/aave-v2/contracts/common.ts new file mode 100644 index 00000000..6cfb1042 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/common.ts @@ -0,0 +1,30 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { Listener } from '@ethersproject/providers'; +import type { Event, EventFilter } from 'ethers'; + +export interface TypedEvent = any, TArgsObject = any> extends Event { + args: TArgsArray & TArgsObject; +} + +export interface TypedEventFilter<_TEvent extends TypedEvent> extends EventFilter {} + +export interface TypedListener { + (...listenerArg: [...__TypechainArgsArray, TEvent]): void; +} + +type __TypechainArgsArray = T extends TypedEvent ? U : never; + +export interface OnEvent { + (eventFilter: TypedEventFilter, listener: TypedListener): TRes; + (eventName: string, listener: Listener): TRes; +} + +export type MinEthersFactory = { + deploy(...a: ARGS[]): Promise; +}; + +export type GetContractTypeFromFactory = F extends MinEthersFactory ? C : never; + +export type GetARGsTypeFromFactory = F extends MinEthersFactory ? Parameters : never; diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/AToken__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/AToken__factory.ts new file mode 100644 index 00000000..3a879271 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/AToken__factory.ts @@ -0,0 +1,39 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { AToken, ATokenInterface } from '../AToken'; + +const _abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'user', + type: 'address', + }, + ], + name: 'scaledBalanceOf', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class AToken__factory { + static readonly abi = _abi; + static createInterface(): ATokenInterface { + return new utils.Interface(_abi) as ATokenInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): AToken { + return new Contract(address, _abi, signerOrProvider) as AToken; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/DebtToken__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/DebtToken__factory.ts new file mode 100644 index 00000000..ce2026f2 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/DebtToken__factory.ts @@ -0,0 +1,62 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { DebtToken, DebtTokenInterface } from '../DebtToken'; + +const _abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'delegatee', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'approveDelegation', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'fromUser', + type: 'address', + }, + { + internalType: 'address', + name: 'toUser', + type: 'address', + }, + ], + name: 'borrowAllowance', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class DebtToken__factory { + static readonly abi = _abi; + static createInterface(): DebtTokenInterface { + return new utils.Interface(_abi) as DebtTokenInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): DebtToken { + return new Contract(address, _abi, signerOrProvider) as DebtToken; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/ETHPriceFeed__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/ETHPriceFeed__factory.ts new file mode 100644 index 00000000..b6587347 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/ETHPriceFeed__factory.ts @@ -0,0 +1,33 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { ETHPriceFeed, ETHPriceFeedInterface } from '../ETHPriceFeed'; + +const _abi = [ + { + inputs: [], + name: 'latestAnswer', + outputs: [ + { + internalType: 'int256', + name: '', + type: 'int256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class ETHPriceFeed__factory { + static readonly abi = _abi; + static createInterface(): ETHPriceFeedInterface { + return new utils.Interface(_abi) as ETHPriceFeedInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): ETHPriceFeed { + return new Contract(address, _abi, signerOrProvider) as ETHPriceFeed; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/LendingPool__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/LendingPool__factory.ts new file mode 100644 index 00000000..f8730543 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/LendingPool__factory.ts @@ -0,0 +1,165 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { LendingPool, LendingPoolInterface } from '../LendingPool'; + +const _abi = [ + { + inputs: [], + name: 'FLASHLOAN_PREMIUM_TOTAL', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + name: 'getReserveData', + outputs: [ + { + components: [ + { + components: [ + { + internalType: 'uint256', + name: 'data', + type: 'uint256', + }, + ], + internalType: 'struct DataTypes.ReserveConfigurationMap', + name: 'configuration', + type: 'tuple', + }, + { + internalType: 'uint128', + name: 'liquidityIndex', + type: 'uint128', + }, + { + internalType: 'uint128', + name: 'variableBorrowIndex', + type: 'uint128', + }, + { + internalType: 'uint128', + name: 'currentLiquidityRate', + type: 'uint128', + }, + { + internalType: 'uint128', + name: 'currentVariableBorrowRate', + type: 'uint128', + }, + { + internalType: 'uint128', + name: 'currentStableBorrowRate', + type: 'uint128', + }, + { + internalType: 'uint40', + name: 'lastUpdateTimestamp', + type: 'uint40', + }, + { + internalType: 'address', + name: 'aTokenAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'stableDebtTokenAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'variableDebtTokenAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'interestRateStrategyAddress', + type: 'address', + }, + { + internalType: 'uint8', + name: 'id', + type: 'uint8', + }, + ], + internalType: 'struct DataTypes.ReserveData', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'user', + type: 'address', + }, + ], + name: 'getUserAccountData', + outputs: [ + { + internalType: 'uint256', + name: 'totalCollateralETH', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalDebtETH', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'availableBorrowsETH', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'currentLiquidationThreshold', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'ltv', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'healthFactor', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class LendingPool__factory { + static readonly abi = _abi; + static createInterface(): LendingPoolInterface { + return new utils.Interface(_abi) as LendingPoolInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): LendingPool { + return new Contract(address, _abi, signerOrProvider) as LendingPool; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/PriceFeed__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/PriceFeed__factory.ts new file mode 100644 index 00000000..66ed316e --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/PriceFeed__factory.ts @@ -0,0 +1,33 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { PriceFeed, PriceFeedInterface } from '../PriceFeed'; + +const _abi = [ + { + inputs: [], + name: 'latestAnswer', + outputs: [ + { + internalType: 'int256', + name: '', + type: 'int256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class PriceFeed__factory { + static readonly abi = _abi; + static createInterface(): PriceFeedInterface { + return new utils.Interface(_abi) as PriceFeedInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): PriceFeed { + return new Contract(address, _abi, signerOrProvider) as PriceFeed; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/PriceOracle__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/PriceOracle__factory.ts new file mode 100644 index 00000000..3b9e0183 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/PriceOracle__factory.ts @@ -0,0 +1,58 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { PriceOracle, PriceOracleInterface } from '../PriceOracle'; + +const _abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + name: 'getAssetPrice', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address[]', + name: 'assets', + type: 'address[]', + }, + ], + name: 'getAssetsPrices', + outputs: [ + { + internalType: 'uint256[]', + name: '', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class PriceOracle__factory { + static readonly abi = _abi; + static createInterface(): PriceOracleInterface { + return new utils.Interface(_abi) as PriceOracleInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): PriceOracle { + return new Contract(address, _abi, signerOrProvider) as PriceOracle; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/ProtocolDataProvider__factory.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/ProtocolDataProvider__factory.ts new file mode 100644 index 00000000..f57da3ef --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/ProtocolDataProvider__factory.ts @@ -0,0 +1,241 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from 'ethers'; +import type { Provider } from '@ethersproject/providers'; +import type { ProtocolDataProvider, ProtocolDataProviderInterface } from '../ProtocolDataProvider'; + +const _abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + name: 'getReserveConfigurationData', + outputs: [ + { + internalType: 'uint256', + name: 'decimals', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'ltv', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidationThreshold', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidationBonus', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'reserveFactor', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'usageAsCollateralEnabled', + type: 'bool', + }, + { + internalType: 'bool', + name: 'borrowingEnabled', + type: 'bool', + }, + { + internalType: 'bool', + name: 'stableBorrowRateEnabled', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isActive', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isFrozen', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + name: 'getReserveTokensAddresses', + outputs: [ + { + internalType: 'address', + name: 'aTokenAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'stableDebtTokenAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'variableDebtTokenAddress', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + name: 'getReserveData', + outputs: [ + { + internalType: 'uint256', + name: 'availableLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalStableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalVariableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'variableBorrowRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'stableBorrowRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'averageStableBorrowRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityIndex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'variableBorrowIndex', + type: 'uint256', + }, + { + internalType: 'uint40', + name: 'lastUpdateTimestamp', + type: 'uint40', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + { + internalType: 'address', + name: 'user', + type: 'address', + }, + ], + name: 'getUserReserveData', + outputs: [ + { + internalType: 'uint256', + name: 'currentATokenBalance', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'currentStableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'currentVariableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'principalStableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'scaledVariableDebt', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'stableBorrowRate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityRate', + type: 'uint256', + }, + { + internalType: 'uint40', + name: 'stableRateLastUpdated', + type: 'uint40', + }, + { + internalType: 'bool', + name: 'usageAsCollateralEnabled', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const; + +export class ProtocolDataProvider__factory { + static readonly abi = _abi; + static createInterface(): ProtocolDataProviderInterface { + return new utils.Interface(_abi) as ProtocolDataProviderInterface; + } + static connect(address: string, signerOrProvider: Signer | Provider): ProtocolDataProvider { + return new Contract(address, _abi, signerOrProvider) as ProtocolDataProvider; + } +} diff --git a/packages/lending/src/protocols/aave-v2/contracts/factories/index.ts b/packages/lending/src/protocols/aave-v2/contracts/factories/index.ts new file mode 100644 index 00000000..063f197a --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/factories/index.ts @@ -0,0 +1,9 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export { AToken__factory } from './AToken__factory'; +export { DebtToken__factory } from './DebtToken__factory'; +export { ETHPriceFeed__factory } from './ETHPriceFeed__factory'; +export { LendingPool__factory } from './LendingPool__factory'; +export { PriceOracle__factory } from './PriceOracle__factory'; +export { ProtocolDataProvider__factory } from './ProtocolDataProvider__factory'; diff --git a/packages/lending/src/protocols/aave-v2/contracts/index.ts b/packages/lending/src/protocols/aave-v2/contracts/index.ts new file mode 100644 index 00000000..134a6d9d --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/contracts/index.ts @@ -0,0 +1,16 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export type { AToken } from './AToken'; +export type { DebtToken } from './DebtToken'; +export type { ETHPriceFeed } from './ETHPriceFeed'; +export type { LendingPool } from './LendingPool'; +export type { PriceOracle } from './PriceOracle'; +export type { ProtocolDataProvider } from './ProtocolDataProvider'; +export * as factories from './factories'; +export { AToken__factory } from './factories/AToken__factory'; +export { DebtToken__factory } from './factories/DebtToken__factory'; +export { ETHPriceFeed__factory } from './factories/ETHPriceFeed__factory'; +export { LendingPool__factory } from './factories/LendingPool__factory'; +export { PriceOracle__factory } from './factories/PriceOracle__factory'; +export { ProtocolDataProvider__factory } from './factories/ProtocolDataProvider__factory'; diff --git a/packages/lending/src/protocols/aave-v2/index.ts b/packages/lending/src/protocols/aave-v2/index.ts new file mode 100644 index 00000000..b8c02126 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/index.ts @@ -0,0 +1,2 @@ +export * from './configs'; +export * from './lending-protocol'; diff --git a/packages/lending/src/protocols/aave-v2/lending-protocol.ts b/packages/lending/src/protocols/aave-v2/lending-protocol.ts new file mode 100644 index 00000000..9aebf336 --- /dev/null +++ b/packages/lending/src/protocols/aave-v2/lending-protocol.ts @@ -0,0 +1,365 @@ +import { ATokenInterface } from './contracts/AToken'; +import { + AToken__factory, + ETHPriceFeed, + ETHPriceFeed__factory, + PriceOracle, + PriceOracle__factory, + ProtocolDataProvider, + ProtocolDataProvider__factory, +} from './contracts'; +import { BigNumber, providers } from 'ethers'; +import { BorrowObject, Market, RepayParams, SupplyObject, SupplyParams, WithdrawParams } from 'src/protocol.type'; +import { ETHPriceFeedInterface } from './contracts/ETHPriceFeed'; +import { Portfolio } from 'src/protocol.portfolio'; +import { PriceOracleInterface } from './contracts/PriceOracle'; +import { Protocol } from 'src/protocol'; +import { ProtocolDataProviderInterface } from './contracts/ProtocolDataProvider'; +import { RAY_DECIMALS, SECONDS_PER_YEAR, calculateCompoundedRate, normalize } from '@aave/math-utils'; +import * as common from '@protocolink/common'; +import { + configMap, + getContractAddress, + isAToken, + supportedChainIds, + toAToken, + toToken, + tokensForBorrowMap, + tokensForDepositMap, +} from './configs'; +import { isWrappedNativeToken, wrapToken } from 'src/helper'; +import { protocols } from '@protocolink/api'; + +const NAME = 'aavev2'; +const displayName = 'Aave V2'; +// const supportedChainIds = [1]; + +export class LendingProtocol extends Protocol { + static readonly markets = supportedChainIds.map((chainId) => ({ + id: common.toNetworkId(chainId), + chainId, + })); + + readonly id = NAME; + readonly market: Market; + readonly isAaveLike = true; + + constructor(chainId: number, provider?: providers.Provider) { + super(chainId, provider); + this.market = LendingProtocol.markets.find((market) => market.chainId === this.chainId)!; + } + + private _protocolDataProvider?: ProtocolDataProvider; + + get protocolDataProvider() { + if (!this._protocolDataProvider) { + this._protocolDataProvider = ProtocolDataProvider__factory.connect( + getContractAddress(this.chainId, 'ProtocolDataProvider'), + this.provider + ); + } + return this._protocolDataProvider; + } + + private _protocolDataProviderIface?: ProtocolDataProviderInterface; + + get protocolDataProviderIface() { + if (!this._protocolDataProviderIface) { + this._protocolDataProviderIface = ProtocolDataProvider__factory.createInterface(); + } + return this._protocolDataProviderIface; + } + + private _priceOracle?: PriceOracle; + + get priceOracle() { + if (!this._priceOracle) { + this._priceOracle = PriceOracle__factory.connect(getContractAddress(this.chainId, 'PriceOracle'), this.provider); + } + return this._priceOracle; + } + + private _priceOracleIface?: PriceOracleInterface; + + get priceOracleIface() { + if (!this._priceOracleIface) { + this._priceOracleIface = PriceOracle__factory.createInterface(); + } + return this._priceOracleIface; + } + + private _ethPriceFeed?: ETHPriceFeed; + + get ethPriceFeed() { + if (!this._ethPriceFeed) { + this._ethPriceFeed = ETHPriceFeed__factory.connect( + getContractAddress(this.chainId, 'ETHPriceFeed'), + this.provider + ); + } + return this._ethPriceFeed; + } + + private _priceFeedIface?: ETHPriceFeedInterface; + + get ethPriceFeedIface() { + if (!this._priceFeedIface) { + this._priceFeedIface = ETHPriceFeed__factory.createInterface(); + } + return this._priceFeedIface; + } + + private _aTokenIface?: ATokenInterface; + + get aTokenIface() { + if (!this._aTokenIface) { + this._aTokenIface = AToken__factory.createInterface(); + } + return this._aTokenIface; + } + + get reserves() { + return configMap[this.chainId].reserves; + } + + getMarketName() { + return displayName; + } + + private reserveDataMap?: Record< + string, + { + ltv: string; + liquidationThreshold: string; + usageAsCollateralEnabled: boolean; + supplyAPY: string; + stableBorrowAPY: string; + variableBorrowAPY: string; + } + >; + + async getPortfolio(account: string, _marketId: string) { + return (await this.getPortfolios(account))[0]; + } + + async getReserveDataMap() { + if (!this.reserveDataMap) { + const calls: common.Multicall3.CallStruct[] = []; + for (const { asset } of this.reserves) { + const wrappedToken = wrapToken(this.chainId, asset); + calls.push({ + target: this.protocolDataProvider.address, + callData: this.protocolDataProviderIface.encodeFunctionData('getReserveConfigurationData', [ + wrappedToken.address, + ]), + }); + calls.push({ + target: this.protocolDataProvider.address, + callData: this.protocolDataProviderIface.encodeFunctionData('getReserveData', [wrappedToken.address]), + }); + } + const { returnData } = await this.multicall3.callStatic.aggregate(calls); + + this.reserveDataMap = {}; + let j = 0; + for (const { asset } of this.reserves) { + const { ltv, liquidationThreshold, usageAsCollateralEnabled } = + this.protocolDataProviderIface.decodeFunctionResult('getReserveConfigurationData', returnData[j]); + j++; + const { liquidityRate, variableBorrowRate, stableBorrowRate } = + this.protocolDataProviderIface.decodeFunctionResult('getReserveData', returnData[j]); + j++; + + this.reserveDataMap[asset.address] = { + ltv: common.toBigUnit(ltv, 4), + liquidationThreshold: common.toBigUnit(liquidationThreshold, 4), + usageAsCollateralEnabled, + supplyAPY: normalize( + calculateCompoundedRate({ rate: liquidityRate.toString(), duration: SECONDS_PER_YEAR }), + RAY_DECIMALS + ), + stableBorrowAPY: normalize( + calculateCompoundedRate({ rate: stableBorrowRate.toString(), duration: SECONDS_PER_YEAR }), + RAY_DECIMALS + ), + variableBorrowAPY: normalize( + calculateCompoundedRate({ rate: variableBorrowRate.toString(), duration: SECONDS_PER_YEAR }), + RAY_DECIMALS + ), + }; + } + } + + return this.reserveDataMap; + } + + async getAssetPriceMap() { + const calls: common.Multicall3.CallStruct[] = [ + { + target: this.ethPriceFeed.address, + callData: this.ethPriceFeedIface.encodeFunctionData('latestAnswer'), + }, + { + target: this.priceOracle.address, + callData: this.priceOracleIface.encodeFunctionData('getAssetsPrices', [ + this.reserves.map(({ asset }) => wrapToken(this.chainId, asset).address), + ]), + }, + ]; + const { returnData } = await this.multicall3.callStatic.aggregate(calls); + + const [ethPrice] = this.ethPriceFeedIface.decodeFunctionResult('latestAnswer', returnData[0]); + const [assetPrices] = this.priceOracleIface.decodeFunctionResult('getAssetsPrices', returnData[1]); + + const assetPriceMap: Record = {}; + for (let i = 0; i < this.reserves.length; i++) { + assetPriceMap[this.reserves[i].asset.address] = common.toBigUnit( + ethPrice.mul(assetPrices[i]).div(BigNumber.from(10).pow(18)), + 8 + ); + } + + return assetPriceMap; + } + + async getUserBalancesMap(account: string) { + const calls: common.Multicall3.CallStruct[] = []; + for (const { asset, aToken } of this.reserves) { + calls.push({ target: aToken.address, callData: this.erc20Iface.encodeFunctionData('balanceOf', [account]) }); + calls.push({ + target: this.protocolDataProvider.address, + callData: this.protocolDataProviderIface.encodeFunctionData('getUserReserveData', [ + wrapToken(this.chainId, asset).address, + account, + ]), + }); + } + const { returnData } = await this.multicall3.callStatic.aggregate(calls); + + const userBalancesMap: Record< + string, + { + supplyBalance: string; + stableBorrowBalance: string; + variableBorrowBalance: string; + usageAsCollateralEnabled: boolean; + } + > = {}; + let j = 0; + for (let i = 0; i < this.reserves.length; i++) { + const { asset } = this.reserves[i]; + + const [aTokenBalance] = this.erc20Iface.decodeFunctionResult('balanceOf', returnData[j]); + j++; + + const { currentStableDebt, currentVariableDebt, usageAsCollateralEnabled } = + this.protocolDataProviderIface.decodeFunctionResult('getUserReserveData', returnData[j]); + j++; + + userBalancesMap[asset.address] = { + supplyBalance: common.toBigUnit(aTokenBalance, asset.decimals), + stableBorrowBalance: common.toBigUnit(currentStableDebt, asset.decimals), + variableBorrowBalance: common.toBigUnit(currentVariableDebt, asset.decimals), + usageAsCollateralEnabled, + }; + } + + return userBalancesMap; + } + + // https://github.com/aave/interface/blob/release-2023-07-25_15-22/src/hooks/app-data-provider/useAppDataProvider.tsx#L228 + // https://github.com/aave/protocol-v2/blob/master/contracts/protocol/libraries/logic/GenericLogic.sol#L150 + async getPortfolios(account: string) { + const reserveDataMap = await this.getReserveDataMap(); + const assetPriceMap = await this.getAssetPriceMap(); + const userBalancesMap = await this.getUserBalancesMap(account); + + const supplies: SupplyObject[] = []; + for (const token of tokensForDepositMap[this.chainId]) { + if (isWrappedNativeToken(this.chainId, token)) continue; + + const reserveData = reserveDataMap[token.address]; + const assetPrice = assetPriceMap[token.address]; + const userBalance = userBalancesMap[token.address]; + + let usageAsCollateralEnabled = reserveData.usageAsCollateralEnabled; + if (Number(userBalance.supplyBalance) > 0) { + usageAsCollateralEnabled = userBalance.usageAsCollateralEnabled; + } + + supplies.push({ + token, + price: assetPrice, + balance: userBalance.supplyBalance, + apy: reserveData.supplyAPY, + usageAsCollateralEnabled, + ltv: reserveData.ltv, + liquidationThreshold: reserveData.liquidationThreshold, + }); + } + + const borrows: BorrowObject[] = []; + for (const token of tokensForBorrowMap[this.chainId]) { + if (isWrappedNativeToken(this.chainId, token)) continue; + + const { stableBorrowAPY, variableBorrowAPY } = reserveDataMap[token.address]; + const assetPrice = assetPriceMap[token.address]; + const { stableBorrowBalance, variableBorrowBalance } = userBalancesMap[token.address]; + + borrows.push({ + token, + price: assetPrice, + balances: [variableBorrowBalance, stableBorrowBalance], + apys: [variableBorrowAPY, stableBorrowAPY], + }); + } + + const portfolio = new Portfolio(this.chainId, this.id, this.market.id, supplies, borrows); + + return [portfolio]; + } + + toUnderlyingToken(protocolToken: common.Token) { + return toToken(this.chainId, protocolToken); + } + + toProtocolToken(underlyingToken: common.Token) { + return toAToken(this.chainId, underlyingToken); + } + + isProtocolToken(token: common.Token) { + return isAToken(this.chainId, token); + } + + async newSupplyLogic(params: SupplyParams) { + const supplyQuotation = await protocols.aavev2.getDepositQuotation(this.chainId, { + input: params.input, + tokenOut: toAToken(this.chainId, params.input.token), + }); + return protocols.aavev2.newDepositLogic({ ...supplyQuotation, balanceBps: common.BPS_BASE }); + } + + async newWithdrawLogic(params: WithdrawParams) { + const withdrawQuotation = await protocols.aavev2.getWithdrawQuotation(this.chainId, { + input: { + token: toAToken(this.chainId, params.output.token), + amount: params.output.amount, + }, + tokenOut: params.output.token, + }); + return protocols.aavev2.newWithdrawLogic(withdrawQuotation); + } + + newBorrowLogic = protocols.aavev2.newBorrowLogic; + + async newRepayLogic(params: RepayParams) { + if (!params.borrower || !params.interestRateMode) throw new Error('missing requied params'); + const repayQuotation = await protocols.aavev2.getRepayQuotation(this.chainId, { + tokenIn: params.input.token, + borrower: params.borrower, + interestRateMode: params.interestRateMode, + }); + repayQuotation.input.amount = params.input.amount; + return protocols.aavev2.newRepayLogic(repayQuotation); + } +} diff --git a/packages/lending/src/protocols/compound-v3/configs.ts b/packages/lending/src/protocols/compound-v3/configs.ts index a65232a9..be185953 100644 --- a/packages/lending/src/protocols/compound-v3/configs.ts +++ b/packages/lending/src/protocols/compound-v3/configs.ts @@ -1,7 +1,7 @@ import { arbitrumTokens, mainnetTokens, polygonTokens } from '@protocolink/test-helpers'; // import { SUPPLY_ETH_NAME, SUPPLY_USDC_NAME, WITHDRAW_ETH_NAME, WITHDRAW_USDC_NAME } from '../compoundv3/constants'; import * as common from '@protocolink/common'; -import { unwrapToken, wrapToken } from 'src/helper'; +import { unwrapToken } from 'src/helper'; export interface AssetConfig { token: common.Token; diff --git a/packages/lending/test/hooks.ts b/packages/lending/test/hooks.ts index 709b9251..f5db6d3a 100644 --- a/packages/lending/test/hooks.ts +++ b/packages/lending/test/hooks.ts @@ -1,9 +1,11 @@ +import { LendingProtocol as AaveV2Lending } from 'src/protocols/aave-v2/lending-protocol'; import { LendingProtocol as AaveV3Lending } from 'src/protocols/aave-v3/lending-protocol'; import { Adapter } from 'src/adapter'; import { LendingProtocol as CompoundV3Lending } from 'src/protocols/compound-v3/lending-protocol'; import { LendingSwaper } from 'src/protocols/paraswap-v5/lending-swaper'; export async function setup() { + Adapter.registerProtocol(AaveV2Lending); Adapter.registerProtocol(AaveV3Lending); Adapter.registerProtocol(CompoundV3Lending); Adapter.registerSwaper(LendingSwaper); diff --git a/packages/lending/test/transactions/zap-borrow.ts b/packages/lending/test/transactions/zap-borrow.ts index f14ad7fa..5510b607 100644 --- a/packages/lending/test/transactions/zap-borrow.ts +++ b/packages/lending/test/transactions/zap-borrow.ts @@ -3,6 +3,7 @@ import { Portfolio } from 'src/protocol.portfolio'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { expect } from 'chai'; import hre from 'hardhat'; +import * as logics from '@protocolink/logics'; import { mainnetTokens } from '@protocolink/test-helpers'; describe('Transaction: Zap Borrow', function () { @@ -50,6 +51,17 @@ describe('Transaction: Zap Borrow', function () { destToken: mainnetTokens.USDC, }, }, + { + skip: false, + protocolId: 'aavev2', + marketId: 'mainnet', + testingAccount: '0x7F67F6A09bcb2159b094B64B4acc53D5193AEa2E', + params: { + srcToken: mainnetTokens.USDC, + srcAmount: '1000', + destToken: mainnetTokens.USDC, + }, + }, ]; for (const [i, { skip, testingAccount, protocolId, marketId, params }] of testCases.entries()) { diff --git a/packages/lending/test/transactions/zap-repay.ts b/packages/lending/test/transactions/zap-repay.ts index 9154b13d..9e723446 100644 --- a/packages/lending/test/transactions/zap-repay.ts +++ b/packages/lending/test/transactions/zap-repay.ts @@ -1,9 +1,9 @@ import { Adapter } from 'src/adapter'; import { Portfolio } from 'src/protocol.portfolio'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { claimToken, mainnetTokens, snapshotAndRevertEach } from '@protocolink/test-helpers'; import { expect } from 'chai'; import hre from 'hardhat'; -import { mainnetTokens, snapshotAndRevertEach } from '@protocolink/test-helpers'; describe('Transaction: Zap Repay', function () { let portfolio: Portfolio; @@ -14,6 +14,7 @@ describe('Transaction: Zap Repay', function () { before(async function () { adapter = new Adapter(chainId, hre.ethers.provider, { permitType: 'approve' }); + await claimToken(chainId, '0x7F67F6A09bcb2159b094B64B4acc53D5193AEa2E', mainnetTokens.USDC, '1000'); }); snapshotAndRevertEach(); @@ -42,6 +43,17 @@ describe('Transaction: Zap Repay', function () { destToken: mainnetTokens.USDC, }, }, + { + skip: false, + protocolId: 'aavev2', + marketId: 'mainnet', + testingAccount: '0x7F67F6A09bcb2159b094B64B4acc53D5193AEa2E', + params: { + srcToken: mainnetTokens.USDC, + srcAmount: '1000', + destToken: mainnetTokens.USDC, + }, + }, ]; for (const [i, { skip, protocolId, marketId, testingAccount, params }] of testCases.entries()) { diff --git a/packages/lending/test/transactions/zap-supply.ts b/packages/lending/test/transactions/zap-supply.ts index 758e0cf2..e7cdca0b 100644 --- a/packages/lending/test/transactions/zap-supply.ts +++ b/packages/lending/test/transactions/zap-supply.ts @@ -3,6 +3,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { claimToken, getBalance, mainnetTokens, snapshotAndRevertEach } from '@protocolink/test-helpers'; import { expect } from 'chai'; import hre from 'hardhat'; +import * as logics from '@protocolink/logics'; describe('Transaction: Zap Supply', function () { let user: SignerWithAddress; @@ -14,7 +15,7 @@ describe('Transaction: Zap Supply', function () { adapter = new Adapter(chainId, hre.ethers.provider, { permitType: 'approve' }); [, user] = await hre.ethers.getSigners(); - await claimToken(chainId, user.address, mainnetTokens.USDC, '1'); + await claimToken(chainId, user.address, mainnetTokens.USDC, '2'); await claimToken(chainId, user.address, mainnetTokens.WETH, '0.4'); }); @@ -109,6 +110,7 @@ describe('Transaction: Zap Supply', function () { }, }, { + skip: false, protocolId: 'compoundv3', marketId: 'ETH', params: { @@ -123,6 +125,22 @@ describe('Transaction: Zap Supply', function () { recieves: [cWETH], }, }, + { + skip: false, + protocolId: 'aavev2', + marketId: 'mainnet', + params: { + srcToken: mainnetTokens.USDC, + srcAmount: '1', + destToken: mainnetTokens.WBTC, + }, + expects: { + funds: [mainnetTokens.USDC], + balances: [logics.aavev2.mainnetTokens.aWBTC], + apporveTimes: 2, + recieves: [logics.aavev2.mainnetTokens.aWBTC], + }, + }, ]; for (const [i, { skip, protocolId, marketId, params, expects }] of testCases.entries()) { diff --git a/packages/lending/test/transactions/zap-withdraw.ts b/packages/lending/test/transactions/zap-withdraw.ts index 627f3873..15ca9bdf 100644 --- a/packages/lending/test/transactions/zap-withdraw.ts +++ b/packages/lending/test/transactions/zap-withdraw.ts @@ -3,6 +3,7 @@ import { Portfolio } from 'src/protocol.portfolio'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { expect } from 'chai'; import hre from 'hardhat'; +import * as logics from '@protocolink/logics'; import { mainnetTokens } from '@protocolink/test-helpers'; describe('Transaction: Zap Withdraw', function () { @@ -67,6 +68,7 @@ describe('Transaction: Zap Withdraw', function () { }, }, { + skip: false, testingAccount: '0xa3C1C91403F0026b9dd086882aDbC8Cdbc3b3cfB', protocolId: 'compoundv3', marketId: 'USDC', @@ -83,6 +85,7 @@ describe('Transaction: Zap Withdraw', function () { }, }, { + skip: false, testingAccount: '0xa3C1C91403F0026b9dd086882aDbC8Cdbc3b3cfB', protocolId: 'compoundv3', marketId: 'USDC', @@ -98,6 +101,23 @@ describe('Transaction: Zap Withdraw', function () { recieves: [mainnetTokens.ETH], }, }, + { + skip: false, + testingAccount: '0x7F67F6A09bcb2159b094B64B4acc53D5193AEa2E', + protocolId: 'aavev2', + marketId: 'mainnet', + params: { + srcToken: mainnetTokens.WBTC, + srcAmount: '2', + destToken: mainnetTokens.USDC, + }, + expects: { + funds: [logics.aavev2.mainnetTokens.aWBTC], + balances: [mainnetTokens.USDC], + apporveTimes: 2, + recieves: [mainnetTokens.USDC], + }, + }, ]; for (const [i, { skip, testingAccount, protocolId, marketId, params, expects }] of testCases.entries()) {