From 9e230be5450284346886126686db8cebcdc426f7 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Fri, 18 Mar 2022 17:04:48 +0300 Subject: [PATCH 01/16] fix: addLiquidity gas estimation for tricrypto2 --- src/pools.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pools.ts b/src/pools.ts index 51c8c3fa..4dec576c 100644 --- a/src/pools.ts +++ b/src/pools.ts @@ -478,7 +478,7 @@ export class Pool { // Lending pools with zap - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name)) { return await this._addLiquidityZap(_amounts, true) as number; } From 7feda549ed886e6071fe352daf50091c8b42f93d Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Sat, 19 Mar 2022 14:12:06 +0300 Subject: [PATCH 02/16] chore: ICurve interface --- src/curve.ts | 4 ++-- src/factory.ts | 49 +++++++++++++++++------------------------------ src/interfaces.ts | 16 +++++++++++++++- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/curve.ts b/src/curve.ts index 35a160d5..94ebe56c 100644 --- a/src/curve.ts +++ b/src/curve.ts @@ -3,7 +3,7 @@ import { Networkish } from "@ethersproject/networks"; import { Provider as MulticallProvider, Contract as MulticallContract } from 'ethcall'; import { getFactoryPoolData } from "./factory"; import { getCryptoFactoryPoolData } from "./factory-crypto"; -import {PoolDataInterface, DictInterface} from "./interfaces"; +import {PoolDataInterface, DictInterface, ICurve} from "./interfaces"; import ERC20Abi from './constants/abis/json/ERC20.json'; import cERC20Abi from './constants/abis/json/cERC20.json'; import yERC20Abi from './constants/abis/json/yERC20.json'; @@ -90,7 +90,7 @@ export let ALIASES = { "registry_exchange": "", } -class Curve { +class Curve implements ICurve { provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider; multicallProvider: MulticallProvider; signer: ethers.Signer | null; diff --git a/src/factory.ts b/src/factory.ts index 285434d8..7c9534f0 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -1,6 +1,6 @@ import { Contract, ethers } from "ethers"; -import {Contract as MulticallContract, Provider as MulticallProvider} from "ethcall"; -import { DictInterface, PoolDataInterface } from "./interfaces"; +import { Contract as MulticallContract } from "ethcall"; +import { DictInterface, PoolDataInterface, ICurve } from "./interfaces"; import ERC20ABI from "./constants/abis/json/ERC20.json"; import factorySwapABI from "./constants/abis/json/factoryPools/swap.json"; import factoryDepositABI from "./constants/abis/json/factoryPools/deposit.json"; @@ -162,22 +162,9 @@ const blackListPolygon: string[] = [ const blackListEthereum: string[] = []; -interface CurveInterface { - provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider, - multicallProvider: MulticallProvider, - signer: ethers.Signer | null, - signerAddress: string, - chainId: number, - contracts: { [index: string]: { contract: Contract, multicallContract: MulticallContract } }, - feeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }, - constantOptions: { gasLimit: number }, - options: { gasPrice?: number | ethers.BigNumber, maxFeePerGas?: number | ethers.BigNumber, maxPriorityFeePerGas?: number | ethers.BigNumber }, - constants: DictInterface; -} - const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); -async function getFactorySwapAddresses(this: CurveInterface): Promise { +async function getFactorySwapAddresses(this: ICurve): Promise { const factoryContract = this.contracts[this.constants.ALIASES.factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.factory].multicallContract; @@ -194,7 +181,7 @@ async function getFactorySwapAddresses(this: CurveInterface): Promise return factorySwapAddresses.filter((addr) => !swapAddresses.includes(addr) && !blacklist.includes(addr)); } -async function getFactorySwapABIs(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactorySwapABIs(this: ICurve, factorySwapAddresses: string[]): Promise { const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; @@ -207,7 +194,7 @@ async function getFactorySwapABIs(this: CurveInterface, factorySwapAddresses: st return implementationAddresses.map((addr: string) => implementationABIDict[addr]); } -function setFactorySwapContracts(this: CurveInterface, factorySwapAddresses: string[], factorySwapABIs: any[]): void { +function setFactorySwapContracts(this: ICurve, factorySwapAddresses: string[], factorySwapABIs: any[]): void { factorySwapAddresses.forEach((addr, i) => { this.contracts[addr] = { contract: new Contract(addr, factorySwapABIs[i], this.signer || this.provider), @@ -216,7 +203,7 @@ function setFactorySwapContracts(this: CurveInterface, factorySwapAddresses: str }); } -async function getFactoryGaugeAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactoryGaugeAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -227,7 +214,7 @@ async function getFactoryGaugeAddresses(this: CurveInterface, factorySwapAddress return (await this.multicallProvider.all(calls) as string[]).map((addr) => addr.toLowerCase()); } -function setFactoryGaugeContracts(this: CurveInterface, factoryGaugeAddresses: string[]): void { +function setFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { factoryGaugeAddresses.filter((addr) => addr !== ethers.constants.AddressZero).forEach((addr, i) => { this.contracts[addr] = { contract: new Contract(addr, factoryGaugeABI, this.signer || this.provider), @@ -236,7 +223,7 @@ function setFactoryGaugeContracts(this: CurveInterface, factoryGaugeAddresses: s }); } -async function getFactoryPoolNames(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactoryPoolNames(this: ICurve, factorySwapAddresses: string[]): Promise { const calls = []; for (const addr of factorySwapAddresses) { calls.push(this.contracts[addr].multicallContract.symbol()); @@ -259,7 +246,7 @@ async function getFactoryPoolNames(this: CurveInterface, factorySwapAddresses: s return names } -async function getFactoryReferenceAssets(this: CurveInterface, factorySwapAddresses: string[]): Promise<('USD' | 'ETH' | 'BTC' | 'OTHER')[]> { +async function getFactoryReferenceAssets(this: ICurve, factorySwapAddresses: string[]): Promise<('USD' | 'ETH' | 'BTC' | 'OTHER')[]> { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -276,7 +263,7 @@ async function getFactoryReferenceAssets(this: CurveInterface, factorySwapAddres }) as ('USD' | 'ETH' | 'BTC' | 'OTHER')[]; } -async function getFactoryCoinAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactoryCoinAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -291,7 +278,7 @@ async function getFactoryCoinAddresses(this: CurveInterface, factorySwapAddresse ); } -function setFactoryCoinsContracts(this: CurveInterface, coinAddresses: string[][]): void { +function setFactoryCoinsContracts(this: ICurve, coinAddresses: string[][]): void { const flattenedCoinAddresses = Array.from(new Set(deepFlatten(coinAddresses))); for (const addr of flattenedCoinAddresses) { if (addr in this.contracts) continue; @@ -303,7 +290,7 @@ function setFactoryCoinsContracts(this: CurveInterface, coinAddresses: string[][ } } -function getExistingCoinAddressNameDict(this: CurveInterface): DictInterface { +function getExistingCoinAddressNameDict(this: ICurve): DictInterface { const dict: DictInterface = {} for (const poolData of Object.values(this.constants.POOLS_DATA as DictInterface)) { poolData.coin_addresses.forEach((addr, i) => { @@ -325,7 +312,7 @@ function getExistingCoinAddressNameDict(this: CurveInterface): DictInterface ): Promise> { @@ -355,7 +342,7 @@ async function getCoinAddressNameDict( } async function getCoinAddressDecimalsDict( - this: CurveInterface, + this: ICurve, coinAddresses: string[][], existingCoinAddressDecimalsDict: DictInterface ): Promise> { @@ -385,7 +372,7 @@ async function getCoinAddressDecimalsDict( return coinAddrNamesDict } -async function getFactoryIsMeta(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactoryIsMeta(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -396,7 +383,7 @@ async function getFactoryIsMeta(this: CurveInterface, factorySwapAddresses: stri return await this.multicallProvider.all(calls); } -async function getFactoryBasePoolAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getFactoryBasePoolAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -407,7 +394,7 @@ async function getFactoryBasePoolAddresses(this: CurveInterface, factorySwapAddr return await this.multicallProvider.all(calls); } -function setFactoryZapContracts(this: CurveInterface): void { +function setFactoryZapContracts(this: ICurve): void { if (this.chainId === 137) { const metaUsdZapAddress = "0x5ab5C56B9db92Ba45a0B46a207286cD83C15C939".toLowerCase(); this.contracts[metaUsdZapAddress] = { @@ -428,7 +415,7 @@ function setFactoryZapContracts(this: CurveInterface): void { } } -export async function getFactoryPoolData(this: CurveInterface): Promise> { +export async function getFactoryPoolData(this: ICurve): Promise> { const swapAddresses = await getFactorySwapAddresses.call(this); const swapABIs = await getFactorySwapABIs.call(this, swapAddresses); setFactorySwapContracts.call(this, swapAddresses, swapABIs); diff --git a/src/interfaces.ts b/src/interfaces.ts index 801c07de..5f16d421 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,9 +1,23 @@ -import { ethers } from "ethers"; +import { Contract, ethers } from "ethers"; +import { Contract as MulticallContract, Provider as MulticallProvider } from "ethcall"; export interface DictInterface { [index: string]: T, } +export interface ICurve { + provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider, + multicallProvider: MulticallProvider, + signer: ethers.Signer | null, + signerAddress: string, + chainId: number, + contracts: { [index: string]: { contract: Contract, multicallContract: MulticallContract } }, + feeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }, + constantOptions: { gasLimit: number }, + options: { gasPrice?: number | ethers.BigNumber, maxFeePerGas?: number | ethers.BigNumber, maxPriorityFeePerGas?: number | ethers.BigNumber }, + constants: DictInterface; +} + export interface PoolDataInterface { reference_asset: 'USD' | 'EUR' | 'BTC' | 'ETH' | 'LINK' | 'CRYPTO' | 'OTHER', N_COINS: number, From 021cc1c9f77eb495622d0cce2d98f9c5f58310c1 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Sat, 19 Mar 2022 14:13:47 +0300 Subject: [PATCH 03/16] feat: getting factory pools data from api --- src/factory/constants.ts | 175 +++++++++++++++++++++++++++++++++++++ src/factory/factory-api.ts | 170 +++++++++++++++++++++++++++++++++++ src/interfaces.ts | 2 + 3 files changed, 347 insertions(+) create mode 100644 src/factory/constants.ts create mode 100644 src/factory/factory-api.ts diff --git a/src/factory/constants.ts b/src/factory/constants.ts new file mode 100644 index 00000000..792d46a0 --- /dev/null +++ b/src/factory/constants.ts @@ -0,0 +1,175 @@ +import {DictInterface} from "../interfaces"; +import factorySwapABI from "../constants/abis/json/factoryPools/swap.json"; +import MetaUSDABI from "../constants/abis/json/factory-v2/MetaUSD.json"; +import MetaUSDBalancesABI from "../constants/abis/json/factory-v2/MetaUSDBalances.json"; +import MetaBTCABI from "../constants/abis/json/factory-v2/MetaBTC.json"; +import MetaBTCBalancesABI from "../constants/abis/json/factory-v2/MetaBTCBalances.json"; +import MetaBTCRenABI from "../constants/abis/json/factory-v2/MetaBTCRen.json"; +import MetaBTCRenBalancesABI from "../constants/abis/json/factory-v2/MetaBTCBalancesRen.json"; +import Plain2BasicABI from "../constants/abis/json/factory-v2/Plain2Basic.json"; +import Plain2BalancesABI from "../constants/abis/json/factory-v2/Plain2Balances.json"; +import Plain2ETHABI from "../constants/abis/json/factory-v2/Plain2ETH.json"; +import Plain2OptimizedABI from "../constants/abis/json/factory-v2/Plain2Optimized.json"; +import Plain3BasicABI from "../constants/abis/json/factory-v2/Plain3Basic.json"; +import Plain3BalancesABI from "../constants/abis/json/factory-v2/Plain3Balances.json"; +import Plain3ETHABI from "../constants/abis/json/factory-v2/Plain3ETH.json"; +import Plain3OptimizedABI from "../constants/abis/json/factory-v2/Plain3Optimized.json"; +import Plain4BasicABI from "../constants/abis/json/factory-v2/Plain4Basic.json"; +import Plain4BalancesABI from "../constants/abis/json/factory-v2/Plain4Balances.json"; +import Plain4ETHABI from "../constants/abis/json/factory-v2/Plain4ETH.json"; +import Plain4OptimizedABI from "../constants/abis/json/factory-v2/Plain4Optimized.json"; + + +export const implementationABIDictEthereum: DictInterface = { + "0x5F890841f657d90E081bAbdB532A05996Af79Fe6": factorySwapABI, + + "0x213be373FDff327658139C7df330817DAD2d5bBE": MetaUSDABI, + "0x55Aa9BF126bCABF0bDC17Fa9E39Ec9239e1ce7A9": MetaUSDBalancesABI, + + "0xC6A8466d128Fbfd34AdA64a9FFFce325D57C9a52": MetaBTCABI, + "0xc4C78b08fA0c3d0a312605634461A88184Ecd630": MetaBTCBalancesABI, + + "0xECAaecd9d2193900b424774133B1f51ae0F29d9E": MetaBTCRenABI, + "0x40fD58D44cFE63E8517c9Bb3ac98676838Ea56A8": MetaBTCRenBalancesABI, + + "0x6523Ac15EC152Cb70a334230F6c5d62C5Bd963f1": Plain2BasicABI, + "0x24D937143d3F5cF04c72bA112735151A8CAE2262": Plain2BalancesABI, + "0x6326DEbBAa15bCFE603d831e7D75f4fc10d9B43E": Plain2ETHABI, + "0x4A4d7868390EF5CaC51cDA262888f34bD3025C3F": Plain2OptimizedABI, + + "0x9B52F13DF69D79Ec5aAB6D1aCe3157d29B409cC3": Plain3BasicABI, + "0x50b085f2e5958C4A87baf93A8AB79F6bec068494": Plain3BalancesABI, + "0x8c1aB78601c259E1B43F19816923609dC7d7de9B": Plain3ETHABI, + "0xE5F4b89E0A16578B3e0e7581327BDb4C712E44De": Plain3OptimizedABI, + + "0x5Bd47eA4494e0F8DE6e3Ca10F1c05F55b72466B8": Plain4BasicABI, + "0xd35B58386705CE75CE6d09842E38E9BE9CDe5bF6": Plain4BalancesABI, + "0x88855cdF2b0A8413D470B86952E726684de915be": Plain4ETHABI, + "0xaD4753D045D3Aed5C1a6606dFb6a7D7AD67C1Ad7": Plain4OptimizedABI, +} + +export const implementationABIDictPolygon: DictInterface = { + "0x4fb93D7d320E8A263F22f62C2059dFC2A8bCbC4c": MetaUSDABI, + "0x39fE1824f98CD828050D7c51dA443E84121c7cf1": MetaUSDBalancesABI, + + "0xC05EB760A135d3D0c839f1141423002681157a17": MetaBTCRenABI, + "0xD8336532f6ED7b94282fAF724fe41d6145E07Cfc": MetaBTCRenBalancesABI, + + "0x571FF5b7b346F706aa48d696a9a4a288e9Bb4091": Plain2BasicABI, + "0x8925D9d9B4569D737a48499DeF3f67BaA5a144b9": Plain2BalancesABI, + "0xAe00f57663F4C85FC948B13963cd4627dAF01061": Plain2ETHABI, + "0x8101E6760130be2C8Ace79643AB73500571b7162": Plain2OptimizedABI, + + "0x493084cA44C779Af27a416ac1F71e3823BF21b53": Plain3BasicABI, + "0x9B4Ed6F8904E976146b3dC0233CD48Cf81835240": Plain3BalancesABI, + "0xA9134FaE98F92217f457918505375Ae91fdc5e3c": Plain3ETHABI, + "0xCC9fd96C26c450Dd4580893afF75efd5cb6C12Fc": Plain3OptimizedABI, + + "0x991b05d5316fa3A2C053F84658b84987cd5c9970": Plain4BasicABI, + "0xC7c46488566b9ef9B981b87E328939CaA5ca152f": Plain4BalancesABI, + "0xf31bcdf0B9a5eCD7AB463eB905551fBc32e51856": Plain4ETHABI, + "0xAc273d5b4FC06625d8b1abA3BE8De15bDFb8E39f": Plain4OptimizedABI, +} + +export const implementationBasePoolAddressDictEthereum: DictInterface = { + "0x5F890841f657d90E081bAbdB532A05996Af79Fe6": "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", // 3pool + + "0x213be373FDff327658139C7df330817DAD2d5bBE": "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", // 3pool + "0x55Aa9BF126bCABF0bDC17Fa9E39Ec9239e1ce7A9": "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", // 3pool + + "0xC6A8466d128Fbfd34AdA64a9FFFce325D57C9a52": "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714", // sbtc + "0xc4C78b08fA0c3d0a312605634461A88184Ecd630": "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714", // sbtc + + "0xECAaecd9d2193900b424774133B1f51ae0F29d9E": "0x93054188d876f558f4a66B2EF1d97d16eDf0895B", // ren + "0x40fD58D44cFE63E8517c9Bb3ac98676838Ea56A8": "0x93054188d876f558f4a66B2EF1d97d16eDf0895B", // ren +} + +export const implementationBasePoolAddressDictPolygon: DictInterface = { + "0x4fb93D7d320E8A263F22f62C2059dFC2A8bCbC4c": "0x445FE580eF8d70FF569aB36e80c647af338db351", // aave + "0x39fE1824f98CD828050D7c51dA443E84121c7cf1": "0x445FE580eF8d70FF569aB36e80c647af338db351", // aave + + "0xC05EB760A135d3D0c839f1141423002681157a17": "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67", // ren + "0xD8336532f6ED7b94282fAF724fe41d6145E07Cfc": "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67", // ren +} + +export const basePoolAddressNameDictEthereum: DictInterface = { + "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7": "3pool", + "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714": "sbtc", + "0x93054188d876f558f4a66B2EF1d97d16eDf0895B": "ren", +} + +export const basePoolAddressNameDictPolygon: DictInterface = { + "0x445FE580eF8d70FF569aB36e80c647af338db351": "aave", + "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67": "ren", +} + +export const basePoolAddressCoinsDictEthereum: DictInterface = { + "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7": ['DAI', 'USDC', 'USDT'], // 3pool + "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714": ['renBTC', 'WBTC', 'sBTC'], // sbtc + "0x93054188d876f558f4a66B2EF1d97d16eDf0895B": ['renBTC', 'WBTC'], // ren +} + +export const basePoolAddressCoinsDictPolygon: DictInterface = { + "0x445FE580eF8d70FF569aB36e80c647af338db351": ['DAI', 'USDC', 'USDT'], // aave + "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67": ['WBTC', 'renBTC'], // ren +} + +export const basePoolAddressCoinAddressesDictEthereum: DictInterface = { + "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7": [ // 3pool + '0x6B175474E89094C44Da98b954EedeAC495271d0F', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + '0xdAC17F958D2ee523a2206206994597C13D831ec7', + ].map((addr) => addr.toLowerCase()), + + "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714": [ // sbtc + '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', + '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', + '0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6', + ].map((addr) => addr.toLowerCase()), + + "0x93054188d876f558f4a66B2EF1d97d16eDf0895B": [ // ren + '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', + '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', + ].map((addr) => addr.toLowerCase()), +} + +export const basePoolAddressCoinAddressesDictPolygon: DictInterface = { + "0x445FE580eF8d70FF569aB36e80c647af338db351": [ // aave + '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + ].map((addr) => addr.toLowerCase()), + + "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67": [ // ren + '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6', + '0xDBf31dF14B66535aF65AaC99C32e9eA844e14501', + ].map((addr) => addr.toLowerCase()), +} + +export const basePoolAddressDecimalsDictEthereum: DictInterface = { + "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7": [18, 6, 6], // 3pool + "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714": [8, 8, 18], // sbtc + "0x93054188d876f558f4a66B2EF1d97d16eDf0895B": [8, 8], // ren +} + +export const basePoolAddressDecimalsDictPolygon: DictInterface = { + "0x445FE580eF8d70FF569aB36e80c647af338db351": [18, 6, 6], // aave + "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67": [8, 8], // ren +} + +export const basePoolAddressZapDictEthereum: DictInterface = { + "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7": "0xA79828DF1850E8a3A3064576f380D90aECDD3359".toLowerCase(), // 3pool + "0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714": "0x7abdbaf29929e7f8621b757d2a7c04d78d633834".toLowerCase(), // sbtc + "0x93054188d876f558f4a66B2EF1d97d16eDf0895B": "0x7abdbaf29929e7f8621b757d2a7c04d78d633834".toLowerCase(), // ren TODO CHECK!!! +} + +export const basePoolAddressZapDictPolygon: DictInterface = { + "0x445FE580eF8d70FF569aB36e80c647af338db351": "0x5ab5C56B9db92Ba45a0B46a207286cD83C15C939".toLowerCase(), // aave + "0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67": "0xE2e6DC1708337A6e59f227921db08F21e3394723".toLowerCase(), // ren +} + +export const blackListPolygon: string[] = [ + "0x666dc3b4babfd063faf965bd020024af0dc51b64", + "0xe4199bc5c5c1f63dba47b56b6db7144c51cf0bf8", + "0x88c4d6534165510b2e2caf0a130d4f70aa4b6d71", +]; diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts new file mode 100644 index 00000000..17fc95dd --- /dev/null +++ b/src/factory/factory-api.ts @@ -0,0 +1,170 @@ +import axios from 'axios'; +import {Contract, ethers} from "ethers"; +import { Contract as MulticallContract } from "ethcall"; +import { DictInterface, PoolDataInterface, ICurve } from "../interfaces"; +import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; +import factoryDepositABI from "../constants/abis/json/factoryPools/deposit.json"; +import ERC20ABI from "../constants/abis/json/ERC20.json"; +import MetaUsdZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaUsdPolygon.json"; +import MetaBtcZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaBtcPolygon.json"; +import { + implementationABIDictEthereum, + implementationABIDictPolygon, + basePoolAddressCoinsDictEthereum, + basePoolAddressCoinsDictPolygon, + implementationBasePoolAddressDictEthereum, + implementationBasePoolAddressDictPolygon, + basePoolAddressCoinAddressesDictEthereum, + basePoolAddressCoinAddressesDictPolygon, + basePoolAddressNameDictEthereum, + basePoolAddressNameDictPolygon, + basePoolAddressDecimalsDictEthereum, + basePoolAddressDecimalsDictPolygon, + basePoolAddressZapDictEthereum, + basePoolAddressZapDictPolygon, +} from "./constants"; + +const url = "https://api.curve.fi/api/getPools/ethereum/factory"; + +function setFactorySwapContracts(this: ICurve, rawPoolList: any[]): void { + const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; + rawPoolList.forEach((pool) => { + const addr = pool.address.toLowerCase(); + this.contracts[addr] = { + contract: new Contract(addr, implementationABIDict[pool.implementationAddress], this.signer || this.provider), + multicallContract: new MulticallContract(addr, implementationABIDict[pool.implementationAddress]), + } + }); +} + +function setFactoryGaugeContracts(this: ICurve, rawPoolList: any[]): void { + rawPoolList.forEach((pool) => { + if (pool.gaugeAddresses) { + const addr = pool.gaugeAddresses.toLowerCase() + this.contracts[addr] = { + contract: new Contract(addr, factoryGaugeABI, this.signer || this.provider), + multicallContract: new MulticallContract(addr, factoryGaugeABI), + } + } + }); +} + +function setFactoryCoinsContracts(this: ICurve, rawPoolList: any[]): void { + const coinAddresses = Array.from(rawPoolList.reduce((coins: Set, pool) => { + pool.coins.forEach((c) => coins.add(c.address.toLowerCase())) + return coins; + }, new Set([]))); + + for (const addr of coinAddresses) { + if (addr in this.contracts) continue; + this.contracts[addr] = { + contract: new Contract(addr, ERC20ABI, this.signer || this.provider), + multicallContract: new MulticallContract(addr, ERC20ABI), + } + } +} + +function setFactoryZapContracts(this: ICurve): void { + if (this.chainId === 137) { + const metaUsdZapAddress = "0x5ab5C56B9db92Ba45a0B46a207286cD83C15C939".toLowerCase(); + this.contracts[metaUsdZapAddress] = { + contract: new Contract(metaUsdZapAddress, MetaUsdZapPolygonABI, this.signer || this.provider), + multicallContract: new MulticallContract(metaUsdZapAddress, MetaUsdZapPolygonABI), + }; + const metaBtcZapAddress = "0xE2e6DC1708337A6e59f227921db08F21e3394723".toLowerCase(); + this.contracts[metaBtcZapAddress] = { + contract: new Contract(metaBtcZapAddress, MetaBtcZapPolygonABI, this.signer || this.provider), + multicallContract: new MulticallContract(metaBtcZapAddress, MetaBtcZapPolygonABI), + }; + } else { + const metaSBtcZapAddress = "0x7abdbaf29929e7f8621b757d2a7c04d78d633834".toLowerCase(); + this.contracts[metaSBtcZapAddress] = { + contract: new Contract(metaSBtcZapAddress, factoryDepositABI, this.signer || this.provider), + multicallContract: new MulticallContract(metaSBtcZapAddress, factoryDepositABI), + }; + } +} + +export async function getFactoryPoolsDataFromApi(this: ICurve): Promise> { + const response = await axios.get(url); + const rawPoolList = response.data.data.poolData; + setFactorySwapContracts.call(this, rawPoolList); + setFactoryGaugeContracts.call(this, rawPoolList); + setFactoryCoinsContracts.call(this, rawPoolList); + setFactoryZapContracts.call(this); + + const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; + const implementationBasePoolAddressDict = this.chainId === 137 ? implementationBasePoolAddressDictPolygon : implementationBasePoolAddressDictEthereum; + const basePoolAddressCoinsDict = this.chainId === 137 ? basePoolAddressCoinsDictPolygon : basePoolAddressCoinsDictEthereum; + const basePoolAddressNameDict = this.chainId === 137 ? basePoolAddressNameDictPolygon : basePoolAddressNameDictEthereum; + const basePoolAddressCoinAddressesDict = this.chainId === 137 ? basePoolAddressCoinAddressesDictPolygon : basePoolAddressCoinAddressesDictEthereum; + const basePoolAddressDecimalsDict = this.chainId === 137 ? basePoolAddressDecimalsDictPolygon : basePoolAddressDecimalsDictEthereum; + const basePoolAddressZapDict = this.chainId === 137 ? basePoolAddressZapDictPolygon : basePoolAddressZapDictEthereum; + + const FACTORY_POOLS_DATA: DictInterface = {}; + rawPoolList.forEach((pool) => { + const coinAddresses = pool.coins.map((c) => c.address.toLowerCase()); + const coinNames = pool.coins.map((c) => c.symbol); + const coinDecimals = pool.coins.map((c) => Number(c.decimals)); + + if (pool.implementation.startsWith("meta")) { + const basePoolAddress = implementationBasePoolAddressDict[pool.implementationAddress]; + const basePoolCoinNames = basePoolAddressCoinsDict[basePoolAddress]; + const basePoolCoinAddresses = basePoolAddressCoinAddressesDict[basePoolAddress]; + const basePoolDecimals = basePoolAddressDecimalsDict[basePoolAddress]; + const basePoolZap = basePoolAddressZapDict[basePoolAddress]; + + FACTORY_POOLS_DATA[pool.id] = { + name: pool.name, + symbol: pool.symbol, + reference_asset: pool.assetTypeName.toUpperCase(), + N_COINS: coinAddresses.length, + underlying_decimals: coinDecimals, + decimals: coinDecimals, + use_lending: coinAddresses.map(() => false), + is_plain: coinAddresses.map(() => true), + swap_address: pool.address.toLowerCase(), + token_address: pool.address.toLowerCase(), + gauge_address: pool.gaugeAddress ? pool.gaugeAddress.toLowerCase() : ethers.constants.AddressZero, + underlying_coins: [coinNames[0], ...basePoolCoinNames], + coins: coinNames, + underlying_coin_addresses: coinAddresses, + coin_addresses: coinAddresses, + swap_abi: implementationABIDict[pool.implementationAddress], + gauge_abi: factoryGaugeABI, + is_factory: true, + is_meta_factory: true, + is_meta: true, + base_pool: basePoolAddressNameDict[basePoolAddress], + meta_coin_addresses: basePoolCoinAddresses, + meta_coin_decimals: [coinDecimals[0], ...basePoolDecimals], + deposit_address: basePoolZap, + deposit_abi: factoryDepositABI, + }; + } else { + FACTORY_POOLS_DATA[pool.id] = { + name: pool.name, + symbol: pool.symbol, + reference_asset: pool.assetTypeName.toUpperCase(), + N_COINS: coinAddresses.length, + underlying_decimals: coinDecimals, + decimals: coinDecimals, + use_lending: coinAddresses.map(() => false), + is_plain: coinAddresses.map(() => true), + swap_address: pool.address.toLowerCase(), + token_address: pool.address.toLowerCase(), + gauge_address: pool.gaugeAddress ? pool.gaugeAddress.toLowerCase() : ethers.constants.AddressZero, + underlying_coins: coinNames, + coins: coinNames, + underlying_coin_addresses: coinAddresses, + coin_addresses: coinAddresses, + swap_abi: implementationABIDict[pool.implementationAddress], + gauge_abi: factoryGaugeABI, + is_factory: true, + is_plain_factory: true, + }; + } + }) + + return FACTORY_POOLS_DATA +} diff --git a/src/interfaces.ts b/src/interfaces.ts index 5f16d421..eb908196 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -19,6 +19,8 @@ export interface ICurve { } export interface PoolDataInterface { + name?: string, + symbol?: string, reference_asset: 'USD' | 'EUR' | 'BTC' | 'ETH' | 'LINK' | 'CRYPTO' | 'OTHER', N_COINS: number, underlying_decimals: number[], From 48557e077c5709f6874dc704e8cbe2854044deee Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Sat, 19 Mar 2022 14:39:30 +0300 Subject: [PATCH 04/16] chore: pool full_name --- src/factory/factory-api.ts | 6 ++++-- src/interfaces.ts | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts index 17fc95dd..6cfda1e9 100644 --- a/src/factory/factory-api.ts +++ b/src/factory/factory-api.ts @@ -115,7 +115,8 @@ export async function getFactoryPoolsDataFromApi(this: ICurve): Promise Date: Mon, 21 Mar 2022 14:18:17 +0300 Subject: [PATCH 05/16] chore: useApi arg in fetchFactoryPools() --- src/curve.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/curve.ts b/src/curve.ts index 94ebe56c..6bf91ef0 100644 --- a/src/curve.ts +++ b/src/curve.ts @@ -2,6 +2,7 @@ import { ethers, Contract } from "ethers"; import { Networkish } from "@ethersproject/networks"; import { Provider as MulticallProvider, Contract as MulticallContract } from 'ethcall'; import { getFactoryPoolData } from "./factory"; +import { getFactoryPoolsDataFromApi } from "./factory/factory-api"; import { getCryptoFactoryPoolData } from "./factory-crypto"; import {PoolDataInterface, DictInterface, ICurve} from "./interfaces"; import ERC20Abi from './constants/abis/json/ERC20.json'; @@ -458,8 +459,12 @@ class Curve implements ICurve { } } - async fetchFactoryPools(): Promise { - this.constants.FACTORY_POOLS_DATA = await getFactoryPoolData.call(this); + async fetchFactoryPools({ useApi } = { useApi: true }): Promise { + if (useApi) { + this.constants.FACTORY_POOLS_DATA = await getFactoryPoolsDataFromApi.call(this); + } else { + this.constants.FACTORY_POOLS_DATA = await getFactoryPoolData.call(this); + } } async fetchCryptoFactoryPools(): Promise { From 83204e10232e19eaa8bdb228f943aeb35c30d177 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 14:19:36 +0300 Subject: [PATCH 06/16] fix: polygon plain factories exchange --- src/pools.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pools.ts b/src/pools.ts index 4dec576c..0e5c410b 100644 --- a/src/pools.ts +++ b/src/pools.ts @@ -1584,28 +1584,28 @@ export class Pool { public exchangeIsApproved = async (inputCoin: string | number, amount: string): Promise => { const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || - (curve.chainId === 137 && this.isFactory) ? this.zap as string : this.swap; + (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await hasAllowance([this.underlyingCoinAddresses[i]], [amount], curve.signerAddress, contractAddress); } private exchangeApproveEstimateGas = async (inputCoin: string | number, amount: string): Promise => { const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || - (curve.chainId === 137 && this.isFactory) ? this.zap as string : this.swap; + (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await ensureAllowanceEstimateGas([this.underlyingCoinAddresses[i]], [amount], contractAddress); } public exchangeApprove = async (inputCoin: string | number, amount: string): Promise => { const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || - (curve.chainId === 137 && this.isFactory) ? this.zap as string : this.swap; + (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await ensureAllowance([this.underlyingCoinAddresses[i]], [amount], contractAddress); } private exchangeEstimateGas = async (inputCoin: string | number, outputCoin: string | number, amount: string, maxSlippage = 0.01): Promise => { const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || - (curve.chainId === 137 && this.isFactory) ? this.zap as string : this.swap; + (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); const j = this._getCoinIdx(outputCoin); @@ -1630,7 +1630,7 @@ export class Pool { if (this.name === "tricrypto2") { return (await contract.estimateGas[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value })).toNumber(); - } else if (curve.chainId === 137 && this.isFactory) { + } else if (curve.chainId === 137 && this.isMetaFactory) { return (await contract.estimateGas[exchangeMethod](this.swap, i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value })).toNumber(); } @@ -1639,7 +1639,7 @@ export class Pool { public exchange = async (inputCoin: string | number, outputCoin: string | number, amount: string, maxSlippage = 0.01): Promise => { const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || - (curve.chainId === 137 && this.isFactory) ? this.zap as string : this.swap; + (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); const j = this._getCoinIdx(outputCoin); @@ -1659,7 +1659,7 @@ export class Pool { if (this.name === 'tricrypto2') { const gasLimit = (await contract.estimateGas[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value })).mul(130).div(100); return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.options, value, gasLimit })).hash - } else if (curve.chainId === 137 && this.isFactory) { + } else if (curve.chainId === 137 && this.isMetaFactory) { const gasLimit = (await contract.estimateGas[exchangeMethod](this.swap, i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value })).mul(140).div(100); return (await contract[exchangeMethod](this.swap, i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash } From 225e17c1721339ab288abc7c6cae336ff5ff8676 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 14:26:36 +0300 Subject: [PATCH 07/16] fix: factory coins adding addresses to constants --- src/factory/factory-api.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts index 6cfda1e9..a086f677 100644 --- a/src/factory/factory-api.ts +++ b/src/factory/factory-api.ts @@ -24,8 +24,6 @@ import { basePoolAddressZapDictPolygon, } from "./constants"; -const url = "https://api.curve.fi/api/getPools/ethereum/factory"; - function setFactorySwapContracts(this: ICurve, rawPoolList: any[]): void { const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; rawPoolList.forEach((pool) => { @@ -34,32 +32,35 @@ function setFactorySwapContracts(this: ICurve, rawPoolList: any[]): void { contract: new Contract(addr, implementationABIDict[pool.implementationAddress], this.signer || this.provider), multicallContract: new MulticallContract(addr, implementationABIDict[pool.implementationAddress]), } + this.constants.LP_TOKENS.push(addr); }); } function setFactoryGaugeContracts(this: ICurve, rawPoolList: any[]): void { rawPoolList.forEach((pool) => { - if (pool.gaugeAddresses) { - const addr = pool.gaugeAddresses.toLowerCase() + if (pool.gaugeAddress) { + const addr = pool.gaugeAddress.toLowerCase(); this.contracts[addr] = { contract: new Contract(addr, factoryGaugeABI, this.signer || this.provider), multicallContract: new MulticallContract(addr, factoryGaugeABI), } + this.constants.GAUGES.push(addr); } }); } function setFactoryCoinsContracts(this: ICurve, rawPoolList: any[]): void { - const coinAddresses = Array.from(rawPoolList.reduce((coins: Set, pool) => { - pool.coins.forEach((c) => coins.add(c.address.toLowerCase())) - return coins; - }, new Set([]))); + for (const pool of rawPoolList) { + for (const coin of pool.coins) { + const addr = coin.address.toLowerCase(); + if (addr in this.contracts) continue; - for (const addr of coinAddresses) { - if (addr in this.contracts) continue; - this.contracts[addr] = { - contract: new Contract(addr, ERC20ABI, this.signer || this.provider), - multicallContract: new MulticallContract(addr, ERC20ABI), + this.contracts[addr] = { + contract: new Contract(addr, ERC20ABI, this.signer || this.provider), + multicallContract: new MulticallContract(addr, ERC20ABI), + } + + this.constants.DECIMALS_LOWER_CASE[addr] = Number(coin.decimals); } } } @@ -86,6 +87,8 @@ function setFactoryZapContracts(this: ICurve): void { } export async function getFactoryPoolsDataFromApi(this: ICurve): Promise> { + const network = this.chainId === 137 ? "polygon" : "ethereum"; + const url = `https://api.curve.fi/api/getPools/${network}/factory`; const response = await axios.get(url); const rawPoolList = response.data.data.poolData; setFactorySwapContracts.call(this, rawPoolList); From 9a8570878a17be245e22383ac8cd533d06899400 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 15:52:07 +0300 Subject: [PATCH 08/16] feat: name, full_name and symbol in poolData --- src/constants/abis/abis-ethereum.ts | 138 +++++++++++++++++++++++ src/constants/abis/abis-polygon.ts | 12 ++ src/interfaces.ts | 4 +- src/pools.ts | 168 ++++++++++++++-------------- 4 files changed, 239 insertions(+), 83 deletions(-) diff --git a/src/constants/abis/abis-ethereum.ts b/src/constants/abis/abis-ethereum.ts index 1b412119..536e6538 100644 --- a/src/constants/abis/abis-ethereum.ts +++ b/src/constants/abis/abis-ethereum.ts @@ -88,6 +88,9 @@ import { PoolDataInterface } from "../../interfaces"; export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { compound: { + name: "compound", + full_name: "compound", + symbol: "compound", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 6], @@ -119,6 +122,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, usdt: { + name: "usdt", + full_name: "usdt", + symbol: "usdt", reference_asset: 'USD', N_COINS: 3, underlying_decimals: [18, 6, 6], @@ -148,6 +154,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, y: { + name: "y", + full_name: "y", + symbol: "Y", reference_asset: 'USD', N_COINS: 4, underlying_decimals: [18, 6, 6, 18], @@ -182,6 +191,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeABI, }, busd: { + name: "busd", + full_name: "busd", + symbol: "busd", reference_asset: 'USD', N_COINS: 4, underlying_decimals: [18, 6, 6, 18], @@ -213,6 +225,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, susd: { + name: "susd", + full_name: "susd", + symbol: "susd", reference_asset: 'USD', swap_abi: susdv2SwapABI, deposit_abi: susdv2DepositABI, @@ -247,6 +262,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, pax: { + name: "pax", + full_name: "pax", + symbol: "pax", reference_asset: 'USD', swap_abi: paxSwapABI, deposit_abi: paxDepositABI, @@ -278,6 +296,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, ren: { + name: "ren", + full_name: "ren", + symbol: "ren", reference_asset: 'BTC', N_COINS: 2, underlying_decimals: [8, 8], @@ -307,6 +328,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, sbtc: { + name: "sbtc", + full_name: "sbtc", + symbol: "sbtc", reference_asset: 'BTC', N_COINS: 3, underlying_decimals: [8, 8, 18], @@ -340,6 +364,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, hbtc: { + name: "hbtc", + full_name: "hbtc", + symbol: "hbtc", reference_asset: 'BTC', swap_abi: hbtcSwapABI, N_COINS: 2, @@ -365,6 +392,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, '3pool': { + name: "3pool", + full_name: "3pool", + symbol: "3pool", reference_asset: 'USD', swap_abi: tripoolSwapABI, N_COINS: 3, @@ -392,6 +422,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, gusd: { + name: "gusd", + full_name: "gusd", + symbol: "gusd", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [2, 18], @@ -437,6 +470,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, husd: { + name: "husd", + full_name: "husd", + symbol: "husd", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [8, 18], @@ -482,6 +518,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, usdk: { + name: "usdk", + full_name: "usdk", + symbol: "usdk", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 18], @@ -527,6 +566,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, usdn: { + name: "usdn", + full_name: "usdn", + symbol: "usdn", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 18], @@ -572,6 +614,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, musd: { + name: "musd", + full_name: "musd", + symbol: "musd", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 18], @@ -620,6 +665,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, rsv: { + name: "rsv", + full_name: "rsv", + symbol: "rsv", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 18], @@ -668,6 +716,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, tbtc: { + name: "tbtc", + full_name: "tbtc", + symbol: "tbtc", reference_asset: 'BTC', N_COINS: 2, underlying_decimals: [18, 18], @@ -715,6 +766,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, dusd: { + name: "dusd", + full_name: "dusd", + symbol: "dusd", reference_asset: 'USD', N_COINS: 2, underlying_decimals: [18, 18], @@ -763,6 +817,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, pbtc: { + name: "pbtc", + full_name: "pbtc", + symbol: "pbtc", reference_asset: 'BTC', swap_abi: pbtcSwapABI, N_COINS: 2, @@ -811,6 +868,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, bbtc: { + name: "bbtc", + full_name: "bbtc", + symbol: "bbtc", reference_asset: 'BTC', swap_abi: bbtcSwapABI, N_COINS: 2, @@ -856,6 +916,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, obtc: { + name: "obtc", + full_name: "obtc", + symbol: "obtc", reference_asset: 'BTC', swap_abi: obtcSwapABI, N_COINS: 2, @@ -904,6 +967,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, seth: { + name: "seth", + full_name: "seth", + symbol: "seth", reference_asset: 'ETH', swap_abi: sethSwapABI, N_COINS: 2, @@ -930,6 +996,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, eurs: { + name: "eurs", + full_name: "eurs", + symbol: "eurs", reference_asset: 'EUR', swap_abi: eursSwapABI, N_COINS: 2, @@ -958,6 +1027,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, ust: { + name: "ust", + full_name: "ust", + symbol: "ust", reference_asset: 'USD', swap_abi: ustSwapABI, N_COINS: 2, @@ -1003,6 +1075,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, aave: { + name: "aave", + full_name: "aave", + symbol: "aave", reference_asset: 'USD', N_COINS: 3, is_aave: true, @@ -1034,6 +1109,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, steth: { + name: "steth", + full_name: "steth", + symbol: "steth", reference_asset: 'ETH', swap_abi: stethSwapABI, N_COINS: 2, @@ -1063,6 +1141,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, saave: { + name: "saave", + full_name: "saave", + symbol: "saave", reference_asset: 'USD', N_COINS: 2, is_aave: true, @@ -1092,6 +1173,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, ankreth: { + name: "ankreth", + full_name: "ankreth", + symbol: "ankreth", reference_asset: 'ETH', swap_abi: ankrethSwapABI, N_COINS: 2, @@ -1121,6 +1205,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, usdp: { + name: "usdp", + full_name: "usdp", + symbol: "usdp", reference_asset: 'USD', swap_abi: usdpSwapABI, N_COINS: 2, @@ -1166,6 +1253,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, ib: { + name: "ib", + full_name: "ib", + symbol: "ib", reference_asset: 'USD', swap_abi: ibSwapABI, N_COINS: 3, @@ -1194,6 +1284,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, link: { + name: "link", + full_name: "link", + symbol: "link", reference_asset: 'LINK', swap_abi: linkSwapABI, N_COINS: 2, @@ -1218,6 +1311,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV2ABI, }, tusd: { + name: "tusd", + full_name: "tusd", + symbol: "tusd", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1263,6 +1359,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV2ABI, }, frax: { + name: "frax", + full_name: "frax", + symbol: "frax", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1311,6 +1410,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV2ABI, }, lusd: { + name: "lusd", + full_name: "lusd", + symbol: "lusd", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1359,6 +1461,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV2ABI, }, busdv2: { + name: "busdv2", + full_name: "busdv2", + symbol: "busdv2", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1404,6 +1509,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV2ABI, }, reth: { + name: "reth", + full_name: "reth", + symbol: "reth", reference_asset: 'ETH', swap_abi: rethSwapABI, N_COINS: 2, @@ -1432,6 +1540,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV3ABI, }, alusd: { + name: "alusd", + full_name: "alusd", + symbol: "alusd", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1480,6 +1591,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV3ABI, }, mim: { + name: "mim", + full_name: "mim", + symbol: "mim", reference_asset: 'USD', swap_abi: factorySwapABI, N_COINS: 2, @@ -1528,6 +1642,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeFactoryABI, }, tricrypto2: { + name: "tricrypto2", + full_name: "tricrypto2", + symbol: "tricrypto2", reference_asset: 'CRYPTO', swap_abi: tricrypto2SwapABI, N_COINS: 3, @@ -1558,6 +1675,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, eurt: { + name: "eurt", + full_name: "eurt", + symbol: "eurt", reference_asset: 'EUR', swap_abi: eurtSwapABI, N_COINS: 2, @@ -1583,6 +1703,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, eurtusd: { + name: "eurtusd", + full_name: "eurtusd", + symbol: "eurtusd", reference_asset: 'CRYPTO', N_COINS: 2, underlying_decimals: [6, 18], @@ -1629,6 +1752,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, crveth: { + name: "crveth", + full_name: "crveth", + symbol: "crveth", reference_asset: 'CRYPTO', swap_abi: crvethSwap, N_COINS: 2, @@ -1655,6 +1781,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { }, cvxeth: { + name: "cvxeth", + full_name: "cvxeth", + symbol: "cvxeth", reference_asset: 'CRYPTO', swap_abi: crvethSwap, N_COINS: 2, @@ -1680,6 +1809,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV4ABI, }, xautusd: { + name: "xautusd", + full_name: "xautusd", + symbol: "xautusd", reference_asset: 'CRYPTO', N_COINS: 2, underlying_decimals: [6, 18], @@ -1725,6 +1857,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV4ABI, }, spelleth: { + name: "spelleth", + full_name: "spelleth", + symbol: "spelleth", reference_asset: 'CRYPTO', N_COINS: 2, is_crypto: true, @@ -1750,6 +1885,9 @@ export const POOLS_DATA_ETHEREUM: { [index: string]: PoolDataInterface } = { gauge_abi: gaugeV4ABI, }, teth: { + name: "teth", + full_name: "teth", + symbol: "teth", reference_asset: 'CRYPTO', N_COINS: 2, is_crypto: true, diff --git a/src/constants/abis/abis-polygon.ts b/src/constants/abis/abis-polygon.ts index 0d895d6e..e02ec095 100644 --- a/src/constants/abis/abis-polygon.ts +++ b/src/constants/abis/abis-polygon.ts @@ -10,6 +10,9 @@ import {PoolDataInterface} from "../../interfaces"; export const POOLS_DATA_POLYGON: { [index: string]: PoolDataInterface } = { aave: { + name: "aave", + full_name: "aave", + symbol: "aave", reference_asset: 'USD', N_COINS: 3, is_aave: true, @@ -42,6 +45,9 @@ export const POOLS_DATA_POLYGON: { [index: string]: PoolDataInterface } = { }, ren: { + name: "ren", + full_name: "ren", + symbol: "ren", reference_asset: 'BTC', N_COINS: 2, is_aave: true, @@ -70,6 +76,9 @@ export const POOLS_DATA_POLYGON: { [index: string]: PoolDataInterface } = { }, atricrypto3: { + name: "atricrypto3", + full_name: "atricrypto3", + symbol: "atricrypto3", reference_asset: 'CRYPTO', swap_abi: atricrypto3Swap, deposit_abi: atricrypto3Zap, @@ -112,6 +121,9 @@ export const POOLS_DATA_POLYGON: { [index: string]: PoolDataInterface } = { }, eurtusd: { + name: "eurtusd", + full_name: "eurtusd", + symbol: "eurtusd", reference_asset: 'CRYPTO', N_COINS: 2, underlying_decimals: [6, 18], diff --git a/src/interfaces.ts b/src/interfaces.ts index 10168a2d..68b61151 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -19,9 +19,9 @@ export interface ICurve { } export interface PoolDataInterface { - name?: string, + name: string, full_name: string, - symbol?: string, + symbol: string, reference_asset: 'USD' | 'EUR' | 'BTC' | 'ETH' | 'LINK' | 'CRYPTO' | 'OTHER', N_COINS: number, underlying_decimals: number[], diff --git a/src/pools.ts b/src/pools.ts index 0e5c410b..5e46ecc1 100644 --- a/src/pools.ts +++ b/src/pools.ts @@ -39,7 +39,10 @@ import axios from "axios"; export class Pool { + id: string; name: string; + fullName: string; + symbol: string; referenceAsset: string; swap: string; zap: string | null; @@ -99,10 +102,13 @@ export class Pool { getRewardsApy: () => Promise, } - constructor(name: string) { + constructor(id: string) { const poolData = { ...POOLS_DATA, ...(curve.constants.FACTORY_POOLS_DATA || {}), ...(curve.constants.CRYPTO_FACTORY_POOLS_DATA || {}) }[name]; - this.name = name; + this.id = id; + this.name = poolData.name; + this.fullName = poolData.full_name; + this.symbol = poolData.symbol; this.referenceAsset = poolData.reference_asset; this.swap = poolData.swap_address; this.zap = poolData.deposit_address || null; @@ -179,9 +185,9 @@ export class Pool { ethers.utils.parseUnits(amount, this.underlyingDecimals[i])); let _expected: ethers.BigNumber; if ( - ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { _expected = await this._calcLpTokenAmountWithUnderlying(_amounts, isDeposit); // Lending pools } else if (this.isMeta) { @@ -249,7 +255,7 @@ export class Pool { ] - const A_PRECISION = curve.chainId === 1 && ['compound', 'usdt', 'y', 'busd', 'susd', 'pax', 'ren', 'sbtc', 'hbtc', '3pool'].includes(this.name) ? 1 : 100; + const A_PRECISION = curve.chainId === 1 && ['compound', 'usdt', 'y', 'busd', 'susd', 'pax', 'ren', 'sbtc', 'hbtc', '3pool'].includes(this.id) ? 1 : 100; const [_future_A, _initial_A, _future_A_time, _initial_A_time] = await curve.multicallProvider.all(additionalCalls) as ethers.BigNumber[] const [future_A, initial_A, future_A_time, initial_A_time] = [ _future_A ? String(Number(ethers.utils.formatUnits(_future_A, 0)) / A_PRECISION) : undefined, @@ -268,20 +274,20 @@ export class Pool { let _poolUnderlyingBalances: ethers.BigNumber[] = []; if (this.isMeta) { - if (this.name !== 'atricrypto3') { + if (this.id !== 'atricrypto3') { _poolWrappedBalances.unshift(_poolWrappedBalances.pop() as ethers.BigNumber); } const [_poolMetaCoinBalance, ..._poolUnderlyingBalance] = _poolWrappedBalances; const basePool = new Pool(this.basePool); const _basePoolExpectedAmounts = await basePool._calcExpectedAmounts(_poolMetaCoinBalance); - _poolUnderlyingBalances = this.name !== 'atricrypto3' ? + _poolUnderlyingBalances = this.id !== 'atricrypto3' ? [..._poolUnderlyingBalance, ..._basePoolExpectedAmounts] : [..._basePoolExpectedAmounts, ..._poolUnderlyingBalance]; } else if ( - ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { const _rates: ethers.BigNumber[] = await this._getRates(); _poolUnderlyingBalances = _poolWrappedBalances.map( @@ -320,7 +326,7 @@ export class Pool { private _getPoolStats = async (): Promise => { const statsUrl = this.isFactory ? _getFactoryStatsUrl() : _getStatsUrl(this.isCrypto); - const name = (this.name === 'ren' && curve.chainId === 1) ? 'ren2' : this.name === 'sbtc' ? 'rens' : this.name; + const name = (this.id === 'ren' && curve.chainId === 1) ? 'ren2' : this.id === 'sbtc' ? 'rens' : this.id; const key = this.isFactory ? this.swap.toLowerCase() : name; if (this.isFactory) { @@ -478,14 +484,14 @@ export class Pool { // Lending pools with zap - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id)) { return await this._addLiquidityZap(_amounts, true) as number; } // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._addLiquidity(_amounts, true, true) as number; } @@ -525,14 +531,14 @@ export class Pool { await curve.updateFeeData(); // Lending pools with zap - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id)) { return await this._addLiquidityZap(_amounts) as string; } // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._addLiquidity(_amounts, true) as string; } @@ -644,9 +650,9 @@ export class Pool { const contract = curve.contracts[ALIASES.deposit_and_stake].contract; const useUnderlying = isUnderlying && ( - ['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + ['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ); const _minMintAmount = isUnderlying ? ethers.utils.parseUnits(await this.depositAndStakeExpected(amounts)).mul(99).div(100) : @@ -786,9 +792,9 @@ export class Pool { ethers.utils.parseUnits(amount, this.decimals[i])); // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._addLiquidity(_amounts, false, true) as number; } @@ -811,9 +817,9 @@ export class Pool { await curve.updateFeeData(); // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._addLiquidity(_amounts, false) as string; } @@ -910,9 +916,9 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); let _expected: ethers.BigNumber[]; - if (['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { _expected = await this._calcExpectedUnderlyingAmounts(_lpTokenAmount); // Lending pools } else if (this.isMeta) { @@ -951,13 +957,13 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id)) { return await this._removeLiquidityZap(_lpTokenAmount, true) as number; } - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidity(_lpTokenAmount, true, true) as number; } @@ -974,13 +980,13 @@ export class Pool { await curve.updateFeeData(); - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id)) { return await this._removeLiquidityZap(_lpTokenAmount) as string; } - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidity(_lpTokenAmount, true) as string; } @@ -1015,9 +1021,9 @@ export class Pool { throw Error(`Not enough LP tokens. Actual: ${lpTokenBalance}, required: ${lpTokenAmount}`); } - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidity(_lpTokenAmount, false, true) as number; } @@ -1034,9 +1040,9 @@ export class Pool { await curve.updateFeeData(); - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidity(_lpTokenAmount, false) as string; } @@ -1071,7 +1077,7 @@ export class Pool { const _amounts: ethers.BigNumber[] = amounts.map((amount: string, i: number) => ethers.utils.parseUnits(amount, this.underlyingDecimals[i])); - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { const _maxBurnAmount = (await this._calcLpTokenAmountWithUnderlying(_amounts, false)).mul(101).div(100); return await hasAllowance([this.lpToken], [ethers.utils.formatUnits(_maxBurnAmount, 18)], curve.signerAddress, this.zap as string); } else if (this.isMeta) { @@ -1089,7 +1095,7 @@ export class Pool { const _amounts: ethers.BigNumber[] = amounts.map((amount: string, i: number) => ethers.utils.parseUnits(amount, this.underlyingDecimals[i])); - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { const _maxBurnAmount = (await this._calcLpTokenAmountWithUnderlying(_amounts, false)).mul(101).div(100); return await ensureAllowanceEstimateGas([this.lpToken], [ethers.utils.formatUnits(_maxBurnAmount, 18)], this.zap as string); } else if (this.isMeta) { @@ -1107,7 +1113,7 @@ export class Pool { const _amounts: ethers.BigNumber[] = amounts.map((amount: string, i: number) => ethers.utils.parseUnits(amount, this.underlyingDecimals[i])); - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { const _maxBurnAmount = (await this._calcLpTokenAmountWithUnderlying(_amounts, false)).mul(101).div(100); return await ensureAllowance([this.lpToken], [ethers.utils.formatUnits(_maxBurnAmount, 18)], this.zap as string); } else if (this.isMeta) { @@ -1136,12 +1142,12 @@ export class Pool { const _amounts: ethers.BigNumber[] = amounts.map((amount: string, i: number) => ethers.utils.parseUnits(amount, this.underlyingDecimals[i])); // Lending pools with zap - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { return await this._removeLiquidityImbalanceZap(_amounts, true) as number; } // Lending pools without zap - if (['aave', 'saave', 'ib'].includes(this.name) || (curve.chainId === 137 && this.name === 'ren')) { + if (['aave', 'saave', 'ib'].includes(this.id) || (curve.chainId === 137 && this.id === 'ren')) { return await this._removeLiquidityImbalance(_amounts, true, true) as number; } @@ -1163,12 +1169,12 @@ export class Pool { await curve.updateFeeData(); // Lending pools with zap - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { return await this._removeLiquidityImbalanceZap(_amounts) as string; } // Lending pools without zap - if (['aave', 'saave', 'ib'].includes(this.name) || (curve.chainId === 137 && this.name === 'ren')) { + if (['aave', 'saave', 'ib'].includes(this.id) || (curve.chainId === 137 && this.id === 'ren')) { return await this._removeLiquidityImbalance(_amounts, true) as string; } @@ -1213,7 +1219,7 @@ export class Pool { const _amounts: ethers.BigNumber[] = amounts.map((amount: string, i: number) => ethers.utils.parseUnits(amount, this.decimals[i])); - if (['aave', 'saave', 'ib'].includes(this.name) || (curve.chainId === 137 && this.name === 'ren')) { + if (['aave', 'saave', 'ib'].includes(this.id) || (curve.chainId === 137 && this.id === 'ren')) { return await this._removeLiquidityImbalance(_amounts, false, true) as number; } @@ -1229,7 +1235,7 @@ export class Pool { await curve.updateFeeData(); - if (['aave', 'saave', 'ib'].includes(this.name) || (curve.chainId === 137 && this.name === 'ren')) { + if (['aave', 'saave', 'ib'].includes(this.id) || (curve.chainId === 137 && this.id === 'ren')) { return await this._removeLiquidityImbalance(_amounts, false, estimateGas); } @@ -1241,9 +1247,9 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); let _expected: ethers.BigNumber; - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name) || this.name === 'susd' || this.isMeta) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id) || this.id === 'susd' || this.isMeta) { _expected = await this._calcWithdrawOneCoinZap(_lpTokenAmount, i); // Lending pools with zap, susd and metapools - } else if (this.name === 'ib') { + } else if (this.id === 'ib') { _expected = await this._calcWithdrawOneCoin(_lpTokenAmount, i, true); // ib } else { _expected = await this._calcWithdrawOneCoinSwap(_lpTokenAmount, i); // Aave, saave and plain pools @@ -1292,14 +1298,14 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); // Lending pools with zap, susd and metapools - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name) || this.name === 'susd' || this.isMeta) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id) || this.id === 'susd' || this.isMeta) { return await this._removeLiquidityOneCoinZap(_lpTokenAmount, i, true) as number; } // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidityOneCoin(_lpTokenAmount, i,true, true) as number; } @@ -1315,14 +1321,14 @@ export class Pool { await curve.updateFeeData(); // Lending pools with zap, susd and metapools - if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.name) || this.name === 'susd' || this.isMeta) { + if (['compound', 'usdt', 'y', 'busd', 'pax', 'tricrypto2'].includes(this.id) || this.id === 'susd' || this.isMeta) { return await this._removeLiquidityOneCoinZap(_lpTokenAmount, i) as string; } // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidityOneCoin(_lpTokenAmount, i,true) as string; } @@ -1336,7 +1342,7 @@ export class Pool { throw Error(`${this.name} pool doesn't have this method`); } - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { throw Error(`${this.name} pool doesn't have remove_liquidity_one_coin method for wrapped tokens`); } @@ -1344,7 +1350,7 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); let _expected: ethers.BigNumber; - if (this.name === 'ib') { + if (this.id === 'ib') { _expected = await this._calcWithdrawOneCoin(_lpTokenAmount, i, false); // ib } else { _expected = await this._calcWithdrawOneCoinSwap(_lpTokenAmount, i); // All other pools @@ -1380,16 +1386,16 @@ export class Pool { } const i = this._getCoinIdx(coin, false); - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { throw Error(`${this.name} pool doesn't have remove_liquidity_one_coin method for wrapped tokens`); } const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidityOneCoin(_lpTokenAmount, i,false, true) as number; } @@ -1404,7 +1410,7 @@ export class Pool { } const i = this._getCoinIdx(coin, false); - if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.name)) { + if (['compound', 'usdt', 'y', 'busd', 'pax'].includes(this.id)) { throw Error(`${this.name} pool doesn't have remove_liquidity_one_coin method for wrapped tokens`); } @@ -1413,9 +1419,9 @@ export class Pool { const _lpTokenAmount = ethers.utils.parseUnits(lpTokenAmount); // Lending pools without zap - if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.name) || + if (['aave', 'saave', 'ib', 'crveth', "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory || - (curve.chainId === 137 && this.name === 'ren') + (curve.chainId === 137 && this.id === 'ren') ) { return await this._removeLiquidityOneCoin(_lpTokenAmount, i,false) as string; } @@ -1583,28 +1589,28 @@ export class Pool { } public exchangeIsApproved = async (inputCoin: string | number, amount: string): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) || (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await hasAllowance([this.underlyingCoinAddresses[i]], [amount], curve.signerAddress, contractAddress); } private exchangeApproveEstimateGas = async (inputCoin: string | number, amount: string): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) || (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await ensureAllowanceEstimateGas([this.underlyingCoinAddresses[i]], [amount], contractAddress); } public exchangeApprove = async (inputCoin: string | number, amount: string): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) || (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); return await ensureAllowance([this.underlyingCoinAddresses[i]], [amount], contractAddress); } private exchangeEstimateGas = async (inputCoin: string | number, outputCoin: string | number, amount: string, maxSlippage = 0.01): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) || (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); const j = this._getCoinIdx(outputCoin); @@ -1628,7 +1634,7 @@ export class Pool { const exchangeMethod = Object.prototype.hasOwnProperty.call(contract, 'exchange_underlying') ? 'exchange_underlying' : 'exchange'; const value = isEth(this.underlyingCoinAddresses[i]) ? _amount : ethers.BigNumber.from(0); - if (this.name === "tricrypto2") { + if (this.id === "tricrypto2") { return (await contract.estimateGas[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value })).toNumber(); } else if (curve.chainId === 137 && this.isMetaFactory) { return (await contract.estimateGas[exchangeMethod](this.swap, i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value })).toNumber(); @@ -1638,7 +1644,7 @@ export class Pool { } public exchange = async (inputCoin: string | number, outputCoin: string | number, amount: string, maxSlippage = 0.01): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) || + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) || (curve.chainId === 137 && this.isMetaFactory) ? this.zap as string : this.swap; const i = this._getCoinIdx(inputCoin); const j = this._getCoinIdx(outputCoin); @@ -1656,7 +1662,7 @@ export class Pool { await curve.updateFeeData(); - if (this.name === 'tricrypto2') { + if (this.id === 'tricrypto2') { const gasLimit = (await contract.estimateGas[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.constantOptions, value })).mul(130).div(100); return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, true, { ...curve.options, value, gasLimit })).hash } else if (curve.chainId === 137 && this.isMetaFactory) { @@ -1665,7 +1671,7 @@ export class Pool { } const estimatedGas = await contract.estimateGas[exchangeMethod](i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value }); - const gasLimit = curve.chainId === 137 && this.name === 'ren' ? + const gasLimit = curve.chainId === 137 && this.id === 'ren' ? estimatedGas.mul(160).div(100) : estimatedGas.mul(130).div(100); return (await contract[exchangeMethod](i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash @@ -1737,7 +1743,7 @@ export class Pool { const contract = curve.contracts[this.swap].contract; const value = isEth(this.coinAddresses[i]) ? _amount : ethers.BigNumber.from(0); - if (this.name === 'tricrypto2') { + if (this.id === 'tricrypto2') { return (await contract.estimateGas.exchange(i, j, _amount, _minRecvAmount, false, { ...curve.constantOptions, value })).toNumber() } @@ -1763,13 +1769,13 @@ export class Pool { const value = isEth(this.coinAddresses[i]) ? _amount : ethers.BigNumber.from(0); await curve.updateFeeData(); - if (this.name === 'tricrypto2') { + if (this.id === 'tricrypto2') { const gasLimit = (await contract.estimateGas.exchange(i, j, _amount, _minRecvAmount, false, { ...curve.constantOptions, value })).mul(130).div(100); return (await contract.exchange(i, j, _amount, _minRecvAmount, false, { ...curve.options, value, gasLimit })).hash } const estimatedGas = await contract.estimateGas.exchange(i, j, _amount, _minRecvAmount, { ...curve.constantOptions, value }); - const gasLimit = curve.chainId === 137 && this.name === 'ren' ? + const gasLimit = curve.chainId === 137 && this.id === 'ren' ? estimatedGas.mul(140).div(100) : estimatedGas.mul(130).div(100); return (await contract.exchange(i, j, _amount, _minRecvAmount, { ...curve.options, value, gasLimit })).hash @@ -1913,9 +1919,9 @@ export class Pool { for (let i = 0; i < this.coinAddresses.length; i++) { const addr = this.coinAddresses[i]; if (this.useLending[i]) { - if (['compound', 'usdt', 'ib'].includes(this.name)) { + if (['compound', 'usdt', 'ib'].includes(this.id)) { _rates.push(await curve.contracts[addr].contract.exchangeRateStored()); - } else if (['y', 'busd', 'pax'].includes(this.name)) { + } else if (['y', 'busd', 'pax'].includes(this.id)) { _rates.push(await curve.contracts[addr].contract.getPricePerFullShare()); } else { _rates.push(ethers.BigNumber.from(10).pow(18)); // Aave ratio 1:1 @@ -2053,7 +2059,7 @@ export class Pool { private _calcLpTokenAmount = async (_amounts: ethers.BigNumber[], isDeposit = true): Promise => { const contract = curve.contracts[this.swap].contract; - if (["eurtusd", "xautusd", "crveth", "cvxeth", "spelleth", "teth"].includes(this.name) || this.isCryptoFactory) { + if (["eurtusd", "xautusd", "crveth", "cvxeth", "spelleth", "teth"].includes(this.id) || this.isCryptoFactory) { return await contract.calc_token_amount(_amounts, curve.constantOptions); } @@ -2067,7 +2073,7 @@ export class Pool { return await contract.calc_token_amount(this.swap, _amounts, isDeposit, curve.constantOptions); } - if (["eurtusd", "xautusd"].includes(this.name)) { + if (["eurtusd", "xautusd"].includes(this.id)) { return await contract.calc_token_amount(_amounts, curve.constantOptions); } @@ -2205,7 +2211,7 @@ export class Pool { private _calcExpectedUnderlyingAmountsMeta = async (_lpTokenAmount: ethers.BigNumber): Promise => { const _expectedWrappedAmounts = await this._calcExpectedAmounts(_lpTokenAmount); - if (this.name !== 'atricrypto3') { + if (this.id !== 'atricrypto3') { _expectedWrappedAmounts.unshift(_expectedWrappedAmounts.pop() as ethers.BigNumber); } const [_expectedMetaCoinAmount, ..._expectedUnderlyingAmounts] = _expectedWrappedAmounts; @@ -2213,7 +2219,7 @@ export class Pool { const basePool = new Pool(this.basePool); const _basePoolExpectedAmounts = await basePool._calcExpectedAmounts(_expectedMetaCoinAmount); - return this.name !== 'atricrypto3' ? + return this.id !== 'atricrypto3' ? [..._expectedUnderlyingAmounts, ..._basePoolExpectedAmounts] : [..._basePoolExpectedAmounts, ..._expectedUnderlyingAmounts]; } @@ -2360,7 +2366,7 @@ export class Pool { return gas.toNumber() } - const gasLimit = curve.chainId === 137 && this.name === 'ren' ? + const gasLimit = curve.chainId === 137 && this.id === 'ren' ? gas.mul(140).div(100) : gas.mul(130).div(100); return (await contract.remove_liquidity_imbalance(_amounts, _maxBurnAmount, useUnderlying, { ...curve.options, gasLimit })).hash; @@ -2402,7 +2408,7 @@ export class Pool { await _ensureAllowance([this.lpToken], [_lpTokenAmount], this.zap as string); } - let _minAmount = this.name === 'tricrypto2' ? + let _minAmount = this.id === 'tricrypto2' ? await this._calcWithdrawOneCoinSwap(_lpTokenAmount, i) : await this._calcWithdrawOneCoinZap(_lpTokenAmount, i); _minAmount = _minAmount.mul(99).div(100); @@ -2428,7 +2434,7 @@ export class Pool { } private _removeLiquidityOneCoin = async (_lpTokenAmount: ethers.BigNumber, i: number, useUnderlying = true, estimateGas = false): Promise => { - let _minAmount = this.name === 'ib' ? + let _minAmount = this.id === 'ib' ? await this._calcWithdrawOneCoin(_lpTokenAmount, i, useUnderlying) : await this._calcWithdrawOneCoinSwap(_lpTokenAmount, i); _minAmount = _minAmount.mul(99).div(100); @@ -2439,14 +2445,14 @@ export class Pool { return gas.toNumber() } - const gasLimit = curve.chainId === 137 && this.name === 'ren' ? + const gasLimit = curve.chainId === 137 && this.id === 'ren' ? gas.mul(160).div(100) : gas.mul(130).div(100); return (await contract.remove_liquidity_one_coin(_lpTokenAmount, i, _minAmount, useUnderlying, { ...curve.options, gasLimit })).hash } private _getExchangeOutput = async (i: number, j: number, _amount: ethers.BigNumber): Promise => { - const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.name) ? this.zap as string : this.swap; + const contractAddress = ["eurtusd", "xautusd", "atricrypto3"].includes(this.id) ? this.zap as string : this.swap; const contract = curve.contracts[contractAddress].contract; if (Object.prototype.hasOwnProperty.call(contract, 'get_dy_underlying')) { return await contract.get_dy_underlying(i, j, _amount, curve.constantOptions) From 6958f7076dde99d116bf0d506dbf3e9e6920f9b8 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 16:43:05 +0300 Subject: [PATCH 09/16] chore: types for api pool data --- src/factory/factory-api.ts | 14 +++++++------- src/interfaces.ts | 22 +++++++++++++++++++++- src/pools.ts | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts index a086f677..7f190f97 100644 --- a/src/factory/factory-api.ts +++ b/src/factory/factory-api.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import {Contract, ethers} from "ethers"; import { Contract as MulticallContract } from "ethcall"; -import { DictInterface, PoolDataInterface, ICurve } from "../interfaces"; +import { DictInterface, PoolDataInterface, ICurve, IPoolDataFromApi, REFERENCE_ASSET } from "../interfaces"; import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; import factoryDepositABI from "../constants/abis/json/factoryPools/deposit.json"; import ERC20ABI from "../constants/abis/json/ERC20.json"; @@ -24,7 +24,7 @@ import { basePoolAddressZapDictPolygon, } from "./constants"; -function setFactorySwapContracts(this: ICurve, rawPoolList: any[]): void { +function setFactorySwapContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]): void { const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; rawPoolList.forEach((pool) => { const addr = pool.address.toLowerCase(); @@ -36,7 +36,7 @@ function setFactorySwapContracts(this: ICurve, rawPoolList: any[]): void { }); } -function setFactoryGaugeContracts(this: ICurve, rawPoolList: any[]): void { +function setFactoryGaugeContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]): void { rawPoolList.forEach((pool) => { if (pool.gaugeAddress) { const addr = pool.gaugeAddress.toLowerCase(); @@ -49,7 +49,7 @@ function setFactoryGaugeContracts(this: ICurve, rawPoolList: any[]): void { }); } -function setFactoryCoinsContracts(this: ICurve, rawPoolList: any[]): void { +function setFactoryCoinsContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]): void { for (const pool of rawPoolList) { for (const coin of pool.coins) { const addr = coin.address.toLowerCase(); @@ -90,7 +90,7 @@ export async function getFactoryPoolsDataFromApi(this: ICurve): Promise; } +export type REFERENCE_ASSET = 'USD' | 'EUR' | 'BTC' | 'ETH' | 'LINK' | 'CRYPTO' | 'OTHER'; + export interface PoolDataInterface { name: string, full_name: string, symbol: string, - reference_asset: 'USD' | 'EUR' | 'BTC' | 'ETH' | 'LINK' | 'CRYPTO' | 'OTHER', + reference_asset: REFERENCE_ASSET, N_COINS: number, underlying_decimals: number[], decimals: number[], @@ -76,6 +78,24 @@ export interface PoolDataInterface { reward_contract?: string, } +export interface ICoinFromPoolDataApi { + address: string, + symbol: string, + decimals: string, +} + +export interface IPoolDataFromApi { + id: string, + name: string, + symbol: string, + assetTypeName: string, + address: string, + gaugeAddress?: string, + implementation: string, + implementationAddress: string, + coins: ICoinFromPoolDataApi[], +} + export interface RewardsApyInterface { token: string, symbol: string, diff --git a/src/pools.ts b/src/pools.ts index 5e46ecc1..5048a851 100644 --- a/src/pools.ts +++ b/src/pools.ts @@ -103,7 +103,7 @@ export class Pool { } constructor(id: string) { - const poolData = { ...POOLS_DATA, ...(curve.constants.FACTORY_POOLS_DATA || {}), ...(curve.constants.CRYPTO_FACTORY_POOLS_DATA || {}) }[name]; + const poolData = { ...POOLS_DATA, ...(curve.constants.FACTORY_POOLS_DATA || {}), ...(curve.constants.CRYPTO_FACTORY_POOLS_DATA || {}) }[id]; this.id = id; this.name = poolData.name; From 6c985753ae2be4a0b13b512d39008830e3bccf6e Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 17:25:01 +0300 Subject: [PATCH 10/16] feat: name, full_name and symbol in factories obtained from SC --- src/factory.ts | 58 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/factory.ts b/src/factory.ts index 7c9534f0..bdb4ad90 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -1,6 +1,6 @@ import { Contract, ethers } from "ethers"; import { Contract as MulticallContract } from "ethcall"; -import { DictInterface, PoolDataInterface, ICurve } from "./interfaces"; +import { DictInterface, PoolDataInterface, ICurve, REFERENCE_ASSET } from "./interfaces"; import ERC20ABI from "./constants/abis/json/ERC20.json"; import factorySwapABI from "./constants/abis/json/factoryPools/swap.json"; import factoryDepositABI from "./constants/abis/json/factoryPools/deposit.json"; @@ -164,7 +164,7 @@ const blackListEthereum: string[] = []; const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); -async function getFactorySwapAddresses(this: ICurve): Promise { +async function getFactoryIdsAndSwapAddresses(this: ICurve): Promise<[string[], string[]]> { const factoryContract = this.contracts[this.constants.ALIASES.factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.factory].multicallContract; @@ -174,11 +174,14 @@ async function getFactorySwapAddresses(this: ICurve): Promise { calls.push(factoryMulticallContract.pool_list(i)); } - const factorySwapAddresses: string[] = (await this.multicallProvider.all(calls) as string[]).map((addr) => addr.toLowerCase()); + let factories: { id: string, address: string}[] = (await this.multicallProvider.all(calls) as string[]).map( + (addr, i) => ({ id: `factory-v2-${i}`, address: addr.toLowerCase()}) + ); const swapAddresses = Object.values(this.constants.POOLS_DATA as PoolDataInterface).map((pool: PoolDataInterface) => pool.swap_address.toLowerCase()); - const blacklist = this.chainId === 137 ? blackListPolygon : blackListEthereum; - return factorySwapAddresses.filter((addr) => !swapAddresses.includes(addr) && !blacklist.includes(addr)); + factories = factories.filter((f) => !swapAddresses.includes(f.address) && !blacklist.includes(f.address)); + + return [factories.map((f) => f.id), factories.map((f) => f.address)] } async function getFactorySwapABIs(this: ICurve, factorySwapAddresses: string[]): Promise { @@ -223,30 +226,25 @@ function setFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]) }); } -async function getFactoryPoolNames(this: ICurve, factorySwapAddresses: string[]): Promise { +async function getFactorySymbolsAndNames(this: ICurve, factorySwapAddresses: string[]): Promise<[string[], string[]]> { const calls = []; for (const addr of factorySwapAddresses) { - calls.push(this.contracts[addr].multicallContract.symbol()); + calls.push(this.contracts[addr].multicallContract.symbol(), this.contracts[addr].multicallContract.name()); } - const names = (await this.multicallProvider.all(calls) as string[]); - const existingNames = Object.keys(this.constants.POOLS_DATA); - - // rename duplications - for (let i = 0; i < names.length; i++) { - if (names.indexOf(names[i]) !== i || existingNames.includes(names[i])) { - let n = 1; - do { n++ } while ( - names.indexOf(names[i].slice(0, -2) + `-${n}` + "-f") !== -1 || existingNames.includes(names[i].slice(0, -2) + `-${n}` + "-f") - ); - names[i] = names[i].slice(0, -2) + `-${n}` + "-f"; - } + const res = (await this.multicallProvider.all(calls) as string[]); + + const symbols: string[] = []; + const names: string[] = []; + for (let i = 0; i < factorySwapAddresses.length; i++) { + symbols.push(res[2 * i]); + names.push(res[(2 * i) + 1]); } - return names + return [symbols, names] } -async function getFactoryReferenceAssets(this: ICurve, factorySwapAddresses: string[]): Promise<('USD' | 'ETH' | 'BTC' | 'OTHER')[]> { +async function getFactoryReferenceAssets(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.factory].multicallContract; const calls = []; @@ -260,7 +258,7 @@ async function getFactoryReferenceAssets(this: ICurve, factorySwapAddresses: str 1: "ETH", 2: "BTC", }[ethers.utils.formatUnits(t, 0)] || "OTHER" - }) as ('USD' | 'ETH' | 'BTC' | 'OTHER')[]; + }) as REFERENCE_ASSET[]; } async function getFactoryCoinAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { @@ -416,14 +414,14 @@ function setFactoryZapContracts(this: ICurve): void { } export async function getFactoryPoolData(this: ICurve): Promise> { - const swapAddresses = await getFactorySwapAddresses.call(this); + const [poolIds, swapAddresses] = await getFactoryIdsAndSwapAddresses.call(this); const swapABIs = await getFactorySwapABIs.call(this, swapAddresses); setFactorySwapContracts.call(this, swapAddresses, swapABIs); this.constants.LP_TOKENS.push(...swapAddresses); // TODO move to another place const gaugeAddresses = await getFactoryGaugeAddresses.call(this, swapAddresses); setFactoryGaugeContracts.call(this, gaugeAddresses); this.constants.GAUGES.push(...gaugeAddresses.filter((addr) => addr !== ethers.constants.AddressZero)); // TODO move to another place - const poolNames = await getFactoryPoolNames.call(this, swapAddresses); + const [poolSymbols, poolNames] = await getFactorySymbolsAndNames.call(this, swapAddresses); const referenceAssets = await getFactoryReferenceAssets.call(this, swapAddresses); const coinAddresses = await getFactoryCoinAddresses.call(this, swapAddresses); setFactoryCoinsContracts.call(this, coinAddresses); @@ -441,9 +439,12 @@ export async function getFactoryPoolData(this: ICurve): Promise = {}; - for (let i = 0; i < poolNames.length; i++) { + for (let i = 0; i < poolIds.length; i++) { if (!isMeta[i]) { - FACTORY_POOLS_DATA[poolNames[i]] = { + FACTORY_POOLS_DATA[poolIds[i]] = { + name: poolNames[i].split(": ")[1].trim(), + full_name: poolNames[i], + symbol: poolSymbols[i], reference_asset: referenceAssets[i], N_COINS: coinAddresses[i].length, underlying_decimals: coinAddresses[i].map((addr) => coinAddressDecimalsDict[addr]), @@ -463,7 +464,10 @@ export async function getFactoryPoolData(this: ICurve): Promise coinAddressDecimalsDict[addr]), From 151dff10b0e42ba81b0aa1fb34b7f77ea8b49642 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Mon, 21 Mar 2022 17:26:42 +0300 Subject: [PATCH 11/16] chore: move factory files to factory dir --- src/{ => factory}/factory-crypto.ts | 8 ++--- src/{ => factory}/factory.ts | 50 ++++++++++++++--------------- 2 files changed, 29 insertions(+), 29 deletions(-) rename src/{ => factory}/factory-crypto.ts (97%) rename src/{ => factory}/factory.ts (91%) diff --git a/src/factory-crypto.ts b/src/factory/factory-crypto.ts similarity index 97% rename from src/factory-crypto.ts rename to src/factory/factory-crypto.ts index b656e31c..7c62d9f7 100644 --- a/src/factory-crypto.ts +++ b/src/factory/factory-crypto.ts @@ -1,9 +1,9 @@ import { Contract, ethers } from "ethers"; import {Contract as MulticallContract, Provider as MulticallProvider} from "ethcall"; -import { DictInterface, PoolDataInterface } from "./interfaces"; -import ERC20ABI from "./constants/abis/json/ERC20.json"; -import cryptoFactorySwapABI from "./constants/abis/json/factory-crypto/factory-crypto-pool-2.json"; -import factoryGaugeABI from "./constants/abis/json/gauge_factory.json"; +import { DictInterface, PoolDataInterface } from "../interfaces"; +import ERC20ABI from "../constants/abis/json/ERC20.json"; +import cryptoFactorySwapABI from "../constants/abis/json/factory-crypto/factory-crypto-pool-2.json"; +import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; diff --git a/src/factory.ts b/src/factory/factory.ts similarity index 91% rename from src/factory.ts rename to src/factory/factory.ts index bdb4ad90..fff2e282 100644 --- a/src/factory.ts +++ b/src/factory/factory.ts @@ -1,30 +1,30 @@ import { Contract, ethers } from "ethers"; import { Contract as MulticallContract } from "ethcall"; -import { DictInterface, PoolDataInterface, ICurve, REFERENCE_ASSET } from "./interfaces"; -import ERC20ABI from "./constants/abis/json/ERC20.json"; -import factorySwapABI from "./constants/abis/json/factoryPools/swap.json"; -import factoryDepositABI from "./constants/abis/json/factoryPools/deposit.json"; -import factoryGaugeABI from "./constants/abis/json/gauge_factory.json"; -import MetaUsdZapPolygonABI from "./constants/abis/json/factory-v2/DepositZapMetaUsdPolygon.json"; -import MetaBtcZapPolygonABI from "./constants/abis/json/factory-v2/DepositZapMetaBtcPolygon.json"; -import MetaUSDABI from "./constants/abis/json/factory-v2/MetaUSD.json"; -import MetaUSDBalancesABI from "./constants/abis/json/factory-v2/MetaUSDBalances.json"; -import MetaBTCABI from "./constants/abis/json/factory-v2/MetaBTC.json"; -import MetaBTCBalancesABI from "./constants/abis/json/factory-v2/MetaBTCBalances.json"; -import MetaBTCRenABI from "./constants/abis/json/factory-v2/MetaBTCRen.json"; -import MetaBTCRenBalancesABI from "./constants/abis/json/factory-v2/MetaBTCBalancesRen.json"; -import Plain2BasicABI from "./constants/abis/json/factory-v2/Plain2Basic.json"; -import Plain2BalancesABI from "./constants/abis/json/factory-v2/Plain2Balances.json"; -import Plain2ETHABI from "./constants/abis/json/factory-v2/Plain2ETH.json"; -import Plain2OptimizedABI from "./constants/abis/json/factory-v2/Plain2Optimized.json"; -import Plain3BasicABI from "./constants/abis/json/factory-v2/Plain3Basic.json"; -import Plain3BalancesABI from "./constants/abis/json/factory-v2/Plain3Balances.json"; -import Plain3ETHABI from "./constants/abis/json/factory-v2/Plain3ETH.json"; -import Plain3OptimizedABI from "./constants/abis/json/factory-v2/Plain3Optimized.json"; -import Plain4BasicABI from "./constants/abis/json/factory-v2/Plain4Basic.json"; -import Plain4BalancesABI from "./constants/abis/json/factory-v2/Plain4Balances.json"; -import Plain4ETHABI from "./constants/abis/json/factory-v2/Plain4ETH.json"; -import Plain4OptimizedABI from "./constants/abis/json/factory-v2/Plain4Optimized.json"; +import { DictInterface, PoolDataInterface, ICurve, REFERENCE_ASSET } from "../interfaces"; +import ERC20ABI from "../constants/abis/json/ERC20.json"; +import factorySwapABI from "../constants/abis/json/factoryPools/swap.json"; +import factoryDepositABI from "../constants/abis/json/factoryPools/deposit.json"; +import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; +import MetaUsdZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaUsdPolygon.json"; +import MetaBtcZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaBtcPolygon.json"; +import MetaUSDABI from "../constants/abis/json/factory-v2/MetaUSD.json"; +import MetaUSDBalancesABI from "../constants/abis/json/factory-v2/MetaUSDBalances.json"; +import MetaBTCABI from "../constants/abis/json/factory-v2/MetaBTC.json"; +import MetaBTCBalancesABI from "../constants/abis/json/factory-v2/MetaBTCBalances.json"; +import MetaBTCRenABI from "../constants/abis/json/factory-v2/MetaBTCRen.json"; +import MetaBTCRenBalancesABI from "../constants/abis/json/factory-v2/MetaBTCBalancesRen.json"; +import Plain2BasicABI from "../constants/abis/json/factory-v2/Plain2Basic.json"; +import Plain2BalancesABI from "../constants/abis/json/factory-v2/Plain2Balances.json"; +import Plain2ETHABI from "../constants/abis/json/factory-v2/Plain2ETH.json"; +import Plain2OptimizedABI from "../constants/abis/json/factory-v2/Plain2Optimized.json"; +import Plain3BasicABI from "../constants/abis/json/factory-v2/Plain3Basic.json"; +import Plain3BalancesABI from "../constants/abis/json/factory-v2/Plain3Balances.json"; +import Plain3ETHABI from "../constants/abis/json/factory-v2/Plain3ETH.json"; +import Plain3OptimizedABI from "../constants/abis/json/factory-v2/Plain3Optimized.json"; +import Plain4BasicABI from "../constants/abis/json/factory-v2/Plain4Basic.json"; +import Plain4BalancesABI from "../constants/abis/json/factory-v2/Plain4Balances.json"; +import Plain4ETHABI from "../constants/abis/json/factory-v2/Plain4ETH.json"; +import Plain4OptimizedABI from "../constants/abis/json/factory-v2/Plain4Optimized.json"; const implementationABIDictEthereum: DictInterface = { From c65a99f69fd9009519e14544ff0d128f9aa53887 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Tue, 22 Mar 2022 17:17:38 +0300 Subject: [PATCH 12/16] feat: getting crypto factory pools data from api --- src/curve.ts | 16 ++++--- src/factory/constants.ts | 3 ++ src/factory/factory-api.ts | 95 ++++++++++++++++++++++++++++++-------- src/index.ts | 8 ++-- src/interfaces.ts | 1 + 5 files changed, 94 insertions(+), 29 deletions(-) diff --git a/src/curve.ts b/src/curve.ts index 6bf91ef0..e11a7d40 100644 --- a/src/curve.ts +++ b/src/curve.ts @@ -1,9 +1,9 @@ import { ethers, Contract } from "ethers"; import { Networkish } from "@ethersproject/networks"; import { Provider as MulticallProvider, Contract as MulticallContract } from 'ethcall'; -import { getFactoryPoolData } from "./factory"; +import { getFactoryPoolData } from "./factory/factory"; import { getFactoryPoolsDataFromApi } from "./factory/factory-api"; -import { getCryptoFactoryPoolData } from "./factory-crypto"; +import { getCryptoFactoryPoolData } from "./factory/factory-crypto"; import {PoolDataInterface, DictInterface, ICurve} from "./interfaces"; import ERC20Abi from './constants/abis/json/ERC20.json'; import cERC20Abi from './constants/abis/json/cERC20.json'; @@ -459,16 +459,20 @@ class Curve implements ICurve { } } - async fetchFactoryPools({ useApi } = { useApi: true }): Promise { + async fetchFactoryPools(useApi = true): Promise { if (useApi) { - this.constants.FACTORY_POOLS_DATA = await getFactoryPoolsDataFromApi.call(this); + this.constants.FACTORY_POOLS_DATA = await getFactoryPoolsDataFromApi.call(this, false); } else { this.constants.FACTORY_POOLS_DATA = await getFactoryPoolData.call(this); } } - async fetchCryptoFactoryPools(): Promise { - if (this.chainId === 1 || this.chainId === 1337) { + async fetchCryptoFactoryPools(useApi = true): Promise { + if (this.chainId !== 1 && this.chainId !== 1337) return + + if (useApi) { + this.constants.CRYPTO_FACTORY_POOLS_DATA = await getFactoryPoolsDataFromApi.call(this, true); + } else { this.constants.CRYPTO_FACTORY_POOLS_DATA = await getCryptoFactoryPoolData.call(this); } } diff --git a/src/factory/constants.ts b/src/factory/constants.ts index 792d46a0..902b4e36 100644 --- a/src/factory/constants.ts +++ b/src/factory/constants.ts @@ -173,3 +173,6 @@ export const blackListPolygon: string[] = [ "0xe4199bc5c5c1f63dba47b56b6db7144c51cf0bf8", "0x88c4d6534165510b2e2caf0a130d4f70aa4b6d71", ]; + +export const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; +export const ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; \ No newline at end of file diff --git a/src/factory/factory-api.ts b/src/factory/factory-api.ts index 7f190f97..d472b755 100644 --- a/src/factory/factory-api.ts +++ b/src/factory/factory-api.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import {Contract, ethers} from "ethers"; +import { Contract, ethers } from "ethers"; import { Contract as MulticallContract } from "ethcall"; import { DictInterface, PoolDataInterface, ICurve, IPoolDataFromApi, REFERENCE_ASSET } from "../interfaces"; import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; @@ -7,6 +7,7 @@ import factoryDepositABI from "../constants/abis/json/factoryPools/deposit.json" import ERC20ABI from "../constants/abis/json/ERC20.json"; import MetaUsdZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaUsdPolygon.json"; import MetaBtcZapPolygonABI from "../constants/abis/json/factory-v2/DepositZapMetaBtcPolygon.json"; +import cryptoFactorySwapABI from "../constants/abis/json/factory-crypto/factory-crypto-pool-2.json"; import { implementationABIDictEthereum, implementationABIDictPolygon, @@ -22,15 +23,38 @@ import { basePoolAddressDecimalsDictPolygon, basePoolAddressZapDictEthereum, basePoolAddressZapDictPolygon, + WETH_ADDRESS, + ETH_ADDRESS, } from "./constants"; -function setFactorySwapContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]): void { - const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; +function setFactorySwapContracts(this: ICurve, rawPoolList: IPoolDataFromApi[], isCrypto: boolean): void { + if (isCrypto) { + rawPoolList.forEach((pool) => { + const addr = pool.address.toLowerCase(); + this.contracts[addr] = { + contract: new Contract(addr, cryptoFactorySwapABI, this.signer || this.provider), + multicallContract: new MulticallContract(addr, cryptoFactorySwapABI), + } + }); + } else { + const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; + rawPoolList.forEach((pool) => { + const addr = pool.address.toLowerCase(); + this.contracts[addr] = { + contract: new Contract(addr, implementationABIDict[pool.implementationAddress], this.signer || this.provider), + multicallContract: new MulticallContract(addr, implementationABIDict[pool.implementationAddress]), + } + this.constants.LP_TOKENS.push(addr); + }); + } +} + +function setCryptoFactoryTokenContracts(this: ICurve, rawPoolList: IPoolDataFromApi[]): void { rawPoolList.forEach((pool) => { - const addr = pool.address.toLowerCase(); + const addr = (pool.lpTokenAddress as string).toLowerCase(); this.contracts[addr] = { - contract: new Contract(addr, implementationABIDict[pool.implementationAddress], this.signer || this.provider), - multicallContract: new MulticallContract(addr, implementationABIDict[pool.implementationAddress]), + contract: new Contract(addr, ERC20ABI, this.signer || this.provider), + multicallContract: new MulticallContract(addr, ERC20ABI), } this.constants.LP_TOKENS.push(addr); }); @@ -86,23 +110,18 @@ function setFactoryZapContracts(this: ICurve): void { } } -export async function getFactoryPoolsDataFromApi(this: ICurve): Promise> { +export async function getFactoryPoolsDataFromApi(this: ICurve, isCrypto: boolean): Promise> { const network = this.chainId === 137 ? "polygon" : "ethereum"; - const url = `https://api.curve.fi/api/getPools/${network}/factory`; + const factoryType = isCrypto ? "factory-crypto" : "factory"; + const url = `https://api.curve.fi/api/getPools/${network}/${factoryType}`; const response = await axios.get(url); const rawPoolList: IPoolDataFromApi[] = response.data.data.poolData; - setFactorySwapContracts.call(this, rawPoolList); + + setFactorySwapContracts.call(this, rawPoolList, isCrypto); + if (isCrypto) setCryptoFactoryTokenContracts.call(this, rawPoolList); setFactoryGaugeContracts.call(this, rawPoolList); setFactoryCoinsContracts.call(this, rawPoolList); - setFactoryZapContracts.call(this); - - const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; - const implementationBasePoolAddressDict = this.chainId === 137 ? implementationBasePoolAddressDictPolygon : implementationBasePoolAddressDictEthereum; - const basePoolAddressCoinsDict = this.chainId === 137 ? basePoolAddressCoinsDictPolygon : basePoolAddressCoinsDictEthereum; - const basePoolAddressNameDict = this.chainId === 137 ? basePoolAddressNameDictPolygon : basePoolAddressNameDictEthereum; - const basePoolAddressCoinAddressesDict = this.chainId === 137 ? basePoolAddressCoinAddressesDictPolygon : basePoolAddressCoinAddressesDictEthereum; - const basePoolAddressDecimalsDict = this.chainId === 137 ? basePoolAddressDecimalsDictPolygon : basePoolAddressDecimalsDictEthereum; - const basePoolAddressZapDict = this.chainId === 137 ? basePoolAddressZapDictPolygon : basePoolAddressZapDictEthereum; + if (!isCrypto) setFactoryZapContracts.call(this); const FACTORY_POOLS_DATA: DictInterface = {}; rawPoolList.forEach((pool) => { @@ -110,7 +129,43 @@ export async function getFactoryPoolsDataFromApi(this: ICurve): Promise c.symbol); const coinDecimals = pool.coins.map((c) => Number(c.decimals)); - if (pool.implementation.startsWith("meta")) { + if (isCrypto) { + const cryptoCoinNames = pool.coins.map((c) => c.symbol === "ETH" ? "WETH" : c.symbol); + const underlyingCoinNames = pool.coins.map((c) => c.symbol === "WETH" ? "ETH" : c.symbol); + const underlyingCoinAddresses = pool.coins.map((c) => c.address.toLowerCase() === WETH_ADDRESS ? ETH_ADDRESS : c.address.toLowerCase()); + + FACTORY_POOLS_DATA[pool.id] = { + name: pool.name.split(": ")[1].trim(), + full_name: pool.name, + symbol: pool.symbol, + reference_asset: "CRYPTO", + N_COINS: coinAddresses.length, + is_crypto: true, + underlying_decimals: coinDecimals, + decimals: coinDecimals, + use_lending: coinAddresses.map(() => false), + is_plain: coinAddresses.map(() => true), + underlying_coins: underlyingCoinNames, + coins: cryptoCoinNames, + swap_address: pool.address.toLowerCase(), + token_address: (pool.lpTokenAddress as string).toLowerCase(), + gauge_address: pool.gaugeAddress ? pool.gaugeAddress.toLowerCase() : ethers.constants.AddressZero, + underlying_coin_addresses: underlyingCoinAddresses, + coin_addresses: coinAddresses, + swap_abi: cryptoFactorySwapABI, + gauge_abi: factoryGaugeABI, + is_factory: true, + is_crypto_factory: true, + }; + } else if (pool.implementation.startsWith("meta")) { + const implementationABIDict = this.chainId === 137 ? implementationABIDictPolygon : implementationABIDictEthereum; + const implementationBasePoolAddressDict = this.chainId === 137 ? implementationBasePoolAddressDictPolygon : implementationBasePoolAddressDictEthereum; + const basePoolAddressCoinsDict = this.chainId === 137 ? basePoolAddressCoinsDictPolygon : basePoolAddressCoinsDictEthereum; + const basePoolAddressNameDict = this.chainId === 137 ? basePoolAddressNameDictPolygon : basePoolAddressNameDictEthereum; + const basePoolAddressCoinAddressesDict = this.chainId === 137 ? basePoolAddressCoinAddressesDictPolygon : basePoolAddressCoinAddressesDictEthereum; + const basePoolAddressDecimalsDict = this.chainId === 137 ? basePoolAddressDecimalsDictPolygon : basePoolAddressDecimalsDictEthereum; + const basePoolAddressZapDict = this.chainId === 137 ? basePoolAddressZapDictPolygon : basePoolAddressZapDictEthereum; + const basePoolAddress = implementationBasePoolAddressDict[pool.implementationAddress]; const basePoolCoinNames = basePoolAddressCoinsDict[basePoolAddress]; const basePoolCoinAddresses = basePoolAddressCoinAddressesDict[basePoolAddress]; @@ -146,6 +201,8 @@ export async function getFactoryPoolsDataFromApi(this: ICurve): Promise { - await _curve.fetchFactoryPools(); +async function fetchFactoryPools(useApi = true): Promise { + await _curve.fetchFactoryPools(useApi); } -async function fetchCryptoFactoryPools(): Promise { - await _curve.fetchCryptoFactoryPools(); +async function fetchCryptoFactoryPools(useApi = true): Promise { + await _curve.fetchCryptoFactoryPools(useApi); } function setCustomFeeData (customFeeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }): void { diff --git a/src/interfaces.ts b/src/interfaces.ts index ab57975d..d9c46bf8 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -90,6 +90,7 @@ export interface IPoolDataFromApi { symbol: string, assetTypeName: string, address: string, + lpTokenAddress?: string, gaugeAddress?: string, implementation: string, implementationAddress: string, From 70ff4464cf9058c9083a0c824ec9870774acd943 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Tue, 22 Mar 2022 17:35:34 +0300 Subject: [PATCH 13/16] feat: name, full_name and symbol in crypto factories obtained from SC --- src/factory/factory-crypto.ts | 92 +++++++++++++++-------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/src/factory/factory-crypto.ts b/src/factory/factory-crypto.ts index 7c62d9f7..9cfeda97 100644 --- a/src/factory/factory-crypto.ts +++ b/src/factory/factory-crypto.ts @@ -1,28 +1,15 @@ import { Contract, ethers } from "ethers"; -import {Contract as MulticallContract, Provider as MulticallProvider} from "ethcall"; -import { DictInterface, PoolDataInterface } from "../interfaces"; +import { Contract as MulticallContract } from "ethcall"; +import { DictInterface, PoolDataInterface, ICurve } from "../interfaces"; import ERC20ABI from "../constants/abis/json/ERC20.json"; import cryptoFactorySwapABI from "../constants/abis/json/factory-crypto/factory-crypto-pool-2.json"; import factoryGaugeABI from "../constants/abis/json/gauge_factory.json"; const WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; -interface CurveInterface { - provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider, - multicallProvider: MulticallProvider, - signer: ethers.Signer | null, - signerAddress: string, - chainId: number, - contracts: { [index: string]: { contract: Contract, multicallContract: MulticallContract } }, - feeData: { gasPrice?: number, maxFeePerGas?: number, maxPriorityFeePerGas?: number }, - constantOptions: { gasLimit: number }, - options: { gasPrice?: number | ethers.BigNumber, maxFeePerGas?: number | ethers.BigNumber, maxPriorityFeePerGas?: number | ethers.BigNumber }, - constants: DictInterface; -} - const deepFlatten = (arr: any[]): any[] => [].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v))); -async function getCryptoFactorySwapAddresses(this: CurveInterface): Promise { +async function getCryptoFactoryIdsAndSwapAddresses(this: ICurve): Promise<[string[], string[]]> { const factoryContract = this.contracts[this.constants.ALIASES.crypto_factory].contract; const factoryMulticallContract = this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; @@ -32,14 +19,17 @@ async function getCryptoFactorySwapAddresses(this: CurveInterface): Promise addr.toLowerCase()); - const swapAddresses = Object.values({...this.constants.POOLS_DATA, ...this.constants.FACTORY_POOLS_DATA} as PoolDataInterface) - .map((pool: PoolDataInterface) => pool.swap_address.toLowerCase()); + let factories: { id: string, address: string}[] = (await this.multicallProvider.all(calls) as string[]).map( + (addr, i) => ({ id: `factory-crypto-${i}`, address: addr.toLowerCase()}) + ); + + const swapAddresses = Object.values(this.constants.POOLS_DATA as PoolDataInterface).map((pool: PoolDataInterface) => pool.swap_address.toLowerCase()); + factories = factories.filter((f) => !swapAddresses.includes(f.address)); - return factorySwapAddresses.filter((addr) => !swapAddresses.includes(addr)); + return [factories.map((f) => f.id), factories.map((f) => f.address)] } -function setCryptoFactorySwapContracts(this: CurveInterface, factorySwapAddresses: string[]): void { +function setCryptoFactorySwapContracts(this: ICurve, factorySwapAddresses: string[]): void { factorySwapAddresses.forEach((addr) => { this.contracts[addr] = { contract: new Contract(addr, cryptoFactorySwapABI, this.signer || this.provider), @@ -48,7 +38,7 @@ function setCryptoFactorySwapContracts(this: CurveInterface, factorySwapAddresse }); } -async function getCryptoFactoryTokenAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getCryptoFactoryTokenAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; const calls = []; @@ -59,7 +49,7 @@ async function getCryptoFactoryTokenAddresses(this: CurveInterface, factorySwapA return (await this.multicallProvider.all(calls) as string[]).map((addr) => addr.toLowerCase()); } -function setCryptoFactoryTokenContracts(this: CurveInterface, factoryTokenAddresses: string[]): void { +function setCryptoFactoryTokenContracts(this: ICurve, factoryTokenAddresses: string[]): void { factoryTokenAddresses.forEach((addr) => { this.contracts[addr] = { contract: new Contract(addr, ERC20ABI, this.signer || this.provider), @@ -68,7 +58,7 @@ function setCryptoFactoryTokenContracts(this: CurveInterface, factoryTokenAddres }); } -async function getCryptoFactoryGaugeAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getCryptoFactoryGaugeAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; const calls = []; @@ -79,7 +69,7 @@ async function getCryptoFactoryGaugeAddresses(this: CurveInterface, factorySwapA return (await this.multicallProvider.all(calls) as string[]).map((addr) => addr.toLowerCase()); } -function setCryptoFactoryGaugeContracts(this: CurveInterface, factoryGaugeAddresses: string[]): void { +function setCryptoFactoryGaugeContracts(this: ICurve, factoryGaugeAddresses: string[]): void { factoryGaugeAddresses.filter((addr) => addr !== ethers.constants.AddressZero).forEach((addr, i) => { this.contracts[addr] = { contract: new Contract(addr, factoryGaugeABI, this.signer || this.provider), @@ -88,30 +78,25 @@ function setCryptoFactoryGaugeContracts(this: CurveInterface, factoryGaugeAddres }); } -async function getCryptoFactoryPoolNames(this: CurveInterface, factoryTokenAddresses: string[]): Promise { +async function getCryptoFactorySymbolsAndNames(this: ICurve, factoryTokenAddresses: string[]): Promise<[string[], string[]]> { const calls = []; for (const addr of factoryTokenAddresses) { - calls.push(this.contracts[addr].multicallContract.symbol()); + calls.push(this.contracts[addr].multicallContract.symbol(), this.contracts[addr].multicallContract.name()); } - const names = (await this.multicallProvider.all(calls) as string[]).map((name) => name + "V2"); - const existingNames = Object.keys(this.constants.POOLS_DATA); - - // rename duplications - for (let i = 0; i < names.length; i++) { - if (names.indexOf(names[i]) !== i || existingNames.includes(names[i])) { - let n = 1; - do { n++ } while ( - names.indexOf(names[i].slice(0, -4) + `-${n}` + "-fV2") !== -1 || existingNames.includes(names[i].slice(0, -4) + `-${n}` + "-fV2") - ); - names[i] = names[i].slice(0, -4) + `-${n}` + "-fV2"; - } + const res = (await this.multicallProvider.all(calls) as string[]); + + const symbols: string[] = []; + const names: string[] = []; + for (let i = 0; i < factoryTokenAddresses.length; i++) { + symbols.push(res[2 * i]); + names.push(res[(2 * i) + 1]); } - return names + return [symbols, names] } -async function getCryptoFactoryCoinAddresses(this: CurveInterface, factorySwapAddresses: string[]): Promise { +async function getCryptoFactoryCoinAddresses(this: ICurve, factorySwapAddresses: string[]): Promise { const factoryMulticallContract = await this.contracts[this.constants.ALIASES.crypto_factory].multicallContract; const calls = []; @@ -122,7 +107,7 @@ async function getCryptoFactoryCoinAddresses(this: CurveInterface, factorySwapAd return (await this.multicallProvider.all(calls) as string[][]).map((addresses) => addresses.map((addr) => addr.toLowerCase())); } -function setCryptoFactoryCoinsContracts(this: CurveInterface, coinAddresses: string[][]): void { +function setCryptoFactoryCoinsContracts(this: ICurve, coinAddresses: string[][]): void { const flattenedCoinAddresses = Array.from(new Set(deepFlatten(coinAddresses))); for (const addr of flattenedCoinAddresses) { if (addr in this.contracts) continue; @@ -134,11 +119,11 @@ function setCryptoFactoryCoinsContracts(this: CurveInterface, coinAddresses: str } } -async function getCryptoFactoryUnderlyingCoinAddresses(this: CurveInterface, coinAddresses: string[][]): Promise { +async function getCryptoFactoryUnderlyingCoinAddresses(this: ICurve, coinAddresses: string[][]): Promise { return coinAddresses.map((coins: string[]) => coins.map((c) => c === WETH_ADDRESS ? "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" : c)); } -function getExistingCoinAddressNameDict(this: CurveInterface): DictInterface { +function getExistingCoinAddressNameDict(this: ICurve): DictInterface { const dict: DictInterface = {} for (const poolData of Object.values(this.constants.POOLS_DATA as DictInterface)) { poolData.coin_addresses.forEach((addr, i) => { @@ -160,7 +145,7 @@ function getExistingCoinAddressNameDict(this: CurveInterface): DictInterface ): Promise> { @@ -192,7 +177,7 @@ async function getCoinAddressNameDict( } async function getCoinAddressDecimalsDict( - this: CurveInterface, + this: ICurve, coinAddresses: string[][], existingCoinAddressDecimalsDict: DictInterface ): Promise> { @@ -223,8 +208,8 @@ async function getCoinAddressDecimalsDict( } -export async function getCryptoFactoryPoolData(this: CurveInterface): Promise> { - const swapAddresses = await getCryptoFactorySwapAddresses.call(this); +export async function getCryptoFactoryPoolData(this: ICurve): Promise> { + const [poolIds, swapAddresses] = await getCryptoFactoryIdsAndSwapAddresses.call(this); setCryptoFactorySwapContracts.call(this, swapAddresses); const tokenAddresses = await getCryptoFactoryTokenAddresses.call(this, swapAddresses); setCryptoFactoryTokenContracts.call(this, tokenAddresses); @@ -232,7 +217,7 @@ export async function getCryptoFactoryPoolData(this: CurveInterface): Promise addr !== ethers.constants.AddressZero)); // TODO move to another place - const poolNames = await getCryptoFactoryPoolNames.call(this, tokenAddresses); + const [poolSymbols, poolNames] = await getCryptoFactorySymbolsAndNames.call(this, tokenAddresses); const coinAddresses = await getCryptoFactoryCoinAddresses.call(this, swapAddresses); setCryptoFactoryCoinsContracts.call(this, coinAddresses); const underlyingCoinAddresses = await getCryptoFactoryUnderlyingCoinAddresses.call(this, coinAddresses); @@ -244,8 +229,11 @@ export async function getCryptoFactoryPoolData(this: CurveInterface): Promise = {}; - for (let i = 0; i < poolNames.length; i++) { - CRYPTO_FACTORY_POOLS_DATA[poolNames[i]] = { + for (let i = 0; i < poolIds.length; i++) { + CRYPTO_FACTORY_POOLS_DATA[poolIds[i]] = { + name: poolNames[i].split(": ")[1].trim(), + full_name: poolNames[i], + symbol: poolSymbols[i], reference_asset: "CRYPTO", N_COINS: coinAddresses[i].length, is_crypto: true, @@ -260,7 +248,7 @@ export async function getCryptoFactoryPoolData(this: CurveInterface): Promise Date: Tue, 22 Mar 2022 18:04:44 +0300 Subject: [PATCH 14/16] test: change name --> id for pools --- test/underlying.test.ts | 63 ++++++++++++++++++++--------------------- test/wrapped.test.ts | 59 +++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/test/underlying.test.ts b/test/underlying.test.ts index eb6cc905..af8c599e 100644 --- a/test/underlying.test.ts +++ b/test/underlying.test.ts @@ -10,33 +10,32 @@ const PLAIN_POOLS = ['susd', 'ren', 'sbtc', 'hbtc', '3pool', 'seth', 'steth', ' const LENDING_POOLS = ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib']; const META_POOLS = ['gusd', 'husd', 'usdk', 'usdn', 'musd', 'rsv', 'tbtc', 'dusd', 'pbtc', 'bbtc', 'obtc', 'ust', 'usdp', 'tusd', 'frax', 'lusd', 'busdv2', 'alusd', 'mim']; const CRYPTO_POOLS = ['tricrypto2', 'eurtusd', 'crveth', 'cvxeth', 'xautusd', 'spelleth', 'teth']; -const FACTORY_PLAIN_POOLS = ['ibEUR+sEUR-2-f', 'D3-f', 'crvCRV-f']; -const FACTORY_META_POOLS = ['baoUSD-3CRV-f', 'ELONXSWAP3CRV-f', 'ibbtc/sbtcCRV-2-f']; -const FACTORY_CRYPTO_POOLS = ['YFIETH-fV2', 'BADGERWBTC-fV2']; +const FACTORY_PLAIN_POOLS = ['factory-v2-3', 'factory-v2-57', 'factory-v2-7']; // ['ibEUR+sEUR-f(2)', 'D3-f', 'crvCRV-f']; +const FACTORY_META_POOLS = ['factory-v2-84', 'factory-v2-80', 'factory-v2-60']; // ['baoUSD-3CRV-f', 'ELONXSWAP3CRV-f', 'ibbtc/sbtcCRV-f(2)']; +const FACTORY_CRYPTO_POOLS = ['factory-crypto-8', 'factory-crypto-4']; // ['YFIETH-fV2', 'BADGERWBTC-fV2']; const POLYGON_MAIN_POOLS = ['aave', 'ren', 'atricrypto3', 'eurtusd']; -const POLYGON_FACTORY_PLAIN_POOLS = ['CRVALRTO-f', '3EUR-f', '4eur-2-f']; -const POLYGON_FACTORY_META_POOLS = ['FRAX3CRV-f3CRV']; +const POLYGON_FACTORY_PLAIN_POOLS = ['factory-v2-113', 'factory-v2-4', 'factory-v2-37']; // ['CRVALRTO-f', '3EUR-f', '4eur-f(2)']; +const POLYGON_FACTORY_META_POOLS = ['factory-v2-11']; // ['FRAX3CRV-f3CRV-f']; // const ETHEREUM_POOLS = [...PLAIN_POOLS, ...LENDING_POOLS, ...META_POOLS, ...CRYPTO_POOLS]; -const ETHEREUM_POOLS = FACTORY_PLAIN_POOLS; -const POLYGON_POOLS = POLYGON_FACTORY_META_POOLS; +const ETHEREUM_POOLS = [...FACTORY_PLAIN_POOLS, ...FACTORY_META_POOLS, ...FACTORY_CRYPTO_POOLS]; +const POLYGON_POOLS = [...POLYGON_FACTORY_PLAIN_POOLS, ...POLYGON_FACTORY_META_POOLS]; -const underlyingLiquidityTest = (name: string) => { - describe(`${name} add/remove liquidity`, function () { +const underlyingLiquidityTest = (id: string) => { + describe(`${id} add/remove liquidity`, function () { let pool: Pool; let coinAddresses: string[]; before(async function () { - pool = new curve.Pool(name); + pool = new curve.Pool(id); coinAddresses = pool.underlyingCoinAddresses; }); it('Adds liquidity', async function () { const amount = '10'; const amounts = coinAddresses.map(() => amount); - if (name === "crvCRV") amounts[3] = '0'; - + if (id === 'factory-v2-7') amounts[3] = '0'; const initialBalances = await pool.balances() as DictInterface; const lpTokenExpected = await pool.addLiquidityExpected(amounts); @@ -45,14 +44,14 @@ const underlyingLiquidityTest = (name: string) => { const balances = await pool.balances() as DictInterface; pool.underlyingCoins.forEach((c, i) => { - if (name === 'steth' || pool.name === 'ibbtc/sbtcCRV') { + if (id === 'steth' || pool.id === 'factory-v2-8') { assert.approximately(Number(BN(balances[c])), Number(BN(initialBalances[c]).minus(BN(amounts[i]).toString())), 1e-18); } else { assert.deepStrictEqual(BN(balances[c]), BN(initialBalances[c]).minus(BN(amounts[i]))); } }) - const delta = ['ELONXSWAP3CRV', 'CRVALRTO'].includes(name) ? 2 : 0.01 + const delta = ['factory-v2-80', 'factory-v2-113'].includes(id) ? 2 : 0.01 assert.approximately(Number(balances.lpToken) - Number(initialBalances.lpToken), Number(lpTokenExpected), delta); }); @@ -99,7 +98,7 @@ const underlyingLiquidityTest = (name: string) => { assert.deepStrictEqual(BN(balances.lpToken), BN(initialBalances.lpToken).minus(BN(lpTokenAmount))); pool.underlyingCoins.forEach((c: string, i: number) => { - const delta = ['gusd', '4eur-2'].includes(name) ? 0.011 : 0.01; + const delta = ['gusd', 'factory-v2-37'].includes(id) ? 0.011 : ['factory-v2-80'].includes(id) ? 1 : 0.01; assert.approximately(Number(balances[c]) - Number(initialBalances[c]), Number(coinsExpected[i]), delta); }) }); @@ -111,7 +110,7 @@ const underlyingLiquidityTest = (name: string) => { } else { const amount = '1'; const amounts = coinAddresses.map(() => amount); - if (name === "crvCRV") amounts[3] = '0.1'; + if (id === "factory-v2-7") amounts[3] = '0.1'; const initialBalances = await pool.balances() as DictInterface; const lpTokenExpected = await pool.removeLiquidityImbalanceExpected(amounts); @@ -119,12 +118,12 @@ const underlyingLiquidityTest = (name: string) => { const balances = await pool.balances() as DictInterface; - const delta = ['ELONXSWAP3CRV', 'CRVALRTO'].includes(name) ? 2 : 0.01 + const delta = ['factory-v2-80', 'factory-v2-113'].includes(id) ? 2 : 0.01 assert.approximately(Number(initialBalances.lpToken) - Number(balances.lpToken), Number(lpTokenExpected), delta); pool.underlyingCoins.forEach((c, i) => { - if (name === 'steth') { + if (id === 'steth') { assert.approximately(Number(initialBalances[c]), Number(BN(balances[c]).minus(BN(amounts[i])).toString()), 1e-18); - } else if (['compound', 'usdt', 'y', 'busd', 'pax', 'ib'].includes(pool.name)) { + } else if (['compound', 'usdt', 'y', 'busd', 'pax', 'ib'].includes(pool.id)) { assert.approximately(Number(initialBalances[c]), Number(BN(balances[c]).minus(BN(amounts[i])).toString()), 3e-6); } else { assert.deepStrictEqual(BN(initialBalances[c]), BN(balances[c]).minus(BN(amounts[i]))); @@ -154,15 +153,15 @@ const underlyingLiquidityTest = (name: string) => { }); } -const underlyingExchangeTest = (name: string) => { - describe(`${name} exchange`, function () { +const underlyingExchangeTest = (id: string) => { + describe(`${id} exchange`, function () { for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (i !== j) { it(`${i} --> ${j}`, async function () { - const pool = new curve.Pool(name); + const pool = new curve.Pool(id); const coinAddresses = pool.underlyingCoinAddresses; - if (i >= coinAddresses.length || j >= coinAddresses.length || (name === "crvCRV" && i === 3)) { + if (i >= coinAddresses.length || j >= coinAddresses.length || (id === "factory-v2-7" && i === 3)) { console.log('Skip') } else { const swapAmount = '10'; @@ -173,7 +172,7 @@ const underlyingExchangeTest = (name: string) => { const coinBalances = await pool.underlyingCoinBalances() as DictInterface; - if (pool.name === 'steth' || pool.name === 'ibbtc/sbtcCRV') { + if (pool.id === 'steth' || pool.id === 'factory-v2-60') { assert.approximately(Number(Object.values(coinBalances)[i]), Number(BN(Object.values(initialCoinBalances)[i]).minus(BN(swapAmount)).toString()), 1e-18); } else { assert.deepStrictEqual(BN(Object.values(coinBalances)[i]), BN(Object.values(initialCoinBalances)[i]).minus(BN(swapAmount))); @@ -196,13 +195,13 @@ describe('Underlying test', async function () { await curve.fetchCryptoFactoryPools(); }); - for (const poolName of ETHEREUM_POOLS) { - underlyingLiquidityTest(poolName); - underlyingExchangeTest(poolName); - } - - // for (const poolName of POLYGON_POOLS) { - // underlyingLiquidityTest(poolName); - // underlyingExchangeTest(poolName); + // for (const poolId of ETHEREUM_POOLS) { + // underlyingLiquidityTest(poolId); + // underlyingExchangeTest(poolId); // } + + for (const poolId of POLYGON_POOLS) { + underlyingLiquidityTest(poolId); + underlyingExchangeTest(poolId); + } }) diff --git a/test/wrapped.test.ts b/test/wrapped.test.ts index f2670635..cca07077 100644 --- a/test/wrapped.test.ts +++ b/test/wrapped.test.ts @@ -8,23 +8,24 @@ import { Pool } from "../src/pools"; const LENDING_POOLS = ['compound', 'usdt', 'y', 'busd', 'pax', 'aave', 'saave', 'ib']; const META_POOLS = ['gusd', 'husd', 'usdk', 'usdn', 'musd', 'rsv', 'tbtc', 'dusd', 'pbtc', 'bbtc', 'obtc', 'ust', 'usdp', 'tusd', 'frax', 'lusd', 'busdv2', 'alusd', 'mim']; const CRYPTO_POOLS = ['tricrypto2', 'eurtusd', 'crveth', 'cvxeth', 'xautusd', 'spelleth', 'teth']; -const FACTORY_META_POOLS = ['baoUSD-3CRV-f', 'ELONXSWAP3CRV-f', 'ibbtc/sbtcCRV-2-f']; -const FACTORY_CRYPTO_POOLS = ['YFIETH-fV2']; +const FACTORY_META_POOLS = ['factory-v2-84', 'factory-v2-80', 'factory-v2-60']; // ['baoUSD-3CRV-f', 'ELONXSWAP3CRV-f', 'ibbtc/sbtcCRV-f(2)']; +const FACTORY_CRYPTO_POOLS = ['factory-crypto-8']; // ['YFIETH-fV2']; const POLYGON_MAIN_POOLS = ['aave', 'ren', 'eurtusd']; -const POLYGON_FACTORY_META_POOLS = ['FRAX3CRV-f3CRV-f']; +const POLYGON_FACTORY_META_POOLS = ['factory-v2-11']; // ['FRAX3CRV-f3CRV-f']; + // const ETHEREUM_POOLS = [...LENDING_POOLS, ...META_POOLS, ...CRYPTO_POOLS]; -const ETHEREUM_POOLS = FACTORY_CRYPTO_POOLS; +const ETHEREUM_POOLS = [...FACTORY_META_POOLS, ...FACTORY_CRYPTO_POOLS]; const POLYGON_POOLS = POLYGON_FACTORY_META_POOLS; -const wrappedLiquidityTest = (name: string) => { - describe(`${name} add/remove liquidity`, function () { +const wrappedLiquidityTest = (id: string) => { + describe(`${id} add/remove liquidity`, function () { let pool: Pool; let coinAddresses: string[]; before(async function () { - pool = new curve.Pool(name); + pool = new curve.Pool(id); coinAddresses = pool.coinAddresses; }); @@ -39,17 +40,17 @@ const wrappedLiquidityTest = (name: string) => { const balances = await pool.balances() as DictInterface; pool.coins.forEach((c: string) => { - if (['aave', 'saave'].includes(name) || (curve.chainId === 137 && pool.name === 'ren')) { + if (['aave', 'saave'].includes(id) || (curve.chainId === 137 && pool.id === 'ren')) { // Because of increasing quantity assert.approximately(Number(BN(balances[c])), Number(BN(initialBalances[c]).minus(BN(amount).toString())), 1e-2); - } else if (pool.name === 'ibbtc/sbtcCRV') { + } else if (pool.id === 'factory-v2-60') { assert.approximately(Number(BN(balances[c])), Number(BN(initialBalances[c]).minus(BN(amount).toString())), 1e-18); } else { assert.deepStrictEqual(BN(balances[c]), BN(initialBalances[c]).minus(BN(amount))); } }) - const delta = name === 'ELONXSWAP3CRV' ? 2 : 0.01 + const delta = id === 'factory-v2-80' ? 2 : 0.01 assert.approximately(Number(balances.lpToken) - Number(initialBalances.lpToken), Number(lpTokenExpected), delta); }); @@ -96,7 +97,7 @@ const wrappedLiquidityTest = (name: string) => { assert.deepStrictEqual(BN(balances.lpToken), BN(initialBalances.lpToken).minus(BN(lpTokenAmount))); pool.coins.forEach((c: string, i: number) => { - const delta = name == 'gusd' ? 0.011 : name === 'ELONXSWAP3CRV' ? 2 : 0.01 + const delta = id == 'gusd' ? 0.011 : id === 'factory-v2-80' ? 2 : 0.01 assert.approximately(Number(balances[c]) - Number(initialBalances[c]), Number(coinsExpected[i]), delta); }); }); @@ -114,10 +115,10 @@ const wrappedLiquidityTest = (name: string) => { const balances = await pool.balances() as DictInterface; - const delta = name === 'ELONXSWAP3CRV' ? 2 : 0.01 + const delta = id === 'factory-v2-80' ? 2 : 0.01 assert.approximately(Number(initialBalances.lpToken) - Number(balances.lpToken), Number(lpTokenExpected), delta); pool.coins.forEach((c: string) => { - if (['aave', 'saave'].includes(name) || (curve.chainId === 137 && pool.name === 'ren')) { + if (['aave', 'saave'].includes(id) || (curve.chainId === 137 && pool.id === 'ren')) { assert.approximately(Number(initialBalances[c]), Number(BN(balances[c]).minus(BN(amount)).toString()), 1e-4); } else { assert.deepStrictEqual(BN(initialBalances[c]), BN(balances[c]).minus(BN(amount))); @@ -126,7 +127,7 @@ const wrappedLiquidityTest = (name: string) => { } }); - if (!['compound', 'usdt', 'y', 'busd', 'pax'].includes(name)) { + if (!['compound', 'usdt', 'y', 'busd', 'pax'].includes(id)) { it('Removes liquidity one coin', async function () { const initialBalances = await pool.balances() as DictInterface; const lpTokenAmount: string = BN(initialBalances.lpToken).div(10).toFixed(18); @@ -141,7 +142,7 @@ const wrappedLiquidityTest = (name: string) => { if (i === 0) { assert.approximately(Number(balances[c]) - Number(initialBalances[c]), Number(expected), 0.01); } else { - if (['aave', 'saave'].includes(name) || (curve.chainId === 137 && this.name === 'ren')) { + if (['aave', 'saave'].includes(id) || (curve.chainId === 137 && this.id === 'ren')) { // Because of increasing quantity assert.approximately(Number(balances[c]), Number(initialBalances[c]), 1e-4); } else { @@ -154,13 +155,13 @@ const wrappedLiquidityTest = (name: string) => { }); } -const wrappedExchangeTest = (name: string) => { - describe(`${name} exchange`, function () { +const wrappedExchangeTest = (id: string) => { + describe(`${id} exchange`, function () { for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (i !== j) { it(`${i} --> ${j}`, async function () { - const pool = new curve.Pool(name); + const pool = new curve.Pool(id); const coinAddresses = pool.coinAddresses; if (i >= coinAddresses.length || j >= coinAddresses.length) { console.log('Skip') @@ -173,10 +174,10 @@ const wrappedExchangeTest = (name: string) => { const coinBalances = await pool.coinBalances() as DictInterface; - if (['aave', 'saave'].includes(pool.name) || (curve.chainId === 137 && pool.name === 'ren')) { + if (['aave', 'saave'].includes(pool.id) || (curve.chainId === 137 && pool.id === 'ren')) { // Because of increasing quantity assert.approximately(Number(Object.values(coinBalances)[i]), Number(BN(Object.values(initialCoinBalances)[i]).minus(BN(swapAmount).toString())), 1e-2); - } else if (pool.name === 'ibbtc/sbtcCRV') { + } else if (pool.id === 'factory-v2-60') { assert.approximately(Number(Object.values(coinBalances)[i]), Number(BN(Object.values(initialCoinBalances)[i]).minus(BN(swapAmount)).toString()), 1e-18); } else { assert.deepStrictEqual(BN(Object.values(coinBalances)[i]), BN(Object.values(initialCoinBalances)[i]).minus(BN(swapAmount))); @@ -195,17 +196,17 @@ describe('Wrapped test', async function () { before(async function () { await curve.init('JsonRpc', {}, { gasPrice: 0 }); - // await curve.fetchFactoryPools(); + await curve.fetchFactoryPools(); await curve.fetchCryptoFactoryPools(); }); - for (const poolName of ETHEREUM_POOLS) { - wrappedLiquidityTest(poolName); - wrappedExchangeTest(poolName); - } - - // for (const poolName of POLYGON_POOLS) { - // wrappedLiquidityTest(poolName); - // wrappedExchangeTest(poolName); + // for (const poolId of ETHEREUM_POOLS) { + // wrappedLiquidityTest(poolId); + // wrappedExchangeTest(poolId); // } + + for (const poolId of POLYGON_POOLS) { + wrappedLiquidityTest(poolId); + wrappedExchangeTest(poolId); + } }) From e4cc7cd40ef1dd936af3e2909368a20c69cc22f0 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Tue, 22 Mar 2022 18:09:54 +0300 Subject: [PATCH 15/16] docs: change name --> id for factory pools --- README.md | 85 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index ebdc19db..36483e0a 100644 --- a/README.md +++ b/README.md @@ -791,47 +791,54 @@ import curve from "@curvefi/api"; const factoryPools = curve.getFactoryPoolList(); // [ - // 'ibEUR+sEUR-f', 'ibKRW+sKRW-f', 'ibEUR+sEUR-2-f', - // 'crvCRVsCRV-f', 'jGBP+TGBP-f', '2CRV-f', - // 'crvCRV-f', 'ibbtc/sbtcCRV-f', 'OUSD3CRV-f', - // 'aUSDC+aDAI-f', 'FEI3CRV3CRV-f', 'GrapeFUSD3CRV-f', - // 'SifuETH3CRV-f', 'RC_INV3CRV-f', 'RC_xRULER3CRV-f', - // 'RC_xCOVER3CRV-f', 'nUSD3CRV-f', 'cvxcrv-f', - // 'USDM3CRV-f', 'mEUR-f', 'waUSD3CRV-f', - // 'waBTC/sbtcCRV-f', 'DOLA3POOL3CRV-f', 'ibJPY+sJPY-f', - // 'ibAUD+sAUD-f', 'ibGBP+sGBP-f', 'ibCHF+sCHF-f', - // 'OPEN MATIC-f', 'EURN/EURT-f', 'sdCRV-f', - // 'BTCpx/sbtcCRV-f', 'PWRD3CRV3CRV-f', 'sansUSDT-f', - // 'alETH+ETH-f', '17PctCypt3CRV-f', '17PctCypt3CRV-2-f', - // 'tbtc2/sbtcCRV-f', 'kusd3pool3CRV-f', 'tusd3pool3CRV-f', - // 'PWRD3CRV-f', 'fUSD3CRV-f', 'TPD3CRV-f', - // 'DEI3CRV-f', 'MIM-UST-f', 'ETH/vETH2-f', - // 'QBITWELLS3CRV-f', 'QWell13CRV-f', 'bveCVX-CVX-f', - // 'UST_whv23CRV-f', 'DSU+3Crv3CRV-f', 'DSU3CRV-f', - // 'aETHb-f', 'D3-f', 'aMATICb-f', - // 'pax-usdp3CRV-f', 'ibbtc/sbtcCRV-2-f', 'fxEUR_CRV-f', - // 'ORK/sbtcCRV-f', 'agEUR/sEUR-f', 'ibZAR+ZARP-f', - // '3DYDX3CRV-f', '3EURpool-f', 'tWETH+WETH-f', - // 'XSTUSD3CRV-f', 'XIM3CRV3CRV-f', 'XIM3CRV-f', - // 'RAMP rUSD3CRV-f', 'bhome3CRV-f', 'JPYC+ibJPY-f', - // 'UST-FRAX-f', 'FEIPCV-1-f', 'bentcvx-f', - // 'USX3CRV3CRV-f', 'ag+ib-EUR-f', 'tFRAX+FRAX-f', - // 'ELONXSWAP3CRV-f', 'BEAN3CRV-f', 'USDV3CRV-f', - // 'PARUSDC3CRV-f', 'baoUSD-3CRV-f', 'sUSD3CRV-f', - // 'AETHV13CRV-f', - // ]; + // 'factory-v2-0', 'factory-v2-1', 'factory-v2-2', 'factory-v2-3', + // 'factory-v2-4', 'factory-v2-5', 'factory-v2-6', 'factory-v2-7', + // 'factory-v2-8', 'factory-v2-9', 'factory-v2-10', 'factory-v2-11', + // 'factory-v2-12', 'factory-v2-13', 'factory-v2-14', 'factory-v2-15', + // 'factory-v2-16', 'factory-v2-17', 'factory-v2-18', 'factory-v2-19', + // 'factory-v2-20', 'factory-v2-21', 'factory-v2-22', 'factory-v2-23', + // 'factory-v2-24', 'factory-v2-25', 'factory-v2-26', 'factory-v2-27', + // 'factory-v2-28', 'factory-v2-29', 'factory-v2-30', 'factory-v2-31', + // 'factory-v2-32', 'factory-v2-33', 'factory-v2-34', 'factory-v2-35', + // 'factory-v2-36', 'factory-v2-37', 'factory-v2-38', 'factory-v2-39', + // 'factory-v2-40', 'factory-v2-41', 'factory-v2-42', 'factory-v2-43', + // 'factory-v2-44', 'factory-v2-45', 'factory-v2-46', 'factory-v2-47', + // 'factory-v2-48', 'factory-v2-49', 'factory-v2-50', 'factory-v2-51', + // 'factory-v2-52', 'factory-v2-53', 'factory-v2-54', 'factory-v2-55', + // 'factory-v2-56', 'factory-v2-57', 'factory-v2-58', 'factory-v2-59', + // 'factory-v2-60', 'factory-v2-61', 'factory-v2-62', 'factory-v2-63', + // 'factory-v2-64', 'factory-v2-65', 'factory-v2-66', 'factory-v2-67', + // 'factory-v2-68', 'factory-v2-69', 'factory-v2-70', 'factory-v2-71', + // 'factory-v2-72', 'factory-v2-73', 'factory-v2-74', 'factory-v2-75', + // 'factory-v2-76', 'factory-v2-77', 'factory-v2-78', 'factory-v2-79', + // 'factory-v2-80', 'factory-v2-81', 'factory-v2-82', 'factory-v2-83', + // 'factory-v2-84', 'factory-v2-85', 'factory-v2-86', 'factory-v2-87', + // 'factory-v2-88', 'factory-v2-89', 'factory-v2-90', 'factory-v2-91', + // 'factory-v2-92', 'factory-v2-93', 'factory-v2-94', 'factory-v2-95', + // 'factory-v2-96', 'factory-v2-97', 'factory-v2-98', 'factory-v2-99', + // ] const cryptoFactoryPools = curve.getCryptoFactoryPoolList() // [ - // 'FXSETH-fV2', 'FXSETH-2-fV2', - // 'FXSETH-3-fV2', 'FXSETH-4-fV2', - // 'BADGERWBTC-fV2', 'INVDOLA-fV2', - // 'RAIFRAX-fV2', 'RAIETH-fV2', - // 'YFIETH-fV2', 'palStkAAVE-fV2', - // 'DYDXETH-fV2', 'SDTETH-fV2', - // 'CADCUSDC-fV2', 'RAIAGEUR-fV2', - // 'rp-eth-fV2', 'PARUSDC-fV2', - // 'DUCKETH-fV2', 'BTRFLYETH-fV2', - // ]; + // 'factory-crypto-0', 'factory-crypto-1', + // 'factory-crypto-2', 'factory-crypto-3', + // 'factory-crypto-4', 'factory-crypto-5', + // 'factory-crypto-6', 'factory-crypto-7', + // 'factory-crypto-8', 'factory-crypto-9', + // 'factory-crypto-10', 'factory-crypto-11', + // 'factory-crypto-12', 'factory-crypto-13', + // 'factory-crypto-14', 'factory-crypto-15', + // 'factory-crypto-16', 'factory-crypto-17', + // 'factory-crypto-18', 'factory-crypto-19', + // 'factory-crypto-20', 'factory-crypto-21', + // 'factory-crypto-22', 'factory-crypto-23', + // 'factory-crypto-24', 'factory-crypto-25', + // 'factory-crypto-26', 'factory-crypto-27', + // 'factory-crypto-28', 'factory-crypto-29', + // 'factory-crypto-30', 'factory-crypto-31', + // 'factory-crypto-32', 'factory-crypto-33', + // 'factory-crypto-34', 'factory-crypto-35', + // 'factory-crypto-36', 'factory-crypto-37' + // ] })() ``` \ No newline at end of file From 8ffe048aa7e9df1b5e14bf6b081e34728561d5c9 Mon Sep 17 00:00:00 2001 From: Makeev Ivan Date: Tue, 22 Mar 2022 18:13:11 +0300 Subject: [PATCH 16/16] build: v1.21.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13bc79ce..4261ee85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@curvefi/api", - "version": "1.20.2", + "version": "1.21.0", "description": "JavaScript library for curve.fi", "main": "lib/index.js", "scripts": {