From c6bca5761b9eb8f18bb4ce0089007a20cd4244fc Mon Sep 17 00:00:00 2001 From: Vadim Pashkov Date: Wed, 21 Jun 2023 15:39:32 +0400 Subject: [PATCH 01/17] (feat) Interact directly with the pool in Uniswap connector --- src/chains/ethereum/ethereum.ts | 5 + src/connectors/uniswap/uniswap.config.ts | 9 + src/connectors/uniswap/uniswap.ts | 257 +++++++++++++++++++---- src/services/common-interfaces.ts | 1 - src/services/schema/uniswap-schema.json | 7 +- src/templates/uniswap.yml | 15 ++ test/connectors/uniswap/uniswap.test.ts | 233 +++++++++++++++++--- 7 files changed, 448 insertions(+), 79 deletions(-) diff --git a/src/chains/ethereum/ethereum.ts b/src/chains/ethereum/ethereum.ts index 7808ad9718..b689063017 100644 --- a/src/chains/ethereum/ethereum.ts +++ b/src/chains/ethereum/ethereum.ts @@ -117,6 +117,11 @@ export class Ethereum extends EthereumBase implements Ethereumish { return this._metricsLogInterval; } + // in place for mocking + public get provider() { + return super.provider; + } + /** * Automatically update the prevailing gas price on the network. * diff --git a/src/connectors/uniswap/uniswap.config.ts b/src/connectors/uniswap/uniswap.config.ts index e3b5d104ba..a5a4ca4ba0 100644 --- a/src/connectors/uniswap/uniswap.config.ts +++ b/src/connectors/uniswap/uniswap.config.ts @@ -11,6 +11,9 @@ export namespace UniswapConfig { tradingTypes: (type: string) => Array; chainType: string; availableNetworks: Array; + useRouter?: boolean; + feeTier?: string; + quoterContractAddress: (network: string) => string; } export const config: NetworkConfig = { @@ -56,5 +59,11 @@ export namespace UniswapConfig { ), }, ], + useRouter: ConfigManagerV2.getInstance().get(`uniswap.useRouter`), + feeTier: ConfigManagerV2.getInstance().get(`uniswap.feeTier`), + quoterContractAddress: (network: string) => + ConfigManagerV2.getInstance().get( + `uniswap.contractAddresses.${network}.uniswapV3QuoterV2ContractAddress` + ), }; } diff --git a/src/connectors/uniswap/uniswap.ts b/src/connectors/uniswap/uniswap.ts index a016f2ef90..873cdc0469 100644 --- a/src/connectors/uniswap/uniswap.ts +++ b/src/connectors/uniswap/uniswap.ts @@ -8,7 +8,17 @@ import { } from '@ethersproject/contracts'; import { AlphaRouter } from '@uniswap/smart-order-router'; import { Trade, SwapRouter } from '@uniswap/router-sdk'; -import { MethodParameters } from '@uniswap/v3-sdk'; +import { + FeeAmount, + MethodParameters, + Pool, + SwapQuoter, + Trade as UniswapV3Trade, + Route, + FACTORY_ADDRESS, +} from '@uniswap/v3-sdk'; +import { abi as IUniswapV3PoolABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json'; +import { abi as IUniswapV3FactoryABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Factory.sol/IUniswapV3Factory.json'; import { Token, CurrencyAmount, @@ -16,7 +26,14 @@ import { TradeType, Currency, } from '@uniswap/sdk-core'; -import { BigNumber, Transaction, Wallet } from 'ethers'; +import { + BigNumber, + Transaction, + Wallet, + Contract, + utils, + constants, +} from 'ethers'; import { logger } from '../../services/logger'; import { percentRegexp } from '../../services/config-manager-v2'; import { Ethereum } from '../../chains/ethereum/ethereum'; @@ -35,6 +52,9 @@ export class Uniswap implements Uniswapish { private chainId; private tokenList: Record = {}; private _ready: boolean = false; + private readonly _useRouter: boolean; + private readonly _feeTier: FeeAmount; + private readonly _quoterContractAddress: string; private constructor(chain: string, network: string) { const config = UniswapConfig.config; @@ -53,6 +73,20 @@ export class Uniswap implements Uniswapish { this._routerAbi = routerAbi.abi; this._gasLimitEstimate = UniswapConfig.config.gasLimitEstimate; this._router = config.uniswapV3SmartOrderRouterAddress(network); + + if (config.useRouter === false && config.feeTier == null) { + throw new Error('Must specify fee tier if not using router'); + } + if (config.useRouter === false && config.quoterContractAddress == null) { + throw new Error( + 'Must specify quoter contract address if not using router' + ); + } + this._useRouter = config.useRouter ?? true; + this._feeTier = config.feeTier + ? FeeAmount[config.feeTier as keyof typeof FeeAmount] + : FeeAmount.MEDIUM; + this._quoterContractAddress = config.quoterContractAddress(network); } public static getInstance(chain: string, network: string): Uniswap { @@ -181,30 +215,61 @@ export class Uniswap implements Uniswapish { `Fetching trade data for ${baseToken.address}-${quoteToken.address}.` ); - const route = await this._alphaRouter.route( - nativeTokenAmount, - quoteToken, - TradeType.EXACT_INPUT, - undefined, - { - maxSwapsPerPath: this.maximumHops, - } - ); + if (this._useRouter) { + const route = await this._alphaRouter.route( + nativeTokenAmount, + quoteToken, + TradeType.EXACT_INPUT, + undefined, + { + maxSwapsPerPath: this.maximumHops, + } + ); - if (!route) { - throw new UniswapishPriceError( - `priceSwapIn: no trade pair found for ${baseToken} to ${quoteToken}.` + if (!route) { + throw new UniswapishPriceError( + `priceSwapIn: no trade pair found for ${baseToken.address} to ${quoteToken.address}.` + ); + } + logger.info( + `Best trade for ${baseToken.address}-${quoteToken.address}: ` + + `${route.trade.executionPrice.toFixed(6)}` + + `${baseToken.symbol}.` + ); + const expectedAmount = route.trade.minimumAmountOut( + this.getAllowedSlippage(allowedSlippage) ); + return { trade: route.trade, expectedAmount }; + } else { + const pool = await this.getPool(baseToken, quoteToken, this._feeTier); + if (!pool) { + throw new UniswapishPriceError( + `priceSwapIn: no trade pair found for ${baseToken.address} to ${quoteToken.address}.` + ); + } + const swapRoute = new Route([pool], baseToken, quoteToken); + const quotedAmount = await this.getQuote( + swapRoute, + quoteToken, + nativeTokenAmount, + TradeType.EXACT_INPUT + ); + const trade = UniswapV3Trade.createUncheckedTrade({ + route: swapRoute, + inputAmount: nativeTokenAmount, + outputAmount: quotedAmount, + tradeType: TradeType.EXACT_INPUT, + }); + logger.info( + `Best trade for ${baseToken.address}-${quoteToken.address}: ` + + `${trade.executionPrice.toFixed(6)}` + + `${baseToken.symbol}.` + ); + const expectedAmount = trade.minimumAmountOut( + this.getAllowedSlippage(allowedSlippage) + ); + return { trade, expectedAmount }; } - logger.info( - `Best trade for ${baseToken.address}-${quoteToken.address}: ` + - `${route.trade.executionPrice.toFixed(6)}` + - `${baseToken.symbol}.` - ); - const expectedAmount = route.trade.minimumAmountOut( - this.getAllowedSlippage(allowedSlippage) - ); - return { trade: route.trade, expectedAmount }; } /** @@ -228,30 +293,62 @@ export class Uniswap implements Uniswapish { logger.info( `Fetching pair data for ${quoteToken.address}-${baseToken.address}.` ); - const route = await this._alphaRouter.route( - nativeTokenAmount, - quoteToken, - TradeType.EXACT_OUTPUT, - undefined, - { - maxSwapsPerPath: this.maximumHops, + + if (this._useRouter) { + const route = await this._alphaRouter.route( + nativeTokenAmount, + quoteToken, + TradeType.EXACT_OUTPUT, + undefined, + { + maxSwapsPerPath: this.maximumHops, + } + ); + if (!route) { + throw new UniswapishPriceError( + `priceSwapOut: no trade pair found for ${quoteToken.address} to ${baseToken.address}.` + ); } - ); - if (!route) { - throw new UniswapishPriceError( - `priceSwapOut: no trade pair found for ${quoteToken.address} to ${baseToken.address}.` + logger.info( + `Best trade for ${quoteToken.address}-${baseToken.address}: ` + + `${route.trade.executionPrice.invert().toFixed(6)} ` + + `${baseToken.symbol}.` ); - } - logger.info( - `Best trade for ${quoteToken.address}-${baseToken.address}: ` + - `${route.trade.executionPrice.invert().toFixed(6)} ` + - `${baseToken.symbol}.` - ); - const expectedAmount = route.trade.maximumAmountIn( - this.getAllowedSlippage(allowedSlippage) - ); - return { trade: route.trade, expectedAmount }; + const expectedAmount = route.trade.maximumAmountIn( + this.getAllowedSlippage(allowedSlippage) + ); + return { trade: route.trade, expectedAmount }; + } else { + const pool = await this.getPool(quoteToken, baseToken, this._feeTier); + if (!pool) { + throw new UniswapishPriceError( + `priceSwapOut: no trade pair found for ${quoteToken.address} to ${baseToken.address}.` + ); + } + const swapRoute = new Route([pool], quoteToken, baseToken); + const quotedAmount = await this.getQuote( + swapRoute, + quoteToken, + nativeTokenAmount, + TradeType.EXACT_OUTPUT + ); + const trade = UniswapV3Trade.createUncheckedTrade({ + route: swapRoute, + inputAmount: quotedAmount, + outputAmount: nativeTokenAmount, + tradeType: TradeType.EXACT_OUTPUT, + }); + logger.info( + `Best trade for ${baseToken.address}-${quoteToken.address}: ` + + `${trade.executionPrice.invert().toFixed(6)}` + + `${baseToken.symbol}.` + ); + const expectedAmount = trade.maximumAmountIn( + this.getAllowedSlippage(allowedSlippage) + ); + return { trade, expectedAmount }; + } } /** @@ -308,7 +405,7 @@ export class Uniswap implements Uniswapish { } else { tx = await wallet.sendTransaction({ data: methodParameters.calldata, - to: this.router, + to: uniswapRouter, gasPrice: (gasPrice * 1e9).toFixed(0), gasLimit: gasLimit.toFixed(0), value: methodParameters.value, @@ -320,4 +417,74 @@ export class Uniswap implements Uniswapish { } ); } + + private async getPool( + tokenA: Token, + tokenB: Token, + feeTier: FeeAmount + ): Promise { + const uniswapFactory = new Contract( + FACTORY_ADDRESS, + IUniswapV3FactoryABI, + this.chain.provider + ); + // Use Uniswap V3 factory to get pool address instead of `Pool.getAddress` to check if pool exists. + const poolAddress = await uniswapFactory.getPool( + tokenA.address, + tokenB.address, + feeTier + ); + if (poolAddress === constants.AddressZero) { + return null; + } + const poolContract = new Contract( + poolAddress, + IUniswapV3PoolABI, + this.chain.provider + ); + + const [liquidity, slot0] = await Promise.all([ + poolContract.liquidity(), + poolContract.slot0(), + ]); + const [sqrtPriceX96, tick] = slot0; + + const pool = new Pool( + tokenA, + tokenB, + this._feeTier, + sqrtPriceX96, + liquidity, + tick + ); + + return pool; + } + + private async getQuote( + swapRoute: Route, + quoteToken: Token, + amount: CurrencyAmount, + tradeType: TradeType + ) { + const { calldata } = await SwapQuoter.quoteCallParameters( + swapRoute, + amount, + tradeType, + { useQuoterV2: true } + ); + const quoteCallReturnData = await this.chain.provider.call({ + to: this._quoterContractAddress, + data: calldata, + }); + const quoteTokenRawAmount = utils.defaultAbiCoder.decode( + ['uint256'], + quoteCallReturnData + ); + const qouteTokenAmount = CurrencyAmount.fromRawAmount( + quoteToken, + quoteTokenRawAmount.toString() + ); + return qouteTokenAmount; + } } diff --git a/src/services/common-interfaces.ts b/src/services/common-interfaces.ts index 4d57854d3b..7f4b2559b9 100644 --- a/src/services/common-interfaces.ts +++ b/src/services/common-interfaces.ts @@ -148,7 +148,6 @@ export type UniswapishTrade = | TradeQuickswap | TradeTraderjoe | SushiswapTrade - | UniswapV3Trade | TradeUniswap | TradeDefikingdoms | DefiraTrade diff --git a/src/services/schema/uniswap-schema.json b/src/services/schema/uniswap-schema.json index 91710caf14..3585d376b4 100644 --- a/src/services/schema/uniswap-schema.json +++ b/src/services/schema/uniswap-schema.json @@ -6,6 +6,10 @@ "gasLimitEstimate": { "type": "integer" }, "ttl": { "type": "integer" }, "maximumHops": { "type": "integer" }, + "useRouter": { "type": "boolean" }, + "feeTier": { + "enum": ["LOWEST", "LOW", "MEDIUM", "HIGH"] + }, "contractAddresses": { "type": "object", "patternProperties": { @@ -13,7 +17,8 @@ "type": "object", "properties": { "uniswapV3SmartOrderRouterAddress": { "type": "string" }, - "uniswapV3NftManagerAddress": { "type": "string" } + "uniswapV3NftManagerAddress": { "type": "string" }, + "uniswapV3QuoterV2ContractAddress": { "type": "string" } }, "required": [ "uniswapV3SmartOrderRouterAddress", diff --git a/src/templates/uniswap.yml b/src/templates/uniswap.yml index f4001280d2..c1f00b1487 100644 --- a/src/templates/uniswap.yml +++ b/src/templates/uniswap.yml @@ -13,19 +13,34 @@ ttl: 600 # Note: More hops will increase latency of the algorithm. maximumHops: 4 +# Use Uniswap Router or Quoter for quoting prices. +# true - use Uniswap Router. +# false - use Uniswap Quoter. +useRouter: true + +# Fee tier to use for the Uniswap Quoter. +# Required if `useRouter` is false. +# Available options: 'LOWEST', 'LOW', 'MEDIUM', 'HIGH'. +feeTier: 'MEDIUM' + contractAddresses: mainnet: uniswapV3SmartOrderRouterAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' uniswapV3NftManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' + uniswapV3QuoterV2ContractAddress: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' goerli: uniswapV3SmartOrderRouterAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' uniswapV3NftManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' + uniswapV3QuoterV2ContractAddress: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' arbitrum_one: uniswapV3SmartOrderRouterAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' uniswapV3NftManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' + uniswapV3QuoterV2ContractAddress: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' optimism: uniswapV3SmartOrderRouterAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' uniswapV3NftManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' + uniswapV3QuoterV2ContractAddress: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' mumbai: uniswapV3SmartOrderRouterAddress: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' uniswapV3NftManagerAddress: '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' + uniswapV3QuoterV2ContractAddress: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e' diff --git a/test/connectors/uniswap/uniswap.test.ts b/test/connectors/uniswap/uniswap.test.ts index 3b666a653d..ff81685ad6 100644 --- a/test/connectors/uniswap/uniswap.test.ts +++ b/test/connectors/uniswap/uniswap.test.ts @@ -1,16 +1,26 @@ jest.useFakeTimers(); +const { MockProvider } = require('mock-ethers-provider'); import { Uniswap } from '../../../src/connectors/uniswap/uniswap'; import { patch, unpatch } from '../../services/patch'; import { UniswapishPriceError } from '../../../src/services/error-handler'; import { CurrencyAmount, Percent, TradeType, Token } from '@uniswap/sdk-core'; import { Pair, Route } from '@uniswap/v2-sdk'; import { Trade } from '@uniswap/router-sdk'; -import { BigNumber, utils } from 'ethers'; +import { BigNumber, constants, utils } from 'ethers'; import { Ethereum } from '../../../src/chains/ethereum/ethereum'; import { patchEVMNonceManager } from '../../evm.nonce.mock'; +import { UniswapConfig } from '../../../src/connectors/uniswap/uniswap.config'; +import { + FACTORY_ADDRESS, + TickMath, + encodeSqrtRatioX96, + Pool as UniswapV3Pool, + FeeAmount, +} from '@uniswap/v3-sdk'; let ethereum: Ethereum; let uniswap: Uniswap; +let mockProvider: typeof MockProvider; const WETH = new Token( 3, @@ -26,13 +36,23 @@ const DAI = new Token( 'DAI' ); +const DAI_WETH_POOL_ADDRESS = '0xBEff876AC507446457C2A6bDA9F7021A97A8547f'; +const POOL_SQRT_RATIO_START = encodeSqrtRatioX96(100e6, 100e18); +const POOL_TICK_CURRENT = TickMath.getTickAtSqrtRatio(POOL_SQRT_RATIO_START); +const POOL_LIQUIDITY = 0; +const DAI_WETH_POOL = new UniswapV3Pool( + WETH, + DAI, + FeeAmount.MEDIUM, + POOL_SQRT_RATIO_START, + POOL_LIQUIDITY, + POOL_TICK_CURRENT +); + beforeAll(async () => { ethereum = Ethereum.getInstance('goerli'); patchEVMNonceManager(ethereum.nonceManager); await ethereum.init(); - - uniswap = Uniswap.getInstance('ethereum', 'goerli'); - await uniswap.init(); }); beforeEach(() => { @@ -94,47 +114,196 @@ const patchTrade = (_key: string, error?: Error) => { }); }; +const patchMockProvider = () => { + mockProvider.setMockContract( + FACTORY_ADDRESS, + require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json') + .abi + ); + mockProvider.stub(FACTORY_ADDRESS, 'getPool', DAI_WETH_POOL_ADDRESS); + + mockProvider.setMockContract( + UniswapConfig.config.quoterContractAddress('goerli'), + require('@uniswap/swap-router-contracts/artifacts/contracts/lens/QuoterV2.sol/QuoterV2.json') + .abi + ); + mockProvider.stub( + UniswapConfig.config.quoterContractAddress('goerli'), + 'quoteExactInputSingle', + /* amountOut */ 1, + /* sqrtPriceX96After */ 0, + /* initializedTicksCrossed */ 0, + /* gasEstimate */ 0 + ); + mockProvider.stub( + UniswapConfig.config.quoterContractAddress('goerli'), + 'quoteExactOutputSingle', + /* amountIn */ 1, + /* sqrtPriceX96After */ 0, + /* initializedTicksCrossed */ 0, + /* gasEstimate */ 0 + ); + + mockProvider.setMockContract( + DAI_WETH_POOL_ADDRESS, + require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json') + .abi + ); + mockProvider.stub( + DAI_WETH_POOL_ADDRESS, + 'slot0', + DAI_WETH_POOL.sqrtRatioX96.toString(), + DAI_WETH_POOL.tickCurrent, + /* observationIndex */ 0, + /* observationCardinality */ 1, + /* observationCardinalityNext */ 1, + /* feeProtocol */ 0, + /* unlocked */ true + ); + mockProvider.stub(DAI_WETH_POOL_ADDRESS, 'liquidity', 0); + patch(ethereum, 'provider', () => { + return mockProvider; + }); +}; + +const patchGetPool = (address: string | null) => { + mockProvider.setMockContract( + FACTORY_ADDRESS, + require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json') + .abi + ); + mockProvider.stub(FACTORY_ADDRESS, 'getPool', address); +}; + +const useRouter = async () => { + const config = UniswapConfig.config; + config.useRouter = true; + + patch(Uniswap, '_instances', () => ({})); + uniswap = Uniswap.getInstance('ethereum', 'goerli'); + await uniswap.init(); +}; + +const useQouter = async () => { + const config = UniswapConfig.config; + config.useRouter = false; + config.feeTier = 'MEDIUM'; + + patch(Uniswap, '_instances', () => ({})); + uniswap = Uniswap.getInstance('ethereum', 'goerli'); + await uniswap.init(); + + mockProvider = new MockProvider(); + patchMockProvider(); +}; + describe('verify Uniswap estimateSellTrade', () => { - it('Should return an ExpectedTrade when available', async () => { - patchTrade('bestTradeExactIn'); + describe('when using router', () => { + beforeAll(async () => { + await useRouter(); + }); - const expectedTrade = await uniswap.estimateSellTrade( - WETH, - DAI, - BigNumber.from(1) - ); - expect(expectedTrade).toHaveProperty('trade'); - expect(expectedTrade).toHaveProperty('expectedAmount'); + it('Should return an ExpectedTrade when available', async () => { + patchTrade('bestTradeExactIn'); + + const expectedTrade = await uniswap.estimateSellTrade( + WETH, + DAI, + BigNumber.from(1) + ); + expect(expectedTrade).toHaveProperty('trade'); + expect(expectedTrade).toHaveProperty('expectedAmount'); + }); + + it('Should throw an error if no pair is available', async () => { + patchTrade('bestTradeExactIn', new Error('error getting trade')); + + await expect(async () => { + await uniswap.estimateSellTrade(WETH, DAI, BigNumber.from(1)); + }).rejects.toThrow(UniswapishPriceError); + }); }); - it('Should throw an error if no pair is available', async () => { - patchTrade('bestTradeExactIn', new Error('error getting trade')); + describe('when using qouter', () => { + beforeEach(async () => { + await useQouter(); + }); + + it('Should return an ExpectedTrade when available', async () => { + patchGetPool(DAI_WETH_POOL_ADDRESS); + + const expectedTrade = await uniswap.estimateSellTrade( + WETH, + DAI, + BigNumber.from(1) + ); + + expect(expectedTrade).toHaveProperty('trade'); + expect(expectedTrade).toHaveProperty('expectedAmount'); + }); + + it('Should throw an error if no pair is available', async () => { + patchGetPool(constants.AddressZero); - await expect(async () => { - await uniswap.estimateSellTrade(WETH, DAI, BigNumber.from(1)); - }).rejects.toThrow(UniswapishPriceError); + await expect(async () => { + await uniswap.estimateSellTrade(WETH, DAI, BigNumber.from(1)); + }).rejects.toThrow(UniswapishPriceError); + }); }); }); describe('verify Uniswap estimateBuyTrade', () => { - it('Should return an ExpectedTrade when available', async () => { - patchTrade('bestTradeExactOut'); + describe('when using router', () => { + beforeAll(async () => { + await useRouter(); + }); - const expectedTrade = await uniswap.estimateBuyTrade( - WETH, - DAI, - BigNumber.from(1) - ); - expect(expectedTrade).toHaveProperty('trade'); - expect(expectedTrade).toHaveProperty('expectedAmount'); + it('Should return an ExpectedTrade when available', async () => { + patchTrade('bestTradeExactOut'); + + const expectedTrade = await uniswap.estimateBuyTrade( + WETH, + DAI, + BigNumber.from(1) + ); + expect(expectedTrade).toHaveProperty('trade'); + expect(expectedTrade).toHaveProperty('expectedAmount'); + }); + + it('Should return an error if no pair is available', async () => { + patchTrade('bestTradeExactOut', new Error('error getting trade')); + + await expect(async () => { + await uniswap.estimateBuyTrade(WETH, DAI, BigNumber.from(1)); + }).rejects.toThrow(UniswapishPriceError); + }); }); - it('Should return an error if no pair is available', async () => { - patchTrade('bestTradeExactOut', new Error('error getting trade')); + describe('when using qouter', () => { + beforeEach(async () => { + await useQouter(); + }); + + it('Should return an ExpectedTrade when available', async () => { + patchGetPool(DAI_WETH_POOL_ADDRESS); + + const expectedTrade = await uniswap.estimateBuyTrade( + WETH, + DAI, + BigNumber.from(1) + ); + + expect(expectedTrade).toHaveProperty('trade'); + expect(expectedTrade).toHaveProperty('expectedAmount'); + }); + + it('Should throw an error if no pair is available', async () => { + patchGetPool(constants.AddressZero); - await expect(async () => { - await uniswap.estimateBuyTrade(WETH, DAI, BigNumber.from(1)); - }).rejects.toThrow(UniswapishPriceError); + await expect(async () => { + await uniswap.estimateBuyTrade(WETH, DAI, BigNumber.from(1)); + }).rejects.toThrow(UniswapishPriceError); + }); }); }); From 01fb1ffcf67750abccf1debafc60905c06f648e1 Mon Sep 17 00:00:00 2001 From: nikspz <83953535+nikspz@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:28:27 +0700 Subject: [PATCH 02/17] fix/ Update version in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 31f467fc88..c4c0e1ec69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hummingbot-gateway", - "version": "1.16.0", + "version": "1.17.0", "description": "Middleware that helps Hummingbot clients access standardized DEX API endpoints on different blockchain networks", "main": "index.js", "license": "Apache-2.0", From 5d5dd22b36824fee0b1d94dd403f018019951625 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 13:37:38 +0000 Subject: [PATCH 03/17] Bump socket.io-parser from 4.2.2 to 4.2.4 Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 4.2.2 to 4.2.4. - [Release notes](https://github.com/socketio/socket.io-parser/releases) - [Changelog](https://github.com/socketio/socket.io-parser/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io-parser/compare/4.2.2...4.2.4) --- updated-dependencies: - dependency-name: socket.io-parser dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 370 +++++++++++++++++++++++++++--------------------------- 1 file changed, 185 insertions(+), 185 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7d06a4b314..1b59d4a6e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -987,137 +987,137 @@ "@ethersproject-xdc/abi@file:vendor/@ethersproject-xdc/abi": version "5.7.0" dependencies: - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/hash" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/hash" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abi-5.7.0-96d078a1-80cd-4b7a-9730-dedded86cc1b-1686225288604/node_modules/@ethersproject-xdc/strings" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/hash" "file:vendor/@ethersproject-xdc/hash" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" "@ethersproject-xdc/abstract-provider@file:vendor/@ethersproject-xdc/abstract-provider": version "5.7.0" dependencies: - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/networks" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/networks" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/transactions" - "@ethersproject-xdc/web" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-provider-5.7.0-5e41186b-3d49-41fa-b218-d2a9b551688e-1686225288603/node_modules/@ethersproject-xdc/web" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/networks" "file:vendor/@ethersproject-xdc/networks" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" + "@ethersproject-xdc/web" "file:vendor/@ethersproject-xdc/web" "@ethersproject-xdc/abstract-signer@file:vendor/@ethersproject-xdc/abstract-signer": version "5.7.0" dependencies: - "@ethersproject-xdc/abstract-provider" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-signer-5.7.0-ad6702a7-47b2-4a62-8e93-4110c299c077-1686225288602/node_modules/@ethersproject-xdc/abstract-provider" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-signer-5.7.0-ad6702a7-47b2-4a62-8e93-4110c299c077-1686225288602/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-signer-5.7.0-ad6702a7-47b2-4a62-8e93-4110c299c077-1686225288602/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-signer-5.7.0-ad6702a7-47b2-4a62-8e93-4110c299c077-1686225288602/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-abstract-signer-5.7.0-ad6702a7-47b2-4a62-8e93-4110c299c077-1686225288602/node_modules/@ethersproject-xdc/properties" + "@ethersproject-xdc/abstract-provider" "file:vendor/@ethersproject-xdc/abstract-provider" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" "@ethersproject-xdc/address@file:vendor/@ethersproject-xdc/address": version "5.7.0" dependencies: - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-address-5.7.0-5d10c9bf-60df-49eb-a1dc-1630f4c35eb3-1686225288603/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-address-5.7.0-5d10c9bf-60df-49eb-a1dc-1630f4c35eb3-1686225288603/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-address-5.7.0-5d10c9bf-60df-49eb-a1dc-1630f4c35eb3-1686225288603/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-address-5.7.0-5d10c9bf-60df-49eb-a1dc-1630f4c35eb3-1686225288603/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/rlp" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-address-5.7.0-5d10c9bf-60df-49eb-a1dc-1630f4c35eb3-1686225288603/node_modules/@ethersproject-xdc/rlp" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/rlp" "file:vendor/@ethersproject-xdc/rlp" "@ethersproject-xdc/base64@file:vendor/@ethersproject-xdc/base64": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-base64-5.7.0-85a2392e-cc58-4207-bce4-e24cb01386e5-1686225288603/node_modules/@ethersproject-xdc/bytes" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" "@ethersproject-xdc/basex@file:vendor/@ethersproject-xdc/basex": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-basex-5.7.0-b5082aa2-28ce-49dd-8f17-5abde9298d9e-1686225288603/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-basex-5.7.0-b5082aa2-28ce-49dd-8f17-5abde9298d9e-1686225288603/node_modules/@ethersproject-xdc/properties" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" "@ethersproject-xdc/bignumber@file:vendor/@ethersproject-xdc/bignumber": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-bignumber-5.7.0-60351a46-94cc-44e9-927b-0b140d67c105-1686225288605/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-bignumber-5.7.0-60351a46-94cc-44e9-927b-0b140d67c105-1686225288605/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" bn.js "^5.2.1" "@ethersproject-xdc/bytes@file:vendor/@ethersproject-xdc/bytes": version "5.7.0" dependencies: - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-bytes-5.7.0-0c530d22-8d9f-46db-9652-f95d88cdf83c-1686225288604/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/constants@file:vendor/@ethersproject-xdc/constants": version "5.7.0" dependencies: - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-constants-5.7.0-083cb356-dfbe-4cc1-8428-69da215d953d-1686225288606/node_modules/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" "@ethersproject-xdc/contracts@file:vendor/@ethersproject-xdc/contracts": version "5.6.0" dependencies: - "@ethersproject-xdc/abi" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/abi" - "@ethersproject-xdc/abstract-provider" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/abstract-provider" - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-contracts-5.6.0-16f0da67-c5fe-41ee-95f3-939689043c5a-1686225288605/node_modules/@ethersproject-xdc/transactions" + "@ethersproject-xdc/abi" "file:vendor/@ethersproject-xdc/abi" + "@ethersproject-xdc/abstract-provider" "file:vendor/@ethersproject-xdc/abstract-provider" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" "@ethersproject-xdc/hash@file:vendor/@ethersproject-xdc/hash": version "5.7.0" dependencies: - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/base64" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/base64" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hash-5.7.0-a7759acf-bef8-4757-802b-2ec177275b5b-1686225288608/node_modules/@ethersproject-xdc/strings" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/base64" "file:vendor/@ethersproject-xdc/base64" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" "@ethersproject-xdc/hdnode@file:vendor/@ethersproject-xdc/hdnode": version "5.7.0" dependencies: - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/basex" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/basex" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/pbkdf2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/pbkdf2" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/sha2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/sha2" - "@ethersproject-xdc/signing-key" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/signing-key" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/strings" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/transactions" - "@ethersproject-xdc/wordlists" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-hdnode-5.7.0-a2bd75ae-01f0-4270-9973-8f1aa5a8512b-1686225288607/node_modules/@ethersproject-xdc/wordlists" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/basex" "file:vendor/@ethersproject-xdc/basex" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/pbkdf2" "file:vendor/@ethersproject-xdc/pbkdf2" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/sha2" "file:vendor/@ethersproject-xdc/sha2" + "@ethersproject-xdc/signing-key" "file:vendor/@ethersproject-xdc/signing-key" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" + "@ethersproject-xdc/wordlists" "file:vendor/@ethersproject-xdc/wordlists" "@ethersproject-xdc/json-wallets@file:vendor/@ethersproject-xdc/json-wallets": version "5.6.0" dependencies: - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/hdnode" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/hdnode" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/pbkdf2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/pbkdf2" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/random" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/random" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/strings" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-json-wallets-5.6.0-ff3f4393-e794-4c7d-9864-79c7ba46bcb1-1686225288606/node_modules/@ethersproject-xdc/transactions" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/hdnode" "file:vendor/@ethersproject-xdc/hdnode" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/pbkdf2" "file:vendor/@ethersproject-xdc/pbkdf2" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/random" "file:vendor/@ethersproject-xdc/random" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" aes-js "3.0.0" scrypt-js "3.0.1" "@ethersproject-xdc/keccak256@file:vendor/@ethersproject-xdc/keccak256": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-keccak256-5.7.0-f0728b49-5c1d-4b33-9e4f-c611bec82a32-1686225288608/node_modules/@ethersproject-xdc/bytes" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" js-sha3 "0.8.0" "@ethersproject-xdc/logger@file:vendor/@ethersproject-xdc/logger": @@ -1126,67 +1126,67 @@ "@ethersproject-xdc/networks@file:vendor/@ethersproject-xdc/networks": version "5.7.1" dependencies: - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-networks-5.7.1-5508d5d5-e011-45d7-8a8b-f326387e9be1-1686225288606/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/pbkdf2@file:vendor/@ethersproject-xdc/pbkdf2": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-pbkdf2-5.7.0-5f457302-61b1-4a7f-98ec-d6182890704f-1686225288606/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/sha2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-pbkdf2-5.7.0-5f457302-61b1-4a7f-98ec-d6182890704f-1686225288606/node_modules/@ethersproject-xdc/sha2" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/sha2" "file:vendor/@ethersproject-xdc/sha2" "@ethersproject-xdc/properties@file:vendor/@ethersproject-xdc/properties": version "5.7.0" dependencies: - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-properties-5.7.0-2a9931db-de8b-4973-b43e-ba7525c0d08b-1686225288609/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/providers@file:vendor/@ethersproject-xdc/providers": version "5.6.2" dependencies: - "@ethersproject-xdc/abstract-provider" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/abstract-provider" - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/basex" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/basex" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/hash" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/hash" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/networks" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/networks" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/random" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/random" - "@ethersproject-xdc/rlp" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/rlp" - "@ethersproject-xdc/sha2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/sha2" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/strings" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/transactions" - "@ethersproject-xdc/web" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-providers-5.6.2-adb85a3d-006b-4730-b1c2-75655f672ec3-1686225288607/node_modules/@ethersproject-xdc/web" + "@ethersproject-xdc/abstract-provider" "file:vendor/@ethersproject-xdc/abstract-provider" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/basex" "file:vendor/@ethersproject-xdc/basex" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/hash" "file:vendor/@ethersproject-xdc/hash" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/networks" "file:vendor/@ethersproject-xdc/networks" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/random" "file:vendor/@ethersproject-xdc/random" + "@ethersproject-xdc/rlp" "file:vendor/@ethersproject-xdc/rlp" + "@ethersproject-xdc/sha2" "file:vendor/@ethersproject-xdc/sha2" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" + "@ethersproject-xdc/web" "file:vendor/@ethersproject-xdc/web" bech32 "1.1.4" ws "7.4.6" "@ethersproject-xdc/random@file:vendor/@ethersproject-xdc/random": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-random-5.7.0-9db0074d-fce3-493c-9738-364069bab1d5-1686225288615/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-random-5.7.0-9db0074d-fce3-493c-9738-364069bab1d5-1686225288615/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/rlp@file:vendor/@ethersproject-xdc/rlp": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-rlp-5.7.0-28796498-07b8-4a0c-9f53-35b21e68d308-1686225288609/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-rlp-5.7.0-28796498-07b8-4a0c-9f53-35b21e68d308-1686225288609/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/sha2@file:vendor/@ethersproject-xdc/sha2": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-sha2-5.7.0-2cd17dd8-580c-4a1d-aaa1-5159fa742627-1686225288611/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-sha2-5.7.0-2cd17dd8-580c-4a1d-aaa1-5159fa742627-1686225288611/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" hash.js "1.1.7" "@ethersproject-xdc/signing-key@file:vendor/@ethersproject-xdc/signing-key": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-signing-key-5.7.0-ca28fe36-94a4-4f8b-befc-401a79120b68-1686225288614/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-signing-key-5.7.0-ca28fe36-94a4-4f8b-befc-401a79120b68-1686225288614/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-signing-key-5.7.0-ca28fe36-94a4-4f8b-befc-401a79120b68-1686225288614/node_modules/@ethersproject-xdc/properties" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" bn.js "^5.2.1" elliptic "6.5.4" hash.js "1.1.7" @@ -1194,76 +1194,76 @@ "@ethersproject-xdc/solidity@file:vendor/@ethersproject-xdc/solidity": version "5.6.0" dependencies: - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/sha2" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/sha2" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-solidity-5.6.0-46a0cfbf-923f-4142-a1f4-702004c712fa-1686225288611/node_modules/@ethersproject-xdc/strings" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/sha2" "file:vendor/@ethersproject-xdc/sha2" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" "@ethersproject-xdc/strings@file:vendor/@ethersproject-xdc/strings": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-strings-5.7.0-f026bd56-0138-413e-8186-7600e2c653c3-1686225288609/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-strings-5.7.0-f026bd56-0138-413e-8186-7600e2c653c3-1686225288609/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-strings-5.7.0-f026bd56-0138-413e-8186-7600e2c653c3-1686225288609/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/transactions@file:vendor/@ethersproject-xdc/transactions": version "5.7.0" dependencies: - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/rlp" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/rlp" - "@ethersproject-xdc/signing-key" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-transactions-5.7.0-d1852b10-1a09-4c3a-847a-0f072be4cf58-1686225288615/node_modules/@ethersproject-xdc/signing-key" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/rlp" "file:vendor/@ethersproject-xdc/rlp" + "@ethersproject-xdc/signing-key" "file:vendor/@ethersproject-xdc/signing-key" "@ethersproject-xdc/units@file:vendor/@ethersproject-xdc/units": version "5.6.0" dependencies: - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-units-5.6.0-4ff8605f-1474-48e7-999a-2afe9110ccdc-1686225288615/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-units-5.6.0-4ff8605f-1474-48e7-999a-2afe9110ccdc-1686225288615/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-units-5.6.0-4ff8605f-1474-48e7-999a-2afe9110ccdc-1686225288615/node_modules/@ethersproject-xdc/logger" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" "@ethersproject-xdc/wallet@file:vendor/@ethersproject-xdc/wallet": version "5.6.0" dependencies: - "@ethersproject-xdc/abstract-provider" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/abstract-provider" - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/hash" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/hash" - "@ethersproject-xdc/hdnode" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/hdnode" - "@ethersproject-xdc/json-wallets" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/json-wallets" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/random" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/random" - "@ethersproject-xdc/signing-key" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/signing-key" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/transactions" - "@ethersproject-xdc/wordlists" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wallet-5.6.0-7e2abba1-0462-4d24-b419-158f0d508715-1686225288616/node_modules/@ethersproject-xdc/wordlists" + "@ethersproject-xdc/abstract-provider" "file:vendor/@ethersproject-xdc/abstract-provider" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/hash" "file:vendor/@ethersproject-xdc/hash" + "@ethersproject-xdc/hdnode" "file:vendor/@ethersproject-xdc/hdnode" + "@ethersproject-xdc/json-wallets" "file:vendor/@ethersproject-xdc/json-wallets" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/random" "file:vendor/@ethersproject-xdc/random" + "@ethersproject-xdc/signing-key" "file:vendor/@ethersproject-xdc/signing-key" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" + "@ethersproject-xdc/wordlists" "file:vendor/@ethersproject-xdc/wordlists" "@ethersproject-xdc/web@file:vendor/@ethersproject-xdc/web": version "5.7.1" dependencies: - "@ethersproject-xdc/base64" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-web-5.7.1-fb65e4ae-6b80-4541-91a8-be9683776f97-1686225288616/node_modules/@ethersproject-xdc/base64" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-web-5.7.1-fb65e4ae-6b80-4541-91a8-be9683776f97-1686225288616/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-web-5.7.1-fb65e4ae-6b80-4541-91a8-be9683776f97-1686225288616/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-web-5.7.1-fb65e4ae-6b80-4541-91a8-be9683776f97-1686225288616/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-web-5.7.1-fb65e4ae-6b80-4541-91a8-be9683776f97-1686225288616/node_modules/@ethersproject-xdc/strings" + "@ethersproject-xdc/base64" "file:vendor/@ethersproject-xdc/base64" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" "@ethersproject-xdc/wordlists@file:vendor/@ethersproject-xdc/wordlists": version "5.7.0" dependencies: - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wordlists-5.7.0-f12d668b-cde2-4092-9834-ea8b338a4446-1686225288614/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/hash" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wordlists-5.7.0-f12d668b-cde2-4092-9834-ea8b338a4446-1686225288614/node_modules/@ethersproject-xdc/hash" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wordlists-5.7.0-f12d668b-cde2-4092-9834-ea8b338a4446-1686225288614/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wordlists-5.7.0-f12d668b-cde2-4092-9834-ea8b338a4446-1686225288614/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-@ethersproject-xdc-wordlists-5.7.0-f12d668b-cde2-4092-9834-ea8b338a4446-1686225288614/node_modules/@ethersproject-xdc/strings" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/hash" "file:vendor/@ethersproject-xdc/hash" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.4.0", "@ethersproject/abi@^5.5.0", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.7.0": version "5.7.0" @@ -8695,36 +8695,36 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: "ethers-xdc@file:./vendor/ethers-xdc": version "5.7.2" dependencies: - "@ethersproject-xdc/abi" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/abi" - "@ethersproject-xdc/abstract-provider" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/abstract-provider" - "@ethersproject-xdc/abstract-signer" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/abstract-signer" - "@ethersproject-xdc/address" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/address" - "@ethersproject-xdc/base64" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/base64" - "@ethersproject-xdc/basex" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/basex" - "@ethersproject-xdc/bignumber" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/bignumber" - "@ethersproject-xdc/bytes" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/bytes" - "@ethersproject-xdc/constants" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/constants" - "@ethersproject-xdc/contracts" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/contracts" - "@ethersproject-xdc/hash" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/hash" - "@ethersproject-xdc/hdnode" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/hdnode" - "@ethersproject-xdc/json-wallets" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/json-wallets" - "@ethersproject-xdc/keccak256" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/keccak256" - "@ethersproject-xdc/logger" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/logger" - "@ethersproject-xdc/networks" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/networks" - "@ethersproject-xdc/pbkdf2" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/pbkdf2" - "@ethersproject-xdc/properties" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/properties" - "@ethersproject-xdc/providers" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/providers" - "@ethersproject-xdc/random" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/random" - "@ethersproject-xdc/rlp" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/rlp" - "@ethersproject-xdc/sha2" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/sha2" - "@ethersproject-xdc/signing-key" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/signing-key" - "@ethersproject-xdc/solidity" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/solidity" - "@ethersproject-xdc/strings" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/strings" - "@ethersproject-xdc/transactions" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/transactions" - "@ethersproject-xdc/units" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/units" - "@ethersproject-xdc/wallet" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/wallet" - "@ethersproject-xdc/web" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/web" - "@ethersproject-xdc/wordlists" "file:../../../../Library/Caches/Yarn/v6/npm-ethers-xdc-5.7.2-11e40edf-e947-4d7f-a15f-0d701ca269e6-1686225288593/node_modules/@ethersproject-xdc/wordlists" + "@ethersproject-xdc/abi" "file:vendor/@ethersproject-xdc/abi" + "@ethersproject-xdc/abstract-provider" "file:vendor/@ethersproject-xdc/abstract-provider" + "@ethersproject-xdc/abstract-signer" "file:vendor/@ethersproject-xdc/abstract-signer" + "@ethersproject-xdc/address" "file:vendor/@ethersproject-xdc/address" + "@ethersproject-xdc/base64" "file:vendor/@ethersproject-xdc/base64" + "@ethersproject-xdc/basex" "file:vendor/@ethersproject-xdc/basex" + "@ethersproject-xdc/bignumber" "file:vendor/@ethersproject-xdc/bignumber" + "@ethersproject-xdc/bytes" "file:vendor/@ethersproject-xdc/bytes" + "@ethersproject-xdc/constants" "file:vendor/@ethersproject-xdc/constants" + "@ethersproject-xdc/contracts" "file:vendor/@ethersproject-xdc/contracts" + "@ethersproject-xdc/hash" "file:vendor/@ethersproject-xdc/hash" + "@ethersproject-xdc/hdnode" "file:vendor/@ethersproject-xdc/hdnode" + "@ethersproject-xdc/json-wallets" "file:vendor/@ethersproject-xdc/json-wallets" + "@ethersproject-xdc/keccak256" "file:vendor/@ethersproject-xdc/keccak256" + "@ethersproject-xdc/logger" "file:vendor/@ethersproject-xdc/logger" + "@ethersproject-xdc/networks" "file:vendor/@ethersproject-xdc/networks" + "@ethersproject-xdc/pbkdf2" "file:vendor/@ethersproject-xdc/pbkdf2" + "@ethersproject-xdc/properties" "file:vendor/@ethersproject-xdc/properties" + "@ethersproject-xdc/providers" "file:vendor/@ethersproject-xdc/providers" + "@ethersproject-xdc/random" "file:vendor/@ethersproject-xdc/random" + "@ethersproject-xdc/rlp" "file:vendor/@ethersproject-xdc/rlp" + "@ethersproject-xdc/sha2" "file:vendor/@ethersproject-xdc/sha2" + "@ethersproject-xdc/signing-key" "file:vendor/@ethersproject-xdc/signing-key" + "@ethersproject-xdc/solidity" "file:vendor/@ethersproject-xdc/solidity" + "@ethersproject-xdc/strings" "file:vendor/@ethersproject-xdc/strings" + "@ethersproject-xdc/transactions" "file:vendor/@ethersproject-xdc/transactions" + "@ethersproject-xdc/units" "file:vendor/@ethersproject-xdc/units" + "@ethersproject-xdc/wallet" "file:vendor/@ethersproject-xdc/wallet" + "@ethersproject-xdc/web" "file:vendor/@ethersproject-xdc/web" + "@ethersproject-xdc/wordlists" "file:vendor/@ethersproject-xdc/wordlists" ethers@4.0.0-beta.3: version "4.0.0-beta.3" @@ -14906,9 +14906,9 @@ socket.io-client@^4.6.1: socket.io-parser "~4.2.1" socket.io-parser@~4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" - integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + version "4.2.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" From 82f1d438de7e9b65b395eeafa557dacc95171376 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Sun, 2 Jul 2023 09:31:43 -0700 Subject: [PATCH 04/17] (fix) change uniswap to default not to use route --- src/templates/uniswap.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/templates/uniswap.yml b/src/templates/uniswap.yml index c1f00b1487..cd00b82dc5 100644 --- a/src/templates/uniswap.yml +++ b/src/templates/uniswap.yml @@ -13,10 +13,10 @@ ttl: 600 # Note: More hops will increase latency of the algorithm. maximumHops: 4 -# Use Uniswap Router or Quoter for quoting prices. -# true - use Uniswap Router. -# false - use Uniswap Quoter. -useRouter: true +# Use Uniswap Router or Quoter to quote prices. +# true - use Smart Order Router +# false - use QuoterV2 Contract +useRouter: false # Fee tier to use for the Uniswap Quoter. # Required if `useRouter` is false. From 0ddfe2332798cad88aab0d28d58c2fc00c75f4ee Mon Sep 17 00:00:00 2001 From: vic-en Date: Wed, 5 Jul 2023 04:37:59 -0500 Subject: [PATCH 05/17] refactor chains --- docs/swagger/algorand-routes.yml | 73 --- .../{evm-routes.yml => chain-routes.yml} | 36 +- docs/swagger/cosmos-routes.yml | 57 --- docs/swagger/definitions.yml | 394 +-------------- docs/swagger/injective-routes.yml | 89 ---- docs/swagger/near-routes.yml | 63 --- docs/swagger/swagger.yml | 12 +- src/amm/amm.controllers.ts | 20 +- src/app.ts | 21 +- src/chains/algorand/algorand.controller.ts | 152 +++--- src/chains/algorand/algorand.routes.ts | 91 ---- src/chains/algorand/algorand.ts | 7 + src/chains/avalanche/avalanche.ts | 3 + .../binance-smart-chain.ts | 10 +- src/chains/chain.controller.ts | 156 ++++++ .../chain.requests.ts} | 0 src/chains/chain.routes.ts | 231 +++++++++ src/chains/cosmos/cosmos.controllers.ts | 107 ++-- src/chains/cosmos/cosmos.routes.ts | 74 --- src/chains/cosmos/cosmos.ts | 3 + src/chains/cronos/cronos.ts | 3 + src/chains/ethereum/ethereum-base.ts | 4 +- src/chains/ethereum/ethereum.controllers.ts | 456 ----------------- src/chains/ethereum/ethereum.requests.ts | 3 +- src/chains/ethereum/ethereum.ts | 5 +- src/chains/ethereum/evm.controllers.ts | 472 ++++++++++++++++++ src/{evm => chains/ethereum}/evm.nonce.ts | 8 +- .../ethereum}/evm.tx-storage.ts | 4 +- src/chains/harmony/harmony.ts | 3 + src/chains/injective/injective.controllers.ts | 76 +-- src/chains/injective/injective.requests.ts | 11 +- src/chains/injective/injective.routes.ts | 122 ----- src/chains/injective/injective.ts | 5 +- src/chains/injective/injective.validators.ts | 20 +- src/chains/near/near.base.ts | 2 +- src/chains/near/near.controllers.ts | 253 +++++----- src/chains/near/near.routes.ts | 87 ---- src/chains/near/near.ts | 3 + src/chains/polygon/polygon.ts | 3 + src/chains/xdc/xdc.base.ts | 4 +- src/chains/xdc/xdc.controllers.ts | 19 + src/evm/evm.routes.ts | 133 ----- src/network/network.controllers.ts | 49 +- src/network/network.routes.ts | 110 ---- src/services/base.ts | 6 +- src/services/common-interfaces.ts | 5 +- test-helpers/curl/curl.sh | 92 ++-- ...gon_key.json.json => add_polygon_key.json} | 0 .../curl/requests/eth_allowances.json | 4 +- test-helpers/curl/requests/eth_nonce.json | 4 +- .../requests/injective_transfer_to_bank.json | 3 +- .../requests/injective_transfer_to_sub.json | 3 +- .../ethereum/ethereum.controllers.test.ts | 34 +- test/chains/ethereum/evm.nonce.test.ts | 2 +- .../harmony/harmony.controllers.test.ts | 31 +- test/chains/near/near.controllers.test.ts | 24 +- test/evm.nonce.mock.ts | 2 +- test/services/evm.nonce.test.ts | 2 +- test/services/evm.tx-storage.test.ts | 2 +- 59 files changed, 1384 insertions(+), 2284 deletions(-) delete mode 100644 docs/swagger/algorand-routes.yml rename docs/swagger/{evm-routes.yml => chain-routes.yml} (81%) delete mode 100644 docs/swagger/cosmos-routes.yml delete mode 100644 docs/swagger/injective-routes.yml delete mode 100644 docs/swagger/near-routes.yml delete mode 100644 src/chains/algorand/algorand.routes.ts create mode 100644 src/chains/chain.controller.ts rename src/{evm/evm.requests.ts => chains/chain.requests.ts} (100%) create mode 100644 src/chains/chain.routes.ts delete mode 100644 src/chains/cosmos/cosmos.routes.ts delete mode 100644 src/chains/ethereum/ethereum.controllers.ts create mode 100644 src/chains/ethereum/evm.controllers.ts rename src/{evm => chains/ethereum}/evm.nonce.ts (98%) rename src/{evm => chains/ethereum}/evm.tx-storage.ts (92%) delete mode 100644 src/chains/injective/injective.routes.ts delete mode 100644 src/chains/near/near.routes.ts create mode 100644 src/chains/xdc/xdc.controllers.ts delete mode 100644 src/evm/evm.routes.ts delete mode 100644 src/network/network.routes.ts rename test-helpers/curl/requests/{add_polygon_key.json.json => add_polygon_key.json} (100%) diff --git a/docs/swagger/algorand-routes.yml b/docs/swagger/algorand-routes.yml deleted file mode 100644 index 3bd24e87f7..0000000000 --- a/docs/swagger/algorand-routes.yml +++ /dev/null @@ -1,73 +0,0 @@ -paths: - /algorand/poll: - post: - tags: - - 'algorand' - summary: 'Poll the status of a transaction' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/AlgorandPollRequest' - responses: - '200': - schema: - $ref: '#/definitions/AlgorandPollResponse' - /algorand/balances: - post: - tags: - - 'algorand' - summary: 'Get the balances of an account' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/BalancesRequest' - responses: - '200': - schema: - $ref: '#/definitions/BalancesResponse' - /algorand/assets: - get: - tags: - - 'algorand' - summary: 'Get assets info' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'query' - name: 'query' - required: true - schema: - $ref: '#/definitions/AlgorandAssetsRequest' - /algorand/opt-in: - post: - tags: - - 'algorand' - summary: 'Opt into an asset' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/AlgorandOptInRequest' - responses: - '200': - schema: - $ref: '#/definitions/AlgorandOptInResponse' \ No newline at end of file diff --git a/docs/swagger/evm-routes.yml b/docs/swagger/chain-routes.yml similarity index 81% rename from docs/swagger/evm-routes.yml rename to docs/swagger/chain-routes.yml index 6e7a292af2..cd706fc471 100644 --- a/docs/swagger/evm-routes.yml +++ b/docs/swagger/chain-routes.yml @@ -1,8 +1,8 @@ paths: - /evm/nonce: + /chain/nonce: post: tags: - - 'evm' + - 'chain' summary: 'Get the current nonce for the provided private key' operationId: 'nonce' consumes: @@ -20,10 +20,10 @@ paths: schema: $ref: '#/definitions/NonceResponse' - /evm/nextNonce: + /chain/nextNonce: post: tags: - - 'evm' + - 'chain' summary: 'Get the next nonce for the provided private key' operationId: 'nonce' consumes: @@ -41,10 +41,10 @@ paths: schema: $ref: '#/definitions/NonceResponse' - /evm/allowances: + /chain/allowances: post: tags: - - 'evm' + - 'chain' summary: 'Get the ERC20 allowances for a spender on a given private key' operationId: 'allowances' consumes: @@ -61,10 +61,10 @@ paths: '200': schema: $ref: '#/definitions/AllowancesResponse' - /evm/approve: + /chain/approve: post: tags: - - 'evm' + - 'chain' summary: 'Create an ERC20 approval for a spender on an private key' operationId: 'approve' consumes: @@ -82,10 +82,10 @@ paths: schema: $ref: '#/definitions/ApproveResponse' - /evm/cancel: + /chain/cancel: post: tags: - - 'evm' + - 'chain' summary: 'Cancel transaction' operationId: 'cancel' consumes: @@ -102,3 +102,19 @@ paths: '200': schema: $ref: '#/definitions/CancelResponse' + + /chain/transfer: + post: + tags: + - 'chain' + summary: 'Transfer balance' + parameters: + - in: 'body' + name: 'body' + required: true + schema: + $ref: '#/definitions/TransferRequest' + produces: + - 'application/json' + responses: + '200' diff --git a/docs/swagger/cosmos-routes.yml b/docs/swagger/cosmos-routes.yml deleted file mode 100644 index 38d44d4f28..0000000000 --- a/docs/swagger/cosmos-routes.yml +++ /dev/null @@ -1,57 +0,0 @@ -paths: - /cosmos: - get: - tags: - - 'cosmos' - summary: 'View the Cosmos network and RPC URL that gateway is configured to use' - description: 'The user can change this by editing src/chains/cosmos/cosmos.config.ts' - operationId: 'root' - produces: - - 'application/json' - responses: - '200': - description: 'Cosmos config' - schema: - $ref: '#/definitions/CosmosConfigResponse' - - /cosmos/balances: - post: - tags: - - 'cosmos' - summary: 'Get the balances of a Cosmos wallet' - operationId: 'balances' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/CosmosBalanceRequest' - responses: - '200': - schema: - $ref: '#/definitions/BalancesResponse' - - /cosmos/poll: - post: - tags: - - 'cosmos' - summary: 'Poll the status of a Cosmos transaction' - operationId: 'poll' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/CosmosPollRequest' - responses: - '200': - schema: - $ref: '#/definitions/CosmosPollResponse' diff --git a/docs/swagger/definitions.yml b/docs/swagger/definitions.yml index 0763752f16..7c231e9813 100644 --- a/docs/swagger/definitions.yml +++ b/docs/swagger/definitions.yml @@ -154,70 +154,6 @@ definitions: type: 'string' example: '{"ETH": "1.5", "WETH": "100","DAI": "300"}' - InjectiveBankBalance: - type: 'object' - required: - - 'token' - - 'amount' - properties: - token: - type: 'string' - example: 'inj' - amount: - type: 'string' - example: '1.25' - - InjectiveSubaccountBalanceSub: - type: 'object' - required: - - 'token' - - 'totalBalance' - - 'availableBalance' - properties: - token: - type: 'string' - example: 'inj' - totalBalance: - type: 'string' - example: '100.0' - availableBalance: - type: 'string' - example: '15.0' - - InjectiveSubaccountBalancesWithId: - type: 'object' - required: - - 'subaccountId' - - 'balances' - properties: - subaccountId: - type: 'string' - example: '0' - balances: - type: 'array' - item: - $ref: '#/definitions/InjectiveSubaccountBalanceSub' - example: '{"token": "inj", "tokenBalance": "100.0", "availableBalance": "15.0"}' - - InjectiveBalancesResponse: - type: 'object' - required: - - 'injectiveAddress' - - 'balances' - - 'subaccounts' - properties: - injectiveAddress: - type: 'string' - example: 'inj1l2sjl5gzl6rz8jffn3etq0j9zpljwu44ed7zuc' - balances: - type: 'array' - item: - $ref: '#/definitions/InjectiveBankBalance' - subaccoutns: - type: 'array' - item: - $ref: '#/definitions/InjectiveSubaccountBalancesWithId' - ApproveRequest: type: 'object' required: @@ -292,53 +228,6 @@ definitions: type: 'object' example: '{"type": 2,"chainId": 42,"nonce": 129,"maxPriorityFeePerGas": "94000000000","maxFeePerGas": "94000000000","gasPrice": null,"gasLimit": "100000","to": "0xd0A1E359811322d97991E03f863a0C30C2cF029C","value": "0","data": "0x095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","accessList": [],"hash": "0xa321bbe8888c3bc88ecb1ad4f03f22a71e6f5715dfcb19e0a2dca9036c981b6d","v": 1,"r": "0x47c517271885b7041d81bcd65cd050a5d6be3fbd67a8f1660ac8d7e68fc8221f","s": "0x7c62e114b2cb0eae6236b597fb4aacb01c51e56afd7f734e6039d83aa400ba82","from": "0xFaA12FD102FE8623C9299c72B03E45107F2772B5","confirmations": 0}' # noqa: documentation - InjectivePollResponse: - type: 'object' - required: - - 'blockNumber' - - 'hash' - - 'gasWanted' - - 'gasLimit' - - 'gasUsed' - - 'sequences' - properties: - blockNumber: - type: 'number' - example: 123456 - hash: - type: 'string' - example: '0xaaaaaaaaaabbbb' - gasWanted: - type: 'number' - example: 1000000 - gasLimit: - type: 'number' - example: 2000000 - gasUsed: - type: 'number' - example: 1000000 - sequences: - type: 'array' - items: 'number' - example: [ 1,2 ] - - InjectivePollRequest: - type: 'object' - required: - - 'txHash' - - 'chain' - - 'network' - properties: - txHash: - type: 'string' - example: '0xa321bbe8888c3bc88ecb1ad4f03f22a71e6f5715dfcb19e0a2dca9036c981b6d' # noqa: documentation - chain: - type: 'string' - example: 'injective' - network: - type: 'string' - example: 'mainnet' - PollRequest: type: 'object' required: @@ -711,86 +600,6 @@ definitions: - type: 'boolean' - type: 'number' - CosmosConfigResponse: - type: 'object' - required: - - 'network' - - 'rpcUrl' - - 'connection' - - 'timestamp' - properties: - network: - type: 'string' - example: 'mainnet' - rpcUrl: - type: 'string' - example: 'https://rpc.cosmos.network/' - connection: - type: 'boolean' - example: true - timestamp: - type: 'integer' - example: 1641889489132 - - CosmosBalanceRequest: - type: 'object' - required: - - 'address' - - 'tokenSymbols' - properties: - address: - type: 'string' - example: 'cosmos1pc8m5m7n0z8xe7sx2tawkvc0v6qkjql83js0dr' - tokenSymbols: - type: 'array' - items: 'string' - example: [ 'ATOM', 'NETA' ] - - CosmosPollRequest: - type: 'object' - required: - - 'txHash' - properties: - txHash: - type: 'string' - example: 'E0E02A6C27A75F4442B0746676BDAF5F66AFF1E71928C54624A35B48D5A4B3AF' - - CosmosPollResponse: - type: 'object' - required: - - 'network' - - 'timestamp' - - 'txHash' - - 'currentBlock' - - 'txBlock' - - 'gasUsed' - - 'gasWanted' - - 'txData' - properties: - network: - type: 'string' - example: 'mainnet' - timestamp: - type: 'integer' - example: 1636368085740 - currentBlock: - type: 'integer' - example: 112646487 - txHash: - type: 'string' - example: 'oaMWkrYr1g9JBcDUPRqz21cJBxowM4CEbDy2FsCgNK569CjZSr4wa51d4k9DpTRJU8GUHfp3e9YX2pGXaBS5Tta' - txBlock: - type: 'number' - example: 11581899 - gasUsed: - type: 'number' - example: 89054 - gasWanted: - type: 'number' - example: 130000 - txData: - $ref: '#/definitions/CosmosTransaction' - TokensResponse: type: 'object' required: @@ -2055,12 +1864,13 @@ definitions: type: 'array' example: [] - TransferToSubAccountRequest: + TransferRequest: type: 'object' required: - 'chain' - 'network' - - 'address' + - 'from' + - 'to' - 'subaccountId' - 'amount' - 'token' @@ -2071,7 +1881,10 @@ definitions: network: type: 'string' example: 'mainnet' - address: + from: + type: 'string' + example: '0x...' + to: type: 'string' example: '0x...' amount: @@ -2081,103 +1894,6 @@ definitions: type: 'string' example: 'inj' - NearBalancesRequest: - type: 'object' - required: - - 'address' - - 'tokenSymbols' - - 'chain' - - 'network' - properties: - privateKey: - type: 'string' - example: 'hummingbot.near' - tokenSymbols: - type: 'array' - items: 'string' - example: [ "NEAR", "ETH", "AURORA" ] - chain: - type: 'string' - example: 'near' - network: - type: 'string' - example: 'testnet' - - NearBalancesResponse: - type: 'object' - required: - - 'network' - - 'timestamp' - - 'latency' - - 'balances' - properties: - network: - type: 'string' - example: 'testnet' - timestamp: - type: 'integer' - example: 1636368085740 - latency: - type: 'number' - example: 0.5 - balances: - type: 'object' - properties: - id: - type: 'string' - name: - type: 'string' - example: '{"NEAR": "1.5", "ETH": "100", "AURORA": "300"}' - - NearPollRequest: - type: 'object' - required: - - 'address' - - 'txHash' - - 'chain' - - 'network' - properties: - address: - type: 'string' - example: 'hummingbot.near' - txHash: - type: 'string' - example: 'HnpRwb8PjrtLjExxz4YxdiyJ2AwuRFhZHKa9WUASwyxk' - chain: - type: 'string' - example: 'near' - network: - type: 'string' - example: 'testnet' - - NearPollResponse: - type: 'object' - required: - - 'network' - - 'timestamp' - - 'currentBlock' - - 'txHash' - - 'txStatus' - - 'txReceipt' - properties: - network: - type: 'string' - example: 'testnet' - timestamp: - type: 'integer' - example: 1636368085740 - currentBlock: - type: 'integer' - example: 28243911 - txHash: - type: 'string' - example: 'HnpRwb8PjrtLjExxz4YxdiyJ2AwuRFhZHKa9WUASwyxk' - txStatus: - type: 'number' - example: 1 - txReceipt: - type: 'object' - PerpClobPostOrderRequest: type: 'object' required: @@ -2323,102 +2039,6 @@ definitions: type: 'string' example: '1.234' - AlgorandPollRequest: - type: 'object' - required: - - 'network' - - 'txHash' - properties: - network: - type: 'string' - example: 'testnet' - txHash: - type: 'string' - example: 'T3ZUYEJ5Y7KEDKITIXO4B5OWU4SBVGOFCPOYGZQHF2XZGENZUBQA' - - AlgorandPollResponse: - type: 'object' - required: - - 'currentBlock' - - 'txBlock' - - 'txHash' - - 'fee' - properties: - currentBlock: - type: 'integer' - example: 28243911 - txBlock: - type: 'integer' - example: 28243910 - txHash: - type: 'string' - example: 'T3ZUYEJ5Y7KEDKITIXO4B5OWU4SBVGOFCPOYGZQHF2XZGENZUBQA' - fee: - type: 'integer' - example: 1000 - - AlgorandAssetsRequest: - type: 'object' - properties: - network: - type: 'string' - example: 'testnet' - assetSymbols: - type: 'array' - items: 'string' - example: [ 'ALGO', 'USDC' ] - - AlgorandAssetsResponse: - type: 'object' - required: - - 'assets' - properties: - assets: - type: 'array' - items: 'object' - example: [ { symbol: 'ALGO', assetId: 0, decimal: 6 } ] - - AlgorandOptInRequest: - type: 'object' - required: - - 'network' - - 'address' - - 'assetSymbol' - properties: - network: - type: 'string' - example: 'testnet' - address: - type: 'string' - example: 'T3ZUYEJ5Y7KEDKITIXO4B5OWU4SBVGOFCPOYGZQHF2XZGENZUBQA' - assetSymbol: - type: 'string' - example: 'USDC' - - AlgorandOptInResponse: - type: 'object' - required: - - 'network' - - 'timestamp' - - 'latency' - - 'assetId' - - 'transactionResponse' - properties: - network: - type: 'string' - example: 'testnet' - timestamp: - type: 'integer' - example: 163636808574 - latency: - type: 'number' - example: 0.5 - assetId: - type: 'string' - example: 'USDC' - transactionResponse: - type: 'object' - ClobBatchOrdersRequest: type: 'object' required: diff --git a/docs/swagger/injective-routes.yml b/docs/swagger/injective-routes.yml deleted file mode 100644 index 557226ee61..0000000000 --- a/docs/swagger/injective-routes.yml +++ /dev/null @@ -1,89 +0,0 @@ -paths: - /injective/balances: - post: - tags: - - 'injective' - summary: 'Get the balances of an injective public key' - operationId: 'balances' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/BalancesRequest' - responses: - '200': - schema: - $ref: '#/definitions/InjectiveBalancesResponse' - - /injective/block/current: - post: - tags: - - 'injective' - summary: 'Get the current block number for an injective network' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/NetworkSelectionRequest' - produces: - - 'application/json' - responses: - '200' - - /injective/poll: - post: - tags: - - 'injective' - summary: 'Poll the status of a transaction' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/InjectivePollRequest' - responses: - '200': - schema: - $ref: '#/definitions/InjectivePollResponse' - - /injective/transfer/to/bank: - post: - tags: - - 'injective' - summary: 'Transfer subaccount balance to bank' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/TransferToSubAccountRequest' - produces: - - 'application/json' - responses: - '200' - - /injective/transfer/to/sub: - post: - tags: - - 'injective' - summary: 'Transfer bank balance to subaccount balance' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/TransferToSubAccountRequest' - produces: - - 'application/json' - responses: - '200' \ No newline at end of file diff --git a/docs/swagger/near-routes.yml b/docs/swagger/near-routes.yml deleted file mode 100644 index cafdd30f30..0000000000 --- a/docs/swagger/near-routes.yml +++ /dev/null @@ -1,63 +0,0 @@ -paths: - /near/balances: - get: - tags: - - 'near' - summary: 'Get the balances of an Near private key' - operationId: 'near.balances' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/NearBalancesRequest' - responses: - '200': - schema: - $ref: '#/definitions/NearBalancesResponse' - - /near/tokens: - get: - tags: - - 'near' - summary: 'Request token information and balance of requested token symbol' - operationId: 'near.token' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/NetworkSelectionRequest' - responses: - '200': - schema: - $ref: '#/definitions/TokensResponse' - - /near/poll: - post: - tags: - - 'near' - summary: 'Poll the status of a Near transaction' - operationId: 'near.poll' - consumes: - - 'application/json' - produces: - - 'application/json' - parameters: - - in: 'body' - name: 'body' - required: true - schema: - $ref: '#/definitions/NearPollRequest' - responses: - '200': - schema: - $ref: '#/definitions/NearPollResponse' diff --git a/docs/swagger/swagger.yml b/docs/swagger/swagger.yml index 5fc6f46c12..bef77055aa 100644 --- a/docs/swagger/swagger.yml +++ b/docs/swagger/swagger.yml @@ -27,16 +27,8 @@ tags: description: 'Interact with CLOB perpetual decentralized exchanges' - name: 'amm/liquidity' description: 'Interact with AMM LP contracts' - - name: 'evm' - description: 'Interact with EVM based blockchains' - - name: 'algorand' - description: 'Interact with the Algorand blockchain' - - name: 'cosmos' - description: 'Interact with the Cosmos blockchain' - - name: 'near' - description: 'Interact with the Near blockchain' - - name: 'injective' - description: 'Interact with the Injective blockchain' + - name: 'chain' + description: 'Interact with primary chain properties' schemes: - 'http' diff --git a/src/amm/amm.controllers.ts b/src/amm/amm.controllers.ts index 76c1a8e3d4..74f3d927ab 100644 --- a/src/amm/amm.controllers.ts +++ b/src/amm/amm.controllers.ts @@ -58,7 +58,7 @@ import { getConnector, } from '../services/connection-manager'; import { - Ethereumish, + Chain as Ethereumish, Nearish, NetworkSelectionRequest, Perpish, @@ -79,9 +79,12 @@ export async function price(req: PriceRequest): Promise { req.chain, req.network ); - const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish= await getConnector< - Uniswapish | RefAMMish | Tinyman | ZigZagish - >(req.chain, req.network, req.connector); + const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish = + await getConnector( + req.chain, + req.network, + req.connector + ); // we currently use the presence of routerAbi to distinguish Uniswapish from RefAMMish if ('routerAbi' in connector) { @@ -100,9 +103,12 @@ export async function trade(req: TradeRequest): Promise { req.chain, req.network ); - const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish = await getConnector< - Uniswapish | RefAMMish | Tinyman | ZigZagish - >(req.chain, req.network, req.connector); + const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish = + await getConnector( + req.chain, + req.network, + req.connector + ); // we currently use the presence of routerAbi to distinguish Uniswapish from RefAMMish if ('routerAbi' in connector) { diff --git a/src/app.ts b/src/app.ts index 286244c103..8e6af2bf72 100644 --- a/src/app.ts +++ b/src/app.ts @@ -2,7 +2,6 @@ import express from 'express'; import { Request, Response, NextFunction } from 'express'; import { ConfigRoutes } from './services/config/config.routes'; -import { CosmosRoutes } from './chains/cosmos/cosmos.routes'; import { WalletRoutes } from './services/wallet/wallet.routes'; import { logger } from './services/logger'; import { addHttps } from './https'; @@ -14,17 +13,13 @@ import { } from './services/error-handler'; import { ConfigManagerV2 } from './services/config-manager-v2'; import { SwaggerManager } from './services/swagger-manager'; -import { NetworkRoutes } from './network/network.routes'; import { ConnectorsRoutes } from './connectors/connectors.routes'; -import { EVMRoutes } from './evm/evm.routes'; import { AmmRoutes, AmmLiquidityRoutes, PerpAmmRoutes } from './amm/amm.routes'; -import { AlgorandRoutes } from './chains/algorand/algorand.routes'; -import { InjectiveRoutes } from './chains/injective/injective.routes'; -import { NearRoutes } from './chains/near/near.routes'; import { CLOBRoutes, PerpClobRoutes } from './clob/clob.routes'; import morgan from 'morgan'; import swaggerUi from 'swagger-ui-express'; +import { ChainRoutes } from './chains/chain.routes'; export const gatewayApp = express(); @@ -48,10 +43,7 @@ gatewayApp.use( // mount sub routers gatewayApp.use('/config', ConfigRoutes.router); -gatewayApp.use('/network', NetworkRoutes.router); -gatewayApp.use('/evm', EVMRoutes.router); -gatewayApp.use('/algorand', AlgorandRoutes.router); -gatewayApp.use('/injective', InjectiveRoutes.router); +gatewayApp.use('/chain', ChainRoutes.router); gatewayApp.use('/connectors', ConnectorsRoutes.router); gatewayApp.use('/amm', AmmRoutes.router); @@ -60,8 +52,6 @@ gatewayApp.use('/amm/liquidity', AmmLiquidityRoutes.router); gatewayApp.use('/wallet', WalletRoutes.router); gatewayApp.use('/clob', CLOBRoutes.router); gatewayApp.use('/clob/perp', PerpClobRoutes.router); -gatewayApp.use('/cosmos', CosmosRoutes.router); -gatewayApp.use('/near', NearRoutes.router); // a simple route to test that the server is running gatewayApp.get('/', (_req: Request, res: Response) => { @@ -103,12 +93,7 @@ export const swaggerDocument = SwaggerManager.generateSwaggerJson( './docs/swagger/wallet-routes.yml', './docs/swagger/amm-routes.yml', './docs/swagger/amm-liquidity-routes.yml', - './docs/swagger/evm-routes.yml', - './docs/swagger/network-routes.yml', - './docs/swagger/algorand-routes.yml', - './docs/swagger/near-routes.yml', - './docs/swagger/cosmos-routes.yml', - './docs/swagger/injective-routes.yml', + './docs/swagger/chain-routes.yml', ] ); diff --git a/src/chains/algorand/algorand.controller.ts b/src/chains/algorand/algorand.controller.ts index 8e60686c7f..877136d5fa 100644 --- a/src/chains/algorand/algorand.controller.ts +++ b/src/chains/algorand/algorand.controller.ts @@ -3,22 +3,22 @@ import { AssetsRequest, AssetsResponse, OptInRequest, - OptInResponse, PollRequest, PollResponse, } from '../algorand/algorand.requests'; import { Algorand } from './algorand'; -import { - BalanceRequest, - BalanceResponse, -} from '../../network/network.requests'; -import { latency } from '../../services/base'; +import { BalanceRequest } from '../../network/network.requests'; import { HttpException, - NETWORK_ERROR_CODE, TOKEN_NOT_SUPPORTED_ERROR_CODE, TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, } from '../../services/error-handler'; +import { + validateAlgorandBalanceRequest, + validateAlgorandPollRequest, + validateAssetsRequest, + validateOptInRequest, +} from './algorand.validators'; async function getInitializedAlgorand(network: string): Promise { const algorand = Algorand.getInstance(network); @@ -30,96 +30,86 @@ async function getInitializedAlgorand(network: string): Promise { return algorand; } -export async function poll( - algorand: Algorand, - req: PollRequest -): Promise { - return await algorand.getTransaction(req.txHash); -} +export class AlgorandController { + static async poll( + algorand: Algorand, + req: PollRequest + ): Promise { + validateAlgorandPollRequest(req); -export async function balances( - chain: Algorand, - request: BalanceRequest -): Promise { - const initTime = Date.now(); - const balances: Record = {}; + return await algorand.getTransaction(req.txHash); + } - const account = await chain.getAccountFromAddress(request.address); + static async balances(chain: Algorand, request: BalanceRequest) { + validateAlgorandBalanceRequest(request); - if (request.tokenSymbols.includes(chain.nativeTokenSymbol)) { - balances[chain.nativeTokenSymbol] = await chain.getNativeBalance(account); - } + const balances: Record = {}; - for (const token of request.tokenSymbols) { - if (token === chain.nativeTokenSymbol) continue; - balances[token] = await chain.getAssetBalance(account, token); - } + const account = await chain.getAccountFromAddress(request.address); - return { - network: request.network, - timestamp: initTime, - latency: latency(initTime, Date.now()), - balances: balances, - }; -} + if (request.tokenSymbols.includes(chain.nativeTokenSymbol)) { + balances[chain.nativeTokenSymbol] = await chain.getNativeBalance(account); + } -export async function getAssets( - request: AssetsRequest -): Promise { - if (request.network === undefined) { - throw new HttpException( - 500, - 'Missing network parameter', - NETWORK_ERROR_CODE - ); + for (const token of request.tokenSymbols) { + if (token === chain.nativeTokenSymbol) continue; + balances[token] = await chain.getAssetBalance(account, token); + } + + return { + balances: balances, + }; } - let assets: AlgorandAsset[] = []; - const algorand = await getInitializedAlgorand(request.network); + static async getTokens( + algorand: Algorand, + request: AssetsRequest + ): Promise { + validateAssetsRequest(request); + + let assets: AlgorandAsset[] = []; - if (!request.assetSymbols) { - assets = algorand.storedAssetList; - } else { - let assetSymbols; - if (typeof request.assetSymbols === 'string') { - assetSymbols = [request.assetSymbols]; + if (!request.assetSymbols) { + assets = algorand.storedAssetList; } else { - assetSymbols = request.assetSymbols; - } - for (const a of assetSymbols as []) { - assets.push(algorand.getAssetForSymbol(a) as AlgorandAsset); + let assetSymbols; + if (typeof request.assetSymbols === 'string') { + assetSymbols = [request.assetSymbols]; + } else { + assetSymbols = request.assetSymbols; + } + for (const a of assetSymbols as []) { + assets.push(algorand.getAssetForSymbol(a) as AlgorandAsset); + } } + + return { + assets: assets, + }; } - return { - assets: assets, - }; -} + static async approve(request: OptInRequest) { + validateOptInRequest(request); -export async function optIn(request: OptInRequest): Promise { - const initTime = Date.now(); + const algorand = await getInitializedAlgorand(request.network); + const asset = algorand.getAssetForSymbol(request.assetSymbol); - const algorand = await getInitializedAlgorand(request.network); - const asset = algorand.getAssetForSymbol(request.assetSymbol); + if (asset === undefined) { + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + request.assetSymbol, + TOKEN_NOT_SUPPORTED_ERROR_CODE + ); + } - if (asset === undefined) { - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + request.assetSymbol, - TOKEN_NOT_SUPPORTED_ERROR_CODE + const transactionResponse = await algorand.optIn( + request.address, + request.assetSymbol ); - } - const transactionResponse = await algorand.optIn( - request.address, - request.assetSymbol - ); - - return { - network: request.network, - timestamp: initTime, - latency: latency(initTime, Date.now()), - assetId: (asset as AlgorandAsset).assetId, - transactionResponse: transactionResponse, - }; + return { + assetId: (asset as AlgorandAsset).assetId, + transactionResponse: transactionResponse, + }; + } } diff --git a/src/chains/algorand/algorand.routes.ts b/src/chains/algorand/algorand.routes.ts deleted file mode 100644 index 365d3c831d..0000000000 --- a/src/chains/algorand/algorand.routes.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* eslint-disable no-inner-declarations */ -/* eslint-disable @typescript-eslint/ban-types */ -import { Response, Router, Request, NextFunction } from 'express'; -import { asyncHandler } from '../../services/error-handler'; -import { - AssetsRequest, - AssetsResponse, - PollRequest, - PollResponse, - OptInRequest, - OptInResponse, -} from './algorand.requests'; -import { - validateAlgorandBalanceRequest, - validateAlgorandPollRequest, - validateAssetsRequest, - validateOptInRequest, -} from './algorand.validators'; -import { getInitializedChain } from '../../services/connection-manager'; -import { Algorand } from './algorand'; -import { balances, getAssets, optIn, poll } from './algorand.controller'; -import { - BalanceRequest, - BalanceResponse, -} from '../../network/network.requests'; - -export namespace AlgorandRoutes { - export const router = Router(); - - router.post( - '/poll', - asyncHandler( - async ( - req: Request<{}, {}, PollRequest>, - res: Response - ) => { - validateAlgorandPollRequest(req.body); - const algorand = await getInitializedChain( - 'algorand', - req.body.network - ); - res.status(200).json(await poll(algorand, req.body)); - } - ) - ); - - router.post( - '/balances', - asyncHandler( - async ( - req: Request<{}, {}, BalanceRequest>, - res: Response, - _next: NextFunction - ) => { - validateAlgorandBalanceRequest(req.body); - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - - res.status(200).json(await balances(chain, req.body)); - } - ) - ); - - router.get( - '/assets', - asyncHandler( - async ( - req: Request<{}, {}, {}, AssetsRequest>, - res: Response - ) => { - validateAssetsRequest(req.query); - res.status(200).json(await getAssets(req.query)); - } - ) - ); - - router.post( - '/opt-in', - asyncHandler( - async ( - req: Request<{}, {}, OptInRequest>, - res: Response - ) => { - validateOptInRequest(req.body); - res.status(200).json(await optIn(req.body)); - } - ) - ); -} diff --git a/src/chains/algorand/algorand.ts b/src/chains/algorand/algorand.ts index b1ce86ffce..62f22bb2d9 100644 --- a/src/chains/algorand/algorand.ts +++ b/src/chains/algorand/algorand.ts @@ -14,6 +14,7 @@ import fse from 'fs-extra'; import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase'; import axios from 'axios'; import { promises as fs } from 'fs'; +import { AlgorandController } from './algorand.controller'; type AssetListType = TokenListType; @@ -31,6 +32,7 @@ export class Algorand { public gasPrice: number; public gasLimit: number; public gasCost: number; + public controller: typeof AlgorandController; constructor( network: string, @@ -49,6 +51,7 @@ export class Algorand { this.gasPrice = 0; this.gasLimit = 0; this.gasCost = 0.001; + this.controller = AlgorandController; } public get algod(): Algodv2 { @@ -290,4 +293,8 @@ export class Algorand { } return assetData; } + + public get storedTokenList() { + return this._assetMap; + } } diff --git a/src/chains/avalanche/avalanche.ts b/src/chains/avalanche/avalanche.ts index 92df9da9bc..6c5da3644b 100644 --- a/src/chains/avalanche/avalanche.ts +++ b/src/chains/avalanche/avalanche.ts @@ -10,6 +10,7 @@ import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; import { Ethereumish } from '../../services/common-interfaces'; import { SushiswapConfig } from '../../connectors/sushiswap/sushiswap.config'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; +import { EVMController } from '../ethereum/evm.controllers'; export class Avalanche extends EthereumBase implements Ethereumish { private static _instances: { [name: string]: Avalanche }; @@ -17,6 +18,7 @@ export class Avalanche extends EthereumBase implements Ethereumish { private _gasPriceRefreshInterval: number | null; private _nativeTokenSymbol: string; private _chain: string; + public controller; private constructor(network: string) { const config = getAvalancheConfig('avalanche', network); @@ -42,6 +44,7 @@ export class Avalanche extends EthereumBase implements Ethereumish { : null; this.updateGasPrice(); + this.controller = EVMController; } public static getInstance(network: string): Avalanche { diff --git a/src/chains/binance-smart-chain/binance-smart-chain.ts b/src/chains/binance-smart-chain/binance-smart-chain.ts index 6c11a744b4..e04dbbe313 100644 --- a/src/chains/binance-smart-chain/binance-smart-chain.ts +++ b/src/chains/binance-smart-chain/binance-smart-chain.ts @@ -4,11 +4,12 @@ import { Contract, Transaction, Wallet } from 'ethers'; import { EthereumBase } from '../ethereum/ethereum-base'; import { getEthereumConfig as getBinanceSmartChainConfig } from '../ethereum/ethereum.config'; import { Provider } from '@ethersproject/abstract-provider'; -import { Ethereumish } from '../../services/common-interfaces'; +import { Chain as Ethereumish } from '../../services/common-interfaces'; import { PancakeSwapConfig } from '../../connectors/pancakeswap/pancakeswap.config'; import { SushiswapConfig } from '../../connectors/sushiswap/sushiswap.config'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; +import { EVMController } from '../ethereum/evm.controllers'; export class BinanceSmartChain extends EthereumBase implements Ethereumish { private static _instances: { [name: string]: BinanceSmartChain }; @@ -16,6 +17,7 @@ export class BinanceSmartChain extends EthereumBase implements Ethereumish { private _gasPrice: number; private _gasPriceRefreshInterval: number | null; private _nativeTokenSymbol: string; + public controller; private constructor(network: string) { const config = getBinanceSmartChainConfig('binance-smart-chain', network); @@ -39,6 +41,7 @@ export class BinanceSmartChain extends EthereumBase implements Ethereumish { : null; this.updateGasPrice(); + this.controller = EVMController; } public static getInstance(network: string): BinanceSmartChain { @@ -102,7 +105,10 @@ export class BinanceSmartChain extends EthereumBase implements Ethereumish { this._chain ); } else if (reqSpender === 'openocean') { - spender = OpenoceanConfig.config.routerAddress('binance-smart-chain', this._chain); + spender = OpenoceanConfig.config.routerAddress( + 'binance-smart-chain', + this._chain + ); } else { spender = reqSpender; } diff --git a/src/chains/chain.controller.ts b/src/chains/chain.controller.ts new file mode 100644 index 0000000000..58f8f4d8b7 --- /dev/null +++ b/src/chains/chain.controller.ts @@ -0,0 +1,156 @@ +import { latency } from '../services/base'; + +import { Chain } from '../services/common-interfaces'; +import { + BalanceRequest, + BalanceResponse, + PollRequest, + PollResponse, + TokensRequest, + TokensResponse, +} from '../network/network.requests'; +import { + NonceRequest, + NonceResponse, + AllowancesRequest, + AllowancesResponse, + ApproveRequest, + ApproveResponse, + CancelRequest, + CancelResponse, +} from './chain.requests'; +import { + TransferRequest, + TransferResponse, +} from './injective/injective.requests'; + +export async function poll( + chain: Chain, + req: PollRequest +): Promise { + const initTime = Date.now(); + const poll = await chain.controller.poll(chain, req); + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...poll, + }; +} + +export async function nonce( + chain: Chain, + req: NonceRequest +): Promise { + const initTime = Date.now(); + const nonce = await chain.controller.nonce(chain, req); + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...nonce, + }; +} + +export async function nextNonce( + chain: Chain, + req: NonceRequest +): Promise { + const initTime = Date.now(); + const nextNonce = await chain.controller.nextNonce(chain, req); + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...nextNonce, + }; +} + +export async function getTokens( + chain: Chain, + req: TokensRequest +): Promise { + const initTime = Date.now(); + const tokens = await chain.controller.getTokens(chain, req); + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...tokens, + }; +} + +export async function allowances( + chain: Chain, + req: AllowancesRequest +): Promise { + const initTime = Date.now(); + const allowances = await chain.controller.allowances(chain, req); + + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...allowances, + }; +} + +export async function balances( + chain: Chain, + req: BalanceRequest +): Promise { + const initTime = Date.now(); + const balances = await chain.controller.balances(chain, req); + + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...balances, + }; +} + +export async function approve( + chain: Chain, + req: ApproveRequest +): Promise { + const initTime = Date.now(); + const approveTx = await chain.controller.approve(chain, req); + + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...approveTx, + }; +} + +export async function cancel( + chain: Chain, + req: CancelRequest +): Promise { + const initTime = Date.now(); + const cancelTx = await chain.controller.cancel(chain, req); + + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...cancelTx, + }; +} + +export async function transfer( + chain: Chain, + req: TransferRequest +): Promise { + const initTime = Date.now(); + const transfer = await chain.controller.transfer(chain, req); + + return { + network: chain.chain, + timestamp: initTime, + latency: latency(initTime, Date.now()), + ...transfer, + }; +} diff --git a/src/evm/evm.requests.ts b/src/chains/chain.requests.ts similarity index 100% rename from src/evm/evm.requests.ts rename to src/chains/chain.requests.ts diff --git a/src/chains/chain.routes.ts b/src/chains/chain.routes.ts new file mode 100644 index 0000000000..9488c9050a --- /dev/null +++ b/src/chains/chain.routes.ts @@ -0,0 +1,231 @@ +/* eslint-disable no-inner-declarations */ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable @typescript-eslint/ban-types */ +import { NextFunction, Request, Response, Router } from 'express'; +import { Chain } from '../services/common-interfaces'; +import { ConfigManagerV2 } from '../services/config-manager-v2'; +import { asyncHandler } from '../services/error-handler'; +import { + mkRequestValidator, + RequestValidator, + validateTxHash, +} from '../services/validators'; +import { + validateChain as validateEthereumChain, + validateNetwork as validateEthereumNetwork, +} from '../chains/ethereum/ethereum.validators'; +import { validateNonceRequest } from './ethereum/ethereum.validators'; + +import { getInitializedChain } from '../services/connection-manager'; +import { + AllowancesRequest, + AllowancesResponse, + ApproveRequest, + ApproveResponse, + CancelRequest, + CancelResponse, + NonceRequest, + NonceResponse, +} from './chain.requests'; +import { getStatus } from '../network/network.controllers'; +import { + StatusRequest, + StatusResponse, + BalanceRequest, + BalanceResponse, + PollRequest, + PollResponse, + TokensRequest, + TokensResponse, +} from '../network/network.requests'; +import { + allowances, + approve, + balances, + cancel, + getTokens, + nextNonce, + nonce, + poll, + transfer, +} from './chain.controller'; +import { + TransferRequest, + TransferResponse, +} from './injective/injective.requests'; + +export const validatePollRequest: RequestValidator = mkRequestValidator([ + validateTxHash, +]); + +export const validateTokensRequest: RequestValidator = mkRequestValidator([ + validateEthereumChain, + validateEthereumNetwork, +]); + +export namespace ChainRoutes { + export const router = Router(); + + router.get( + '/status', + asyncHandler( + async ( + req: Request<{}, {}, {}, StatusRequest>, + res: Response + ) => { + res.status(200).json(await getStatus(req.query)); + } + ) + ); + + router.get('/config', (_req: Request, res: Response) => { + res.status(200).json(ConfigManagerV2.getInstance().allConfigurations); + }); + + router.post( + '/balances', + asyncHandler( + async ( + req: Request<{}, {}, BalanceRequest>, + res: Response, + _next: NextFunction + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + + res.status(200).json(await balances(chain, req.body)); + } + ) + ); + + router.post( + '/poll', + asyncHandler( + async ( + req: Request<{}, {}, PollRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await poll(chain, req.body)); + } + ) + ); + + router.get( + '/tokens', + asyncHandler( + async ( + req: Request<{}, {}, {}, TokensRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.query.chain as string, + req.query.network as string + ); + res.status(200).json(await getTokens(chain, req.query)); + } + ) + ); + + router.post( + '/nextNonce', + asyncHandler( + async ( + req: Request<{}, {}, NonceRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await nextNonce(chain, req.body)); + } + ) + ); + + router.post( + '/nonce', + asyncHandler( + async ( + req: Request<{}, {}, NonceRequest>, + res: Response + ) => { + validateNonceRequest(req.body); + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await nonce(chain, req.body)); + } + ) + ); + + router.post( + '/allowances', + asyncHandler( + async ( + req: Request<{}, {}, AllowancesRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await allowances(chain, req.body)); + } + ) + ); + + router.post( + '/approve', + asyncHandler( + async ( + req: Request<{}, {}, ApproveRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await approve(chain, req.body)); + } + ) + ); + + router.post( + '/cancel', + asyncHandler( + async ( + req: Request<{}, {}, CancelRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await cancel(chain, req.body)); + } + ) + ); + + router.post( + '/transfer', + asyncHandler( + async ( + req: Request<{}, {}, TransferRequest>, + res: Response + ) => { + const chain = await getInitializedChain( + req.body.chain, + req.body.network + ); + res.status(200).json(await transfer(chain, req.body)); + } + ) + ); +} diff --git a/src/chains/cosmos/cosmos.controllers.ts b/src/chains/cosmos/cosmos.controllers.ts index 3444650d25..ce4b8c9629 100644 --- a/src/chains/cosmos/cosmos.controllers.ts +++ b/src/chains/cosmos/cosmos.controllers.ts @@ -1,52 +1,18 @@ import { Cosmos } from './cosmos'; -import { - CosmosBalanceRequest, - CosmosBalanceResponse, - CosmosPollRequest, - CosmosPollResponse, -} from './cosmos.requests'; -import { latency, TokenValue, tokenValueToString } from '../../services/base'; +import { CosmosBalanceRequest, CosmosPollRequest } from './cosmos.requests'; +import { TokenValue, tokenValueToString } from '../../services/base'; import { HttpException, TOKEN_NOT_SUPPORTED_ERROR_CODE, TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, } from '../../services/error-handler'; +import { + validateCosmosBalanceRequest, + validateCosmosPollRequest, +} from './cosmos.validators'; const { decodeTxRaw } = require('@cosmjs/proto-signing'); -export async function balances( - cosmosish: Cosmos, - req: CosmosBalanceRequest -): Promise { - const initTime = Date.now(); - - const wallet = await cosmosish.getWallet(req.address, 'cosmos'); - - const { tokenSymbols } = req; - - tokenSymbols.forEach((symbol: string) => { - const token = cosmosish.getTokenForSymbol(symbol); - - if (!token) { - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + symbol, - TOKEN_NOT_SUPPORTED_ERROR_CODE - ); - } - }); - - const balances = await cosmosish.getBalances(wallet); - const filteredBalances = toCosmosBalances(balances, tokenSymbols); - - return { - network: cosmosish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - balances: filteredBalances, - }; -} - export const toCosmosBalances = ( balances: Record, tokenSymbols: Array @@ -66,22 +32,47 @@ export const toCosmosBalances = ( return walletBalances; }; -export async function poll( - cosmos: Cosmos, - req: CosmosPollRequest -): Promise { - const initTime = Date.now(); - const transaction = await cosmos.getTransaction(req.txHash); - const currentBlock = await cosmos.getCurrentBlockNumber(); - - return { - network: cosmos.chain, - timestamp: initTime, - txHash: req.txHash, - currentBlock, - txBlock: transaction.height, - gasUsed: transaction.gasUsed, - gasWanted: transaction.gasWanted, - txData: decodeTxRaw(transaction.tx), - }; +export class CosmosController { + static async balances(cosmosish: Cosmos, req: CosmosBalanceRequest) { + validateCosmosBalanceRequest(req); + + const wallet = await cosmosish.getWallet(req.address, 'cosmos'); + + const { tokenSymbols } = req; + + tokenSymbols.forEach((symbol: string) => { + const token = cosmosish.getTokenForSymbol(symbol); + + if (!token) { + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + symbol, + TOKEN_NOT_SUPPORTED_ERROR_CODE + ); + } + }); + + const balances = await cosmosish.getBalances(wallet); + const filteredBalances = toCosmosBalances(balances, tokenSymbols); + + return { + balances: filteredBalances, + }; + } + + static async poll(cosmos: Cosmos, req: CosmosPollRequest) { + validateCosmosPollRequest(req); + + const transaction = await cosmos.getTransaction(req.txHash); + const currentBlock = await cosmos.getCurrentBlockNumber(); + + return { + txHash: req.txHash, + currentBlock, + txBlock: transaction.height, + gasUsed: transaction.gasUsed, + gasWanted: transaction.gasWanted, + txData: decodeTxRaw(transaction.tx), + }; + } } diff --git a/src/chains/cosmos/cosmos.routes.ts b/src/chains/cosmos/cosmos.routes.ts deleted file mode 100644 index 9d1b514017..0000000000 --- a/src/chains/cosmos/cosmos.routes.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ -import { NextFunction, Router, Request, Response } from 'express'; -import { verifyCosmosIsAvailable } from './cosmos-middlewares'; -import { asyncHandler } from '../../services/error-handler'; -import { Cosmos } from './cosmos'; -import { balances, poll } from './cosmos.controllers'; -import { - CosmosBalanceResponse, - CosmosBalanceRequest, - CosmosPollRequest, - CosmosPollResponse, -} from './cosmos.requests'; -import { - validateCosmosBalanceRequest, - validateCosmosPollRequest, -} from './cosmos.validators'; - -export namespace CosmosRoutes { - export const router = Router(); - export const getCosmos = async (request: Request) => { - const cosmos = await Cosmos.getInstance(request.body.network); - await cosmos.init(); - - return cosmos; - }; - - router.use(asyncHandler(verifyCosmosIsAvailable)); - - router.get( - '/', - asyncHandler(async (_req: Request, res: Response) => { - const { rpcUrl, chain } = await getCosmos(_req); - - res.status(200).json({ - network: chain, - rpcUrl: rpcUrl, - connection: true, - timestamp: Date.now(), - }); - }) - ); - - // Get balance for wallet - router.post( - '/balances', - asyncHandler( - async ( - req: Request<{}, {}, CosmosBalanceRequest>, - res: Response, - _next: NextFunction - ) => { - const cosmos = await getCosmos(req); - validateCosmosBalanceRequest(req.body); - res.status(200).json(await balances(cosmos, req.body)); - } - ) - ); - - // Gets status information about given transaction hash - router.post( - '/poll', - asyncHandler( - async ( - req: Request<{}, {}, CosmosPollRequest>, - res: Response - ) => { - const cosmos = await getCosmos(req); - - validateCosmosPollRequest(req.body); - res.status(200).json(await poll(cosmos, req.body)); - } - ) - ); -} diff --git a/src/chains/cosmos/cosmos.ts b/src/chains/cosmos/cosmos.ts index 6917c9a659..2238437eb3 100644 --- a/src/chains/cosmos/cosmos.ts +++ b/src/chains/cosmos/cosmos.ts @@ -2,6 +2,7 @@ import { Cosmosish } from '../../services/common-interfaces'; import { CosmosBase } from './cosmos-base'; import { getCosmosConfig } from './cosmos.config'; import { logger } from '../../services/logger'; +import { CosmosController } from './cosmos.controllers'; export class Cosmos extends CosmosBase implements Cosmosish { private static _instances: { [name: string]: Cosmos }; @@ -11,6 +12,7 @@ export class Cosmos extends CosmosBase implements Cosmosish { private _requestCount: number; private _metricsLogInterval: number; private _metricTimer; + public controller; private constructor(network: string) { const config = getCosmosConfig('cosmos'); @@ -33,6 +35,7 @@ export class Cosmos extends CosmosBase implements Cosmosish { this.metricLogger.bind(this), this.metricsLogInterval ); + this.controller = CosmosController; } public static getInstance(network: string): Cosmos { diff --git a/src/chains/cronos/cronos.ts b/src/chains/cronos/cronos.ts index 00f68a8609..c39a2dfe2d 100755 --- a/src/chains/cronos/cronos.ts +++ b/src/chains/cronos/cronos.ts @@ -9,6 +9,7 @@ import { MadMeerkatConfig } from '../../connectors/mad_meerkat/mad_meerkat.confi import { VVSConfig } from '../../connectors/vvs/vvs.config'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; +import { EVMController } from '../ethereum/evm.controllers'; export class Cronos extends EthereumBase implements Ethereumish { private static _instances: { [name: string]: Cronos }; @@ -16,6 +17,7 @@ export class Cronos extends EthereumBase implements Ethereumish { private _gasPriceRefreshInterval: number | null; private _nativeTokenSymbol: string; private _chain: string; + public controller; private constructor(network: string) { const config = getCronosConfig('cronos', network); @@ -40,6 +42,7 @@ export class Cronos extends EthereumBase implements Ethereumish { : null; this.updateGasPrice(); + this.controller = EVMController; } public static getInstance(network: string): Cronos { diff --git a/src/chains/ethereum/ethereum-base.ts b/src/chains/ethereum/ethereum-base.ts index 08e1e9723c..64aefbe3a8 100644 --- a/src/chains/ethereum/ethereum-base.ts +++ b/src/chains/ethereum/ethereum-base.ts @@ -11,9 +11,9 @@ import { promises as fs } from 'fs'; import path from 'path'; import { rootPath } from '../../paths'; import { TokenListType, TokenValue, walletPath } from '../../services/base'; -import { EVMNonceManager } from '../../evm/evm.nonce'; +import { EVMNonceManager } from './evm.nonce'; import NodeCache from 'node-cache'; -import { EvmTxStorage } from '../../evm/evm.tx-storage'; +import { EvmTxStorage } from './evm.tx-storage'; import fse from 'fs-extra'; import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase'; import { logger } from '../../services/logger'; diff --git a/src/chains/ethereum/ethereum.controllers.ts b/src/chains/ethereum/ethereum.controllers.ts deleted file mode 100644 index 2b4af46fdf..0000000000 --- a/src/chains/ethereum/ethereum.controllers.ts +++ /dev/null @@ -1,456 +0,0 @@ -import ethers, { - constants, - Wallet, - utils, - BigNumber, - Transaction, -} from 'ethers'; -import { latency, bigNumberWithDecimalToStr } from '../../services/base'; -import { - HttpException, - LOAD_WALLET_ERROR_CODE, - LOAD_WALLET_ERROR_MESSAGE, - TOKEN_NOT_SUPPORTED_ERROR_CODE, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, -} from '../../services/error-handler'; -import { tokenValueToString } from '../../services/base'; -import { TokenInfo } from './ethereum-base'; -import { getConnector } from '../../services/connection-manager'; - -import { - CustomTransactionReceipt, - CustomTransaction, - CustomTransactionResponse, -} from './ethereum.requests'; -import { - Ethereumish, - UniswapLPish, - Uniswapish, - CLOBish, -} from '../../services/common-interfaces'; -import { - NonceRequest, - NonceResponse, - AllowancesRequest, - AllowancesResponse, - ApproveRequest, - ApproveResponse, - CancelRequest, - CancelResponse, -} from '../../evm/evm.requests'; -import { - PollRequest, - PollResponse, - BalanceRequest, - BalanceResponse, -} from '../../network/network.requests'; -import { logger } from '../../services/logger'; - -export async function nonce( - ethereum: Ethereumish, - req: NonceRequest -): Promise { - // get the address via the public key since we generally use the public - // key to interact with gateway and the address is not part of the user config - const wallet = await ethereum.getWallet(req.address); - const nonce = await ethereum.nonceManager.getNonce(wallet.address); - return { nonce }; -} - -export async function nextNonce( - ethereum: Ethereumish, - req: NonceRequest -): Promise { - // get the address via the public key since we generally use the public - // key to interact with gateway and the address is not part of the user config - const wallet = await ethereum.getWallet(req.address); - const nonce = await ethereum.nonceManager.getNextNonce(wallet.address); - return { nonce }; -} - -export const getTokenSymbolsToTokens = ( - ethereum: Ethereumish, - tokenSymbols: Array -): Record => { - const tokens: Record = {}; - - for (let i = 0; i < tokenSymbols.length; i++) { - const symbol = tokenSymbols[i]; - const token = ethereum.getTokenBySymbol(symbol); - if (token) tokens[symbol] = token; - } - - return tokens; -}; - -export async function allowances( - ethereumish: Ethereumish, - req: AllowancesRequest -): Promise { - const initTime = Date.now(); - const wallet = await ethereumish.getWallet(req.address); - const tokens = getTokenSymbolsToTokens(ethereumish, req.tokenSymbols); - const spender = ethereumish.getSpender(req.spender); - - const approvals: Record = {}; - await Promise.all( - Object.keys(tokens).map(async (symbol) => { - // instantiate a contract and pass in provider for read-only access - const contract = ethereumish.getContract( - tokens[symbol].address, - ethereumish.provider - ); - approvals[symbol] = tokenValueToString( - await ethereumish.getERC20Allowance( - contract, - wallet, - spender, - tokens[symbol].decimals - ) - ); - }) - ); - - return { - network: ethereumish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - spender: spender, - approvals: approvals, - }; -} - -export async function balances( - ethereumish: Ethereumish, - req: BalanceRequest -): Promise { - const initTime = Date.now(); - - let wallet: Wallet; - const connector: CLOBish | undefined = req.connector - ? ((await getConnector(req.chain, req.network, req.connector)) as CLOBish) - : undefined; - const balances: Record = {}; - let connectorBalances: { [key: string]: string } | undefined; - - if (!connector?.balances) { - try { - wallet = await ethereumish.getWallet(req.address); - } catch (err) { - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE - ); - } - - const tokens = getTokenSymbolsToTokens(ethereumish, req.tokenSymbols); - if (req.tokenSymbols.includes(ethereumish.nativeTokenSymbol)) { - balances[ethereumish.nativeTokenSymbol] = tokenValueToString( - await ethereumish.getNativeBalance(wallet) - ); - } - await Promise.all( - Object.keys(tokens).map(async (symbol) => { - if (tokens[symbol] !== undefined) { - const address = tokens[symbol].address; - const decimals = tokens[symbol].decimals; - // instantiate a contract and pass in provider for read-only access - const contract = ethereumish.getContract( - address, - ethereumish.provider - ); - const balance = await ethereumish.getERC20Balance( - contract, - wallet, - decimals - ); - balances[symbol] = tokenValueToString(balance); - } - }) - ); - - if (!Object.keys(balances).length) { - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, - TOKEN_NOT_SUPPORTED_ERROR_CODE - ); - } - } else { - // CLOB connector or any other connector that has the concept of separation of account has to implement a balance function - connectorBalances = await connector.balances(req); - } - - return { - network: ethereumish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - balances: connectorBalances || balances, - }; -} - -const toEthereumTransaction = (transaction: Transaction): CustomTransaction => { - let maxFeePerGas = null; - if (transaction.maxFeePerGas) { - maxFeePerGas = transaction.maxFeePerGas.toString(); - } - let maxPriorityFeePerGas = null; - if (transaction.maxPriorityFeePerGas) { - maxPriorityFeePerGas = transaction.maxPriorityFeePerGas.toString(); - } - let gasLimit = null; - if (transaction.gasLimit) { - gasLimit = transaction.gasLimit.toString(); - } - return { - ...transaction, - maxPriorityFeePerGas, - maxFeePerGas, - gasLimit, - value: transaction.value.toString(), - }; -}; - -export async function approve( - ethereumish: Ethereumish, - req: ApproveRequest -): Promise { - const { amount, nonce, address, token, maxFeePerGas, maxPriorityFeePerGas } = - req; - - const spender = ethereumish.getSpender(req.spender); - const initTime = Date.now(); - let wallet: Wallet; - try { - wallet = await ethereumish.getWallet(address); - } catch (err) { - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE - ); - } - const fullToken = ethereumish.getTokenBySymbol(token); - if (!fullToken) { - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + token, - TOKEN_NOT_SUPPORTED_ERROR_CODE - ); - } - const amountBigNumber = amount - ? utils.parseUnits(amount, fullToken.decimals) - : constants.MaxUint256; - - let maxFeePerGasBigNumber; - if (maxFeePerGas) { - maxFeePerGasBigNumber = BigNumber.from(maxFeePerGas); - } - let maxPriorityFeePerGasBigNumber; - if (maxPriorityFeePerGas) { - maxPriorityFeePerGasBigNumber = BigNumber.from(maxPriorityFeePerGas); - } - // instantiate a contract and pass in wallet, which act on behalf of that signer - const contract = ethereumish.getContract(fullToken.address, wallet); - - // convert strings to BigNumber - // call approve function - const approval = await ethereumish.approveERC20( - contract, - wallet, - spender, - amountBigNumber, - nonce, - maxFeePerGasBigNumber, - maxPriorityFeePerGasBigNumber, - ethereumish.gasPrice - ); - - if (approval.hash) { - await ethereumish.txStorage.saveTx( - ethereumish.chain, - ethereumish.chainId, - approval.hash, - new Date(), - ethereumish.gasPrice - ); - } - - return { - network: ethereumish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - tokenAddress: fullToken.address, - spender: spender, - amount: bigNumberWithDecimalToStr(amountBigNumber, fullToken.decimals), - nonce: approval.nonce, - approval: toEthereumTransaction(approval), - }; -} - -// TransactionReceipt from ethers uses BigNumber which is not easy to interpret directly from JSON. -// Transform those BigNumbers to string and pass the rest of the data without changes. - -const toEthereumTransactionReceipt = ( - receipt: ethers.providers.TransactionReceipt | null -): CustomTransactionReceipt | null => { - if (receipt) { - let effectiveGasPrice = null; - if (receipt.effectiveGasPrice) { - effectiveGasPrice = receipt.effectiveGasPrice.toString(); - } - return { - ...receipt, - gasUsed: receipt.gasUsed.toString(), - cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), - effectiveGasPrice, - }; - } - - return null; -}; - -const toEthereumTransactionResponse = ( - response: ethers.providers.TransactionResponse | null -): CustomTransactionResponse | null => { - if (response) { - let gasPrice = null; - if (response.gasPrice) { - gasPrice = response.gasPrice.toString(); - } - return { - ...response, - gasPrice, - gasLimit: response.gasLimit.toString(), - value: response.value.toString(), - }; - } - - return null; -}; - -export function willTxSucceed( - txDuration: number, - txDurationLimit: number, - txGasPrice: number, - currentGasPrice: number -): boolean { - if (txDuration > txDurationLimit && currentGasPrice > txGasPrice) { - return false; - } - return true; -} - -// txStatus -// -1: not in the mempool or failed -// 1: succeeded -// 2: in the mempool and likely to succeed -// 3: in the mempool and likely to fail -// 0: in the mempool but we dont have data to guess its status -export async function poll( - ethereumish: Ethereumish, - req: PollRequest -): Promise { - const initTime = Date.now(); - const currentBlock = await ethereumish.getCurrentBlockNumber(); - const txData = await ethereumish.getTransaction(req.txHash); - let txBlock, txReceipt, txStatus; - if (!txData) { - // tx not found, didn't reach the mempool or it never existed - txBlock = -1; - txReceipt = null; - txStatus = -1; - } else { - txReceipt = await ethereumish.getTransactionReceipt(req.txHash); - if (txReceipt === null) { - // tx is in the mempool - txBlock = -1; - txReceipt = null; - txStatus = 0; - - const transactions = await ethereumish.txStorage.getTxs( - ethereumish.chain, - ethereumish.chainId - ); - - if (transactions[txData.hash]) { - const data: [Date, number] = transactions[txData.hash]; - const now = new Date(); - const txDuration = Math.abs(now.getTime() - data[0].getTime()); - if ( - willTxSucceed(txDuration, 60000 * 3, data[1], ethereumish.gasPrice) - ) { - txStatus = 2; - } else { - txStatus = 3; - } - } - } else { - // tx has been processed - txBlock = txReceipt.blockNumber; - txStatus = typeof txReceipt.status === 'number' ? 1 : -1; - - // decode logs - if (req.connector) { - try { - const connector: Uniswapish | UniswapLPish | CLOBish = - await getConnector( - req.chain, - req.network, - req.connector - ); - - txReceipt.logs = connector.abiDecoder?.decodeLogs(txReceipt.logs); - } catch (e) { - logger.error(e); - } - } - } - } - - logger.info( - `Poll ${ethereumish.chain}, txHash ${req.txHash}, status ${txStatus}.` - ); - return { - network: ethereumish.chain, - currentBlock, - timestamp: initTime, - txHash: req.txHash, - txBlock, - txStatus, - txData: toEthereumTransactionResponse(txData), - txReceipt: toEthereumTransactionReceipt(txReceipt), - }; -} - -export async function cancel( - ethereumish: Ethereumish, - req: CancelRequest -): Promise { - const initTime = Date.now(); - let wallet: Wallet; - try { - wallet = await ethereumish.getWallet(req.address); - } catch (err) { - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE - ); - } - - // call cancelTx function - const cancelTx = await ethereumish.cancelTx(wallet, req.nonce); - - logger.info( - `Cancelled transaction at nonce ${req.nonce}, cancel txHash ${cancelTx.hash}.` - ); - - return { - network: ethereumish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - txHash: cancelTx.hash, - }; -} diff --git a/src/chains/ethereum/ethereum.requests.ts b/src/chains/ethereum/ethereum.requests.ts index dbfa95a58f..d699398aa5 100644 --- a/src/chains/ethereum/ethereum.requests.ts +++ b/src/chains/ethereum/ethereum.requests.ts @@ -1,4 +1,5 @@ import ethers, { Transaction } from 'ethers'; +import { NetworkSelectionRequest } from '../../services/common-interfaces'; // gasUsed and cumulativeGasUsed are BigNumbers // then need to be converted to strings before being @@ -89,7 +90,7 @@ export interface EthereumApproveResponse { approval: CustomTransaction; } -export interface PollRequest { +export interface PollRequest extends NetworkSelectionRequest { txHash: string; } diff --git a/src/chains/ethereum/ethereum.ts b/src/chains/ethereum/ethereum.ts index 7808ad9718..9315258a1e 100644 --- a/src/chains/ethereum/ethereum.ts +++ b/src/chains/ethereum/ethereum.ts @@ -6,7 +6,8 @@ import { getEthereumConfig } from './ethereum.config'; import { Provider } from '@ethersproject/abstract-provider'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; // import { throttleRetryWrapper } from '../../services/retry'; -import { Ethereumish } from '../../services/common-interfaces'; +import { Chain as Ethereumish } from '../../services/common-interfaces'; +import { EVMController } from './evm.controllers'; import { UniswapConfig } from '../../connectors/uniswap/uniswap.config'; import { Perp } from '../../connectors/perp/perp'; @@ -33,6 +34,7 @@ export class Ethereum extends EthereumBase implements Ethereumish { private _requestCount: number; private _metricsLogInterval: number; private _metricTimer; + public controller; private constructor(network: string) { const config = getEthereumConfig('ethereum', network); @@ -65,6 +67,7 @@ export class Ethereum extends EthereumBase implements Ethereumish { this.metricLogger.bind(this), this.metricsLogInterval ); + this.controller = EVMController; } public static getInstance(network: string): Ethereum { diff --git a/src/chains/ethereum/evm.controllers.ts b/src/chains/ethereum/evm.controllers.ts new file mode 100644 index 0000000000..ea6e17b6ab --- /dev/null +++ b/src/chains/ethereum/evm.controllers.ts @@ -0,0 +1,472 @@ +import ethers, { + constants, + Wallet, + utils, + BigNumber, + Transaction, +} from 'ethers'; +import { bigNumberWithDecimalToStr } from '../../services/base'; +import { + HttpException, + LOAD_WALLET_ERROR_CODE, + LOAD_WALLET_ERROR_MESSAGE, + TOKEN_NOT_SUPPORTED_ERROR_CODE, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, +} from '../../services/error-handler'; +import { tokenValueToString } from '../../services/base'; +import { TokenInfo } from './ethereum-base'; +import { getConnector } from '../../services/connection-manager'; + +import { + CustomTransactionReceipt, + CustomTransactionResponse, + PollRequest, +} from './ethereum.requests'; +import { + CLOBish, + Chain as Ethereumish, + UniswapLPish, + Uniswapish, +} from '../../services/common-interfaces'; +import { + NonceRequest, + NonceResponse, + AllowancesRequest, + ApproveRequest, + CancelRequest, +} from '../chain.requests'; +import { BalanceRequest, TokensRequest } from '../../network/network.requests'; +import { logger } from '../../services/logger'; +import { + validateAllowancesRequest, + validateApproveRequest, + validateBalanceRequest, + validateCancelRequest, + validateNonceRequest, +} from './ethereum.validators'; +import { validatePollRequest, validateTokensRequest } from '../chain.routes'; + +// TransactionReceipt from ethers uses BigNumber which is not easy to interpret directly from JSON. +// Transform those BigNumbers to string and pass the rest of the data without changes. + +const toEthereumTransactionReceipt = ( + receipt: ethers.providers.TransactionReceipt | null +): CustomTransactionReceipt | null => { + if (receipt) { + let effectiveGasPrice = null; + if (receipt.effectiveGasPrice) { + effectiveGasPrice = receipt.effectiveGasPrice.toString(); + } + return { + ...receipt, + gasUsed: receipt.gasUsed.toString(), + cumulativeGasUsed: receipt.cumulativeGasUsed.toString(), + effectiveGasPrice, + }; + } + + return null; +}; + +const toEthereumTransactionResponse = ( + response: ethers.providers.TransactionResponse | null +): CustomTransactionResponse | null => { + if (response) { + let gasPrice = null; + if (response.gasPrice) { + gasPrice = response.gasPrice.toString(); + } + return { + ...response, + gasPrice, + gasLimit: response.gasLimit.toString(), + value: response.value.toString(), + }; + } + + return null; +}; + +const toEthereumTransaction = (transaction: Transaction) => { + let maxFeePerGas = null; + if (transaction.maxFeePerGas) { + maxFeePerGas = transaction.maxFeePerGas.toString(); + } + let maxPriorityFeePerGas = null; + if (transaction.maxPriorityFeePerGas) { + maxPriorityFeePerGas = transaction.maxPriorityFeePerGas.toString(); + } + let gasLimit = null; + if (transaction.gasLimit) { + gasLimit = transaction.gasLimit.toString(); + } + return { + ...transaction, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + value: transaction.value.toString(), + }; +}; + +export const willTxSucceed = ( + txDuration: number, + txDurationLimit: number, + txGasPrice: number, + currentGasPrice: number +) => { + if (txDuration > txDurationLimit && currentGasPrice > txGasPrice) { + return false; + } + return true; +}; + +export class EVMController { + // txStatus + // -1: not in the mempool or failed + // 1: succeeded + // 2: in the mempool and likely to succeed + // 3: in the mempool and likely to fail + // 0: in the mempool but we dont have data to guess its status + static async poll(ethereumish: Ethereumish, req: PollRequest) { + validatePollRequest(req); + + const currentBlock = await ethereumish.getCurrentBlockNumber(); + const txData = await ethereumish.getTransaction(req.txHash); + let txBlock, txReceipt, txStatus; + if (!txData) { + // tx not found, didn't reach the mempool or it never existed + txBlock = -1; + txReceipt = null; + txStatus = -1; + } else { + txReceipt = await ethereumish.getTransactionReceipt(req.txHash); + if (txReceipt === null) { + // tx is in the mempool + txBlock = -1; + txReceipt = null; + txStatus = 0; + + const transactions = await ethereumish.txStorage.getTxs( + ethereumish.chain, + ethereumish.chainId + ); + + if (transactions[txData.hash]) { + const data: [Date, number] = transactions[txData.hash]; + const now = new Date(); + const txDuration = Math.abs(now.getTime() - data[0].getTime()); + if ( + willTxSucceed(txDuration, 60000 * 3, data[1], ethereumish.gasPrice) + ) { + txStatus = 2; + } else { + txStatus = 3; + } + } + } else { + // tx has been processed + txBlock = txReceipt.blockNumber; + txStatus = typeof txReceipt.status === 'number' ? 1 : -1; + + // decode logs + if (req.connector) { + try { + const connector: Uniswapish | UniswapLPish | CLOBish = + await getConnector( + req.chain, + req.network, + req.connector + ); + + txReceipt.logs = connector.abiDecoder?.decodeLogs(txReceipt.logs); + } catch (e) { + logger.error(e); + } + } + } + } + + logger.info( + `Poll ${ethereumish.chain}, txHash ${req.txHash}, status ${txStatus}.` + ); + return { + currentBlock, + txHash: req.txHash, + txBlock, + txStatus, + txData: toEthereumTransactionResponse(txData), + txReceipt: toEthereumTransactionReceipt(txReceipt), + }; + } + + static async nonce( + ethereum: Ethereumish, + req: NonceRequest + ): Promise { + validateNonceRequest(req); + // get the address via the public key since we generally use the public + // key to interact with gateway and the address is not part of the user config + const wallet = await ethereum.getWallet(req.address); + const nonce = await ethereum.nonceManager.getNonce(wallet.address); + return { nonce }; + } + + static async nextNonce( + ethereum: Ethereumish, + req: NonceRequest + ): Promise { + validateNonceRequest(req); + // get the address via the public key since we generally use the public + // key to interact with gateway and the address is not part of the user config + const wallet = await ethereum.getWallet(req.address); + const nonce = await ethereum.nonceManager.getNextNonce(wallet.address); + return { nonce }; + } + + static getTokenSymbolsToTokens = ( + ethereum: Ethereumish, + tokenSymbols: Array + ): Record => { + const tokens: Record = {}; + + for (let i = 0; i < tokenSymbols.length; i++) { + const symbol = tokenSymbols[i]; + const token = ethereum.getTokenBySymbol(symbol); + if (token) tokens[symbol] = token; + } + + return tokens; + }; + + static async getTokens(connection: Ethereumish, req: TokensRequest) { + validateTokensRequest(req); + let tokens: TokenInfo[] = []; + if (!req.tokenSymbols) { + tokens = connection.storedTokenList; + } else { + for (const t of req.tokenSymbols as []) { + tokens.push(connection.getTokenForSymbol(t) as TokenInfo); + } + } + + return { tokens }; + } + + static async allowances(ethereumish: Ethereumish, req: AllowancesRequest) { + validateAllowancesRequest(req); + return EVMController.allowancesWithoutValidation(ethereumish, req); + } + + static async allowancesWithoutValidation( + ethereumish: Ethereumish, + req: AllowancesRequest + ) { + const wallet = await ethereumish.getWallet(req.address); + const tokens = EVMController.getTokenSymbolsToTokens( + ethereumish, + req.tokenSymbols + ); + const spender = ethereumish.getSpender(req.spender); + + const approvals: Record = {}; + await Promise.all( + Object.keys(tokens).map(async (symbol) => { + // instantiate a contract and pass in provider for read-only access + const contract = ethereumish.getContract( + tokens[symbol].address, + ethereumish.provider + ); + approvals[symbol] = tokenValueToString( + await ethereumish.getERC20Allowance( + contract, + wallet, + spender, + tokens[symbol].decimals + ) + ); + }) + ); + + return { + spender: spender, + approvals: approvals, + }; + } + + static async balances(ethereumish: Ethereumish, req: BalanceRequest) { + validateBalanceRequest(req); + + let wallet: Wallet; + const connector: CLOBish | undefined = req.connector + ? ((await getConnector(req.chain, req.network, req.connector)) as CLOBish) + : undefined; + const balances: Record = {}; + let connectorBalances: { [key: string]: string } | undefined; + + if (!connector?.balances) { + try { + wallet = await ethereumish.getWallet(req.address); + } catch (err) { + throw new HttpException( + 500, + LOAD_WALLET_ERROR_MESSAGE + err, + LOAD_WALLET_ERROR_CODE + ); + } + + const tokens = EVMController.getTokenSymbolsToTokens( + ethereumish, + req.tokenSymbols + ); + if (req.tokenSymbols.includes(ethereumish.nativeTokenSymbol)) { + balances[ethereumish.nativeTokenSymbol] = tokenValueToString( + await ethereumish.getNativeBalance(wallet) + ); + } + await Promise.all( + Object.keys(tokens).map(async (symbol) => { + if (tokens[symbol] !== undefined) { + const address = tokens[symbol].address; + const decimals = tokens[symbol].decimals; + // instantiate a contract and pass in provider for read-only access + const contract = ethereumish.getContract( + address, + ethereumish.provider + ); + const balance = await ethereumish.getERC20Balance( + contract, + wallet, + decimals + ); + balances[symbol] = tokenValueToString(balance); + } + }) + ); + + if (!Object.keys(balances).length) { + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, + TOKEN_NOT_SUPPORTED_ERROR_CODE + ); + } + } else { + // CLOB connector or any other connector that has the concept of separation of account has to implement a balance function + connectorBalances = await connector.balances(req); + } + + return { + balances: connectorBalances || balances, + }; + } + + static async approve(ethereumish: Ethereumish, req: ApproveRequest) { + validateApproveRequest(req); + return await EVMController.approveWithoutValidation(ethereumish, req); + } + + static async approveWithoutValidation( + ethereumish: Ethereumish, + req: ApproveRequest + ) { + const { + amount, + nonce, + address, + token, + maxFeePerGas, + maxPriorityFeePerGas, + } = req; + + const spender = ethereumish.getSpender(req.spender); + let wallet: Wallet; + try { + wallet = await ethereumish.getWallet(address); + } catch (err) { + throw new HttpException( + 500, + LOAD_WALLET_ERROR_MESSAGE + err, + LOAD_WALLET_ERROR_CODE + ); + } + const fullToken = ethereumish.getTokenBySymbol(token); + if (!fullToken) { + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + token, + TOKEN_NOT_SUPPORTED_ERROR_CODE + ); + } + const amountBigNumber = amount + ? utils.parseUnits(amount, fullToken.decimals) + : constants.MaxUint256; + + let maxFeePerGasBigNumber; + if (maxFeePerGas) { + maxFeePerGasBigNumber = BigNumber.from(maxFeePerGas); + } + let maxPriorityFeePerGasBigNumber; + if (maxPriorityFeePerGas) { + maxPriorityFeePerGasBigNumber = BigNumber.from(maxPriorityFeePerGas); + } + // instantiate a contract and pass in wallet, which act on behalf of that signer + const contract = ethereumish.getContract(fullToken.address, wallet); + + // convert strings to BigNumber + // call approve function + const approval = await ethereumish.approveERC20( + contract, + wallet, + spender, + amountBigNumber, + nonce, + maxFeePerGasBigNumber, + maxPriorityFeePerGasBigNumber, + ethereumish.gasPrice + ); + + if (approval.hash) { + await ethereumish.txStorage.saveTx( + ethereumish.chain, + ethereumish.chainId, + approval.hash, + new Date(), + ethereumish.gasPrice + ); + } + + return { + tokenAddress: fullToken.address, + spender: spender, + amount: bigNumberWithDecimalToStr(amountBigNumber, fullToken.decimals), + nonce: approval.nonce, + approval: toEthereumTransaction(approval), + }; + } + + static async cancel(ethereumish: Ethereumish, req: CancelRequest) { + validateCancelRequest(req); + let wallet: Wallet; + try { + wallet = await ethereumish.getWallet(req.address); + } catch (err) { + throw new HttpException( + 500, + LOAD_WALLET_ERROR_MESSAGE + err, + LOAD_WALLET_ERROR_CODE + ); + } + + // call cancelTx function + const cancelTx = await ethereumish.cancelTx(wallet, req.nonce); + + logger.info( + `Cancelled transaction at nonce ${req.nonce}, cancel txHash ${cancelTx.hash}.` + ); + + return { + txHash: cancelTx.hash, + }; + } +} diff --git a/src/evm/evm.nonce.ts b/src/chains/ethereum/evm.nonce.ts similarity index 98% rename from src/evm/evm.nonce.ts rename to src/chains/ethereum/evm.nonce.ts index 3de221847c..60c949e4d1 100644 --- a/src/evm/evm.nonce.ts +++ b/src/chains/ethereum/evm.nonce.ts @@ -5,10 +5,10 @@ import { INVALID_NONCE_ERROR_MESSAGE, SERVICE_UNITIALIZED_ERROR_CODE, SERVICE_UNITIALIZED_ERROR_MESSAGE, -} from '../services/error-handler'; -import { LocalStorage } from '../services/local-storage'; -import { logger } from '../services/logger'; -import { ReferenceCountingCloseable } from '../services/refcounting-closeable'; +} from '../../services/error-handler'; +import { LocalStorage } from '../../services/local-storage'; +import { logger } from '../../services/logger'; +import { ReferenceCountingCloseable } from '../../services/refcounting-closeable'; export class NonceInfo { constructor(readonly nonce: number, public expiry: number) {} diff --git a/src/evm/evm.tx-storage.ts b/src/chains/ethereum/evm.tx-storage.ts similarity index 92% rename from src/evm/evm.tx-storage.ts rename to src/chains/ethereum/evm.tx-storage.ts index 907e19d716..c74e6eae2e 100644 --- a/src/evm/evm.tx-storage.ts +++ b/src/chains/ethereum/evm.tx-storage.ts @@ -1,5 +1,5 @@ -import { LocalStorage } from '../services/local-storage'; -import { ReferenceCountingCloseable } from '../services/refcounting-closeable'; +import { LocalStorage } from '../../services/local-storage'; +import { ReferenceCountingCloseable } from '../../services/refcounting-closeable'; // store the timestamp for when a transaction was initiated // this will be used to calculate a heuristic of the likelihood diff --git a/src/chains/harmony/harmony.ts b/src/chains/harmony/harmony.ts index cdcdcec097..fb994ca795 100644 --- a/src/chains/harmony/harmony.ts +++ b/src/chains/harmony/harmony.ts @@ -9,6 +9,7 @@ import { Ethereumish } from '../../services/common-interfaces'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; import { SushiswapConfig } from '../../connectors/sushiswap/sushiswap.config'; +import { EVMController } from '../ethereum/evm.controllers'; export class Harmony extends EthereumBase implements Ethereumish { private static _instances: { [name: string]: Harmony }; @@ -19,6 +20,7 @@ export class Harmony extends EthereumBase implements Ethereumish { private _requestCount: number; private _metricsLogInterval: number; private _metricTimer; + public controller; private constructor(network: string) { const config = getHarmonyConfig('harmony', network); @@ -48,6 +50,7 @@ export class Harmony extends EthereumBase implements Ethereumish { this.metricLogger.bind(this), this.metricsLogInterval ); + this.controller = EVMController; } public static getInstance(network: string): Harmony { diff --git a/src/chains/injective/injective.controllers.ts b/src/chains/injective/injective.controllers.ts index c7b6eb0d17..158f6fa21c 100644 --- a/src/chains/injective/injective.controllers.ts +++ b/src/chains/injective/injective.controllers.ts @@ -4,45 +4,51 @@ import { BalancesResponse, PollRequest, PollResponse, - TransferToSubAccountRequest, - TransferToSubAccountResponse, - TransferToBankAccountRequest, - TransferToBankAccountResponse, + TransferRequest, + TransferResponse, } from './injective.requests'; +import { + validateBalanceRequest, + validatePollRequest, + validateTransferRequest, +} from './injective.validators'; -export async function currentBlockNumber( - injective: Injective -): Promise { - return injective.currentBlockNumber(); -} +export class InjectiveController { + static async currentBlockNumber(injective: Injective): Promise { + return injective.currentBlockNumber(); + } -export async function transferToSubAccount( - injective: Injective, - req: TransferToSubAccountRequest -): Promise { - const wallet = await injective.getWallet(req.address); - return injective.transferToSubAccount(wallet, req.amount, req.token); -} + static async transfer( + injective: Injective, + req: TransferRequest + ): Promise { + validateTransferRequest(req); -export async function transferToBankAccount( - injective: Injective, - req: TransferToBankAccountRequest -): Promise { - const wallet = await injective.getWallet(req.address); - return injective.transferToBankAccount(wallet, req.amount, req.token); -} + if (req.from.length > req.to.length) { + const wallet = await injective.getWallet(req.from); + return injective.transferToBankAccount(wallet, req.amount, req.token); + } else { + const wallet = await injective.getWallet(req.to); + return injective.transferToSubAccount(wallet, req.amount, req.token); + } + } -export async function balances( - injective: Injective, - req: BalancesRequest -): Promise { - const wallet = await injective.getWallet(req.address); - return injective.balances(wallet); -} + static async balances( + injective: Injective, + req: BalancesRequest + ): Promise { + validateBalanceRequest(req); + + const wallet = await injective.getWallet(req.address); + return injective.balances(wallet); + } + + static async poll( + injective: Injective, + req: PollRequest + ): Promise { + validatePollRequest(req); -export async function poll( - injective: Injective, - req: PollRequest -): Promise { - return injective.poll(req.txHash); + return injective.poll(req.txHash); + } } diff --git a/src/chains/injective/injective.requests.ts b/src/chains/injective/injective.requests.ts index 957cf7b722..f0bd0be1b2 100644 --- a/src/chains/injective/injective.requests.ts +++ b/src/chains/injective/injective.requests.ts @@ -39,14 +39,11 @@ export type BalancesResponse = { subaccounts: Array; }; -export interface TransferToSubAccountRequest extends NetworkSelectionRequest { - address: string; +export interface TransferRequest extends NetworkSelectionRequest { + to: string; + from: string; amount: string; token: string; } -export type TransferToSubAccountResponse = string; - -export type TransferToBankAccountRequest = TransferToSubAccountRequest; - -export type TransferToBankAccountResponse = TransferToSubAccountResponse; +export type TransferResponse = string; diff --git a/src/chains/injective/injective.routes.ts b/src/chains/injective/injective.routes.ts deleted file mode 100644 index 0894b03957..0000000000 --- a/src/chains/injective/injective.routes.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* eslint-disable no-inner-declarations */ -/* eslint-disable @typescript-eslint/ban-types */ -import { Router, Request, Response } from 'express'; -import { asyncHandler } from '../../services/error-handler'; -import { - balances, - currentBlockNumber, - poll, - transferToBankAccount, - transferToSubAccount, -} from './injective.controllers'; -import { Injective } from './injective'; -import { - BalancesRequest, - BalancesResponse, - PollRequest, - PollResponse, - TransferToBankAccountRequest, - TransferToBankAccountResponse, - TransferToSubAccountRequest, - TransferToSubAccountResponse, -} from './injective.requests'; -import { - validatePollRequest, - validateBalanceRequest, - validateTransferToBankAccountRequest, - validateTransferToSubAccountRequest, -} from './injective.validators'; -import { getInitializedChain } from '../../services/connection-manager'; -import { NetworkSelectionRequest } from '../../services/common-interfaces'; - -export namespace InjectiveRoutes { - export const router = Router(); - - router.get( - '/block/current', - asyncHandler( - async ( - req: Request<{}, {}, NetworkSelectionRequest>, - res: Response - ) => { - const injective = await getInitializedChain( - req.query.chain, - req.query.network - ); - res.status(200).json(await currentBlockNumber(injective)); - } - ) - ); - - router.post( - '/transfer/to/bank', - asyncHandler( - async ( - req: Request<{}, {}, TransferToBankAccountRequest>, - res: Response - ) => { - validateTransferToBankAccountRequest(req.body); - const injective = await getInitializedChain( - req.body.chain, - req.body.network - ); - res - .status(200) - .json(await transferToBankAccount(injective, req.body)); - } - ) - ); - - router.post( - '/transfer/to/sub', - asyncHandler( - async ( - req: Request<{}, {}, TransferToSubAccountRequest>, - res: Response - ) => { - validateTransferToSubAccountRequest(req.body); - const injective = await getInitializedChain( - req.body.chain, - req.body.network - ); - res - .status(200) - .json(await transferToSubAccount(injective, req.body)); - } - ) - ); - - router.post( - '/balances', - asyncHandler( - async ( - req: Request<{}, {}, BalancesRequest>, - res: Response - ) => { - validateBalanceRequest(req.body); - const injective = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await balances(injective, req.body)); - } - ) - ); - - router.post( - '/poll', - asyncHandler( - async ( - req: Request<{}, {}, PollRequest>, - res: Response - ) => { - validatePollRequest(req.body); - const injective = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await poll(injective, req.body)); - } - ) - ); -} diff --git a/src/chains/injective/injective.ts b/src/chains/injective/injective.ts index 4ad21ac06e..a7e48fc1b6 100644 --- a/src/chains/injective/injective.ts +++ b/src/chains/injective/injective.ts @@ -51,8 +51,9 @@ import { import { MsgBroadcasterLocal } from './injective.message'; import LRUCache from 'lru-cache'; import { TokenInfo } from '../../services/base'; -import { EVMNonceManager } from '../../evm/evm.nonce'; +import { EVMNonceManager } from '../ethereum/evm.nonce'; import { AccountDetails } from '@injectivelabs/sdk-ts/dist/cjs/types/auth'; +import { InjectiveController } from './injective.controllers'; export interface InjectiveWallet { ethereumAddress: string; @@ -88,6 +89,7 @@ export class Injective { public maxCacheSize: number; private _blockUpdateIntervalID: number | undefined; private _walletMap: LRUCache; + public controller: typeof InjectiveController; private constructor(network: Network, chainId: ChainId) { this._network = network; @@ -120,6 +122,7 @@ export class Injective { this._walletMap = new LRUCache({ max: this.maxCacheSize, }); + this.controller = InjectiveController; } public static getInstance(networkStr: string): Injective { diff --git a/src/chains/injective/injective.validators.ts b/src/chains/injective/injective.validators.ts index 4163228835..be6139aaba 100644 --- a/src/chains/injective/injective.validators.ts +++ b/src/chains/injective/injective.validators.ts @@ -28,6 +28,18 @@ export const validateAddress: Validator = mkValidator( (val) => typeof val === 'string' ); +export const validateFrom: Validator = mkValidator( + 'from', + invalidAddressError, + (val) => typeof val === 'string' +); + +export const validateTo: Validator = mkValidator( + 'to', + invalidAddressError, + (val) => typeof val === 'string' +); + export const validateBalanceRequest: RequestValidator = mkRequestValidator([ validateNetwork, validateAddress, @@ -50,12 +62,10 @@ export const validateToken: Validator = mkValidator( (val) => typeof val === 'string' ); -export const validateTransferToSubAccountRequest = mkRequestValidator([ +export const validateTransferRequest = mkRequestValidator([ validateNetwork, - validateAddress, + validateFrom, + validateTo, validateAmount, validateToken, ]); - -export const validateTransferToBankAccountRequest = - validateTransferToSubAccountRequest; diff --git a/src/chains/near/near.base.ts b/src/chains/near/near.base.ts index fa60eeb782..763c569e31 100644 --- a/src/chains/near/near.base.ts +++ b/src/chains/near/near.base.ts @@ -12,7 +12,7 @@ import axios from 'axios'; import { promises as fs } from 'fs'; import { TokenListType, TokenValue, walletPath } from '../../services/base'; import NodeCache from 'node-cache'; -import { EvmTxStorage } from '../../evm/evm.tx-storage'; +import { EvmTxStorage } from '../ethereum/evm.tx-storage'; import fse from 'fs-extra'; import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase'; import { logger } from '../../services/logger'; diff --git a/src/chains/near/near.controllers.ts b/src/chains/near/near.controllers.ts index 7244a4ee25..07ca4b8b3d 100644 --- a/src/chains/near/near.controllers.ts +++ b/src/chains/near/near.controllers.ts @@ -1,6 +1,5 @@ import { Account, providers, utils } from 'near-api-js'; import { BigNumber, utils as ethersUtils } from 'ethers'; -import { latency } from '../../services/base'; import { HttpException, OUT_OF_GAS_ERROR_CODE, @@ -12,158 +11,138 @@ import { } from '../../services/error-handler'; import { TokenInfo } from './near.base'; -import { - CancelRequest, - CancelResponse, - PollResponse, - BalanceRequest, - BalanceResponse, -} from './near.requests'; +import { CancelRequest, BalanceRequest, PollRequest } from './near.requests'; import { logger } from '../../services/logger'; import { Nearish } from '../../services/common-interfaces'; -export const getTokenSymbolsToTokens = ( - near: Nearish, - tokenSymbols: Array -): Record => { - const tokens: Record = {}; - - for (let i = 0; i < tokenSymbols.length; i++) { - const symbol = tokenSymbols[i]; - const token = near.getTokenBySymbol(symbol); - if (token) tokens[symbol] = token; - } +export class NearController { + static getTokenSymbolsToTokens = ( + near: Nearish, + tokenSymbols: Array + ): Record => { + const tokens: Record = {}; - return tokens; -}; + for (let i = 0; i < tokenSymbols.length; i++) { + const symbol = tokenSymbols[i]; + const token = near.getTokenBySymbol(symbol); + if (token) tokens[symbol] = token; + } -export async function balances( - nearish: Nearish, - req: BalanceRequest -): Promise { - const initTime = Date.now(); - - let account: Account; - try { - account = await nearish.getWallet(req.address); - } catch (err) { - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE - ); - } - const tokens = getTokenSymbolsToTokens(nearish, req.tokenSymbols); - const balances: Record = {}; - if (req.tokenSymbols.includes(nearish.nativeTokenSymbol)) { - balances[nearish.nativeTokenSymbol] = utils.format.formatNearAmount( - await nearish.getNativeBalance(account) + return tokens; + }; + static async balances(nearish: Nearish, req: BalanceRequest) { + let account: Account; + try { + account = await nearish.getWallet(req.address); + } catch (err) { + throw new HttpException( + 500, + LOAD_WALLET_ERROR_MESSAGE + err, + LOAD_WALLET_ERROR_CODE + ); + } + const tokens = NearController.getTokenSymbolsToTokens( + nearish, + req.tokenSymbols ); - } - await Promise.all( - Object.keys(tokens).map(async (symbol) => { - if ( - tokens[symbol] !== undefined && - symbol !== nearish.nativeTokenSymbol - ) { - const address = tokens[symbol].address; - const decimals = tokens[symbol].decimals; - // instantiate a contract and pass in provider for read-only access - const contract = nearish.getContract(address, account); - const balance: string = await nearish.getFungibleTokenBalance(contract); - balances[symbol] = ethersUtils - .formatUnits(BigNumber.from(balance), decimals) - .toString(); - } - }) - ); - - if (!Object.keys(balances).length) { - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, - TOKEN_NOT_SUPPORTED_ERROR_CODE + const balances: Record = {}; + if (req.tokenSymbols.includes(nearish.nativeTokenSymbol)) { + balances[nearish.nativeTokenSymbol] = utils.format.formatNearAmount( + await nearish.getNativeBalance(account) + ); + } + await Promise.all( + Object.keys(tokens).map(async (symbol) => { + if ( + tokens[symbol] !== undefined && + symbol !== nearish.nativeTokenSymbol + ) { + const address = tokens[symbol].address; + const decimals = tokens[symbol].decimals; + // instantiate a contract and pass in provider for read-only access + const contract = nearish.getContract(address, account); + const balance: string = await nearish.getFungibleTokenBalance( + contract + ); + balances[symbol] = ethersUtils + .formatUnits(BigNumber.from(balance), decimals) + .toString(); + } + }) ); - } - return { - network: nearish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - balances: balances, - }; -} + if (!Object.keys(balances).length) { + throw new HttpException( + 500, + TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, + TOKEN_NOT_SUPPORTED_ERROR_CODE + ); + } -// txStatus -// -1: not in the mempool or failed -// 1: succeeded -export async function poll( - nearish: Nearish, - address: string, - txHash: string -): Promise { - const initTime = Date.now(); - const currentBlock = await nearish.getCurrentBlockNumber(); - const txReceipt: providers.FinalExecutionOutcome = - await nearish.getTransaction(txHash, address); - let txStatus = -1; - if ( - typeof txReceipt.status === 'object' && - 'SuccessValue' in txReceipt.status - ) { - txStatus = 1; + return { + balances: balances, + }; } - if ( - txReceipt.transaction_outcome.outcome.gas_burnt / - nearish.gasLimitTransaction > - 0.9 - ) { - throw new HttpException( - 503, - OUT_OF_GAS_ERROR_MESSAGE, - OUT_OF_GAS_ERROR_CODE - ); - } + // txStatus + // -1: not in the mempool or failed + // 1: succeeded + static async poll(nearish: Nearish, body: PollRequest) { + const currentBlock = await nearish.getCurrentBlockNumber(); + const txReceipt: providers.FinalExecutionOutcome = + await nearish.getTransaction(body.txHash, body.address); + let txStatus = -1; + if ( + typeof txReceipt.status === 'object' && + 'SuccessValue' in txReceipt.status + ) { + txStatus = 1; + } - logger.info(`Poll ${nearish.chain}, txHash ${txHash}, status ${txStatus}.`); - return { - network: nearish.chain, - currentBlock, - timestamp: initTime, - txHash: txHash, - txStatus, - txReceipt, - }; -} + if ( + txReceipt.transaction_outcome.outcome.gas_burnt / + nearish.gasLimitTransaction > + 0.9 + ) { + throw new HttpException( + 503, + OUT_OF_GAS_ERROR_MESSAGE, + OUT_OF_GAS_ERROR_CODE + ); + } -export async function cancel( - nearish: Nearish, - req: CancelRequest -): Promise { - const initTime = Date.now(); - let account: Account; - try { - account = await nearish.getWallet(req.address); - } catch (err) { - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE + logger.info( + `Poll ${nearish.chain}, txHash ${body.txHash}, status ${txStatus}.` ); + return { + currentBlock, + txHash: body.txHash, + txStatus, + txReceipt, + }; } - // call cancelTx function - const cancelTx = await nearish.cancelTx(account, req.nonce); + static async cancel(nearish: Nearish, req: CancelRequest) { + let account: Account; + try { + account = await nearish.getWallet(req.address); + } catch (err) { + throw new HttpException( + 500, + LOAD_WALLET_ERROR_MESSAGE + err, + LOAD_WALLET_ERROR_CODE + ); + } - logger.info( - `Cancelled transaction at nonce ${req.nonce}, cancel txHash ${cancelTx}.` - ); + // call cancelTx function + const cancelTx = await nearish.cancelTx(account, req.nonce); - return { - network: nearish.chain, - timestamp: initTime, - latency: latency(initTime, Date.now()), - txHash: cancelTx, - }; + logger.info( + `Cancelled transaction at nonce ${req.nonce}, cancel txHash ${cancelTx}.` + ); + + return { + txHash: cancelTx, + }; + } } diff --git a/src/chains/near/near.routes.ts b/src/chains/near/near.routes.ts deleted file mode 100644 index 28e345cef5..0000000000 --- a/src/chains/near/near.routes.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ -import { Router, Request, Response, NextFunction } from 'express'; -import { Nearish } from '../../services/common-interfaces'; -import { asyncHandler } from '../../services/error-handler'; - -import { getInitializedChain } from '../../services/connection-manager'; -import { BalanceResponse, PollRequest, PollResponse } from './near.requests'; -import { validateBalanceRequest } from './near.validators'; -import * as nearControllers from './near.controllers'; -import { getTokens } from '../../network/network.controllers'; -import { - validatePollRequest, - validateTokensRequest, -} from '../../network/network.routes'; -import { - BalanceRequest, - TokensRequest, - TokensResponse, -} from '../../network/network.requests'; - -export namespace NearRoutes { - export const router = Router(); - - router.post( - '/balances', - asyncHandler( - async ( - req: Request<{}, {}, BalanceRequest>, - res: Response, - _next: NextFunction - ) => { - validateBalanceRequest(req.body); - - const chain = await getInitializedChain( - 'near', - req.body.network - ); - - res - .status(200) - .json( - (await nearControllers.balances(chain, req.body)) as BalanceResponse - ); - } - ) - ); - - router.post( - '/poll', - asyncHandler( - async ( - req: Request<{}, {}, PollRequest>, - res: Response - ) => { - validatePollRequest(req.body); - - const chain = await getInitializedChain( - 'near', - req.body.network - ); - - res - .status(200) - .json( - await nearControllers.poll( - chain, - req.body.address, - req.body.txHash - ) - ); - } - ) - ); - - router.get( - '/tokens', - asyncHandler( - async ( - req: Request<{}, {}, {}, TokensRequest>, - res: Response - ) => { - validateTokensRequest(req.query); - res.status(200).json(await getTokens(req.query)); - } - ) - ); -} diff --git a/src/chains/near/near.ts b/src/chains/near/near.ts index da6bc37fad..6d44e6f72b 100644 --- a/src/chains/near/near.ts +++ b/src/chains/near/near.ts @@ -5,6 +5,7 @@ import { ConfigManagerV2 } from '../../services/config-manager-v2'; import { NearBase } from './near.base'; import { ContractMethods } from 'near-api-js/lib/contract'; import { getNearConfig } from './near.config'; +import { NearController } from './near.controllers'; export class Near extends NearBase { private static _instances: { [name: string]: Near }; @@ -12,6 +13,7 @@ export class Near extends NearBase { private _gasPriceRefreshInterval: number | null; private _nativeTokenSymbol: string; private _chain: string; + public controller; private constructor(network: string) { const config = getNearConfig('near', network); @@ -34,6 +36,7 @@ export class Near extends NearBase { : null; this.updateGasPrice(); + this.controller = NearController; } public static getInstance(network: string): Near { diff --git a/src/chains/polygon/polygon.ts b/src/chains/polygon/polygon.ts index bf97a824eb..39cb2a758c 100644 --- a/src/chains/polygon/polygon.ts +++ b/src/chains/polygon/polygon.ts @@ -10,12 +10,14 @@ import { UniswapConfig } from '../../connectors/uniswap/uniswap.config'; import { Ethereumish } from '../../services/common-interfaces'; import { ConfigManagerV2 } from '../../services/config-manager-v2'; import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; +import { EVMController } from '../ethereum/evm.controllers'; export class Polygon extends EthereumBase implements Ethereumish { private static _instances: { [name: string]: Polygon }; private _gasPrice: number; private _nativeTokenSymbol: string; private _chain: string; + public controller; private constructor(network: string) { const config = getPolygonConfig('polygon', network); @@ -33,6 +35,7 @@ export class Polygon extends EthereumBase implements Ethereumish { this._chain = config.network.name; this._nativeTokenSymbol = config.nativeCurrencySymbol; this._gasPrice = config.manualGasPrice; + this.controller = EVMController; } public static getInstance(network: string): Polygon { diff --git a/src/chains/xdc/xdc.base.ts b/src/chains/xdc/xdc.base.ts index 8b65a31ac6..bd718d81f0 100644 --- a/src/chains/xdc/xdc.base.ts +++ b/src/chains/xdc/xdc.base.ts @@ -11,9 +11,9 @@ import { promises as fs } from 'fs'; import path from 'path'; import { rootPath } from '../../paths'; import { TokenListType, TokenValue, walletPath } from '../../services/base'; -import { EVMNonceManager } from '../../evm/evm.nonce'; +import { EVMNonceManager } from '../ethereum/evm.nonce'; import NodeCache from 'node-cache'; -import { EvmTxStorage } from '../../evm/evm.tx-storage'; +import { EvmTxStorage } from '../ethereum/evm.tx-storage'; import fse from 'fs-extra'; import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase'; import { logger } from '../../services/logger'; diff --git a/src/chains/xdc/xdc.controllers.ts b/src/chains/xdc/xdc.controllers.ts new file mode 100644 index 0000000000..6c7ce52100 --- /dev/null +++ b/src/chains/xdc/xdc.controllers.ts @@ -0,0 +1,19 @@ +import { Chain as Ethereumish } from '../../services/common-interfaces'; +import { AllowancesRequest, ApproveRequest } from '../chain.requests'; +import { EVMController } from '../ethereum/evm.controllers'; +import { + validateXdcAllowancesRequest, + validateXdcApproveRequest, +} from './xdc.validators'; + +export class XDCCOntroller extends EVMController { + static async allowances(ethereumish: Ethereumish, req: AllowancesRequest) { + validateXdcAllowancesRequest(req); + return EVMController.allowancesWithoutValidation(ethereumish, req); + } + + static async approve(ethereumish: Ethereumish, req: ApproveRequest) { + validateXdcApproveRequest(req); + return await EVMController.approveWithoutValidation(ethereumish, req); + } +} diff --git a/src/evm/evm.routes.ts b/src/evm/evm.routes.ts deleted file mode 100644 index d064a0c0ac..0000000000 --- a/src/evm/evm.routes.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* eslint-disable no-inner-declarations */ -/* eslint-disable @typescript-eslint/ban-types */ -import { Router, Request, Response } from 'express'; -import { Ethereumish } from '../services/common-interfaces'; -import { asyncHandler } from '../services/error-handler'; -import { - approve, - allowances, - nonce, - nextNonce, - cancel, -} from '../chains/ethereum/ethereum.controllers'; - -import { - validateAllowancesRequest, - validateApproveRequest, - validateCancelRequest, - validateNonceRequest, -} from '../chains/ethereum/ethereum.validators'; -import { - validateXdcApproveRequest, - validateXdcAllowancesRequest, -} from '../chains/xdc/xdc.validators'; - -import { getInitializedChain } from '../services/connection-manager'; -import { - AllowancesRequest, - AllowancesResponse, - ApproveRequest, - ApproveResponse, - CancelRequest, - CancelResponse, - NonceRequest, - NonceResponse, -} from './evm.requests'; - -export namespace EVMRoutes { - export const router = Router(); - - router.post( - '/nextNonce', - asyncHandler( - async ( - req: Request<{}, {}, NonceRequest>, - res: Response - ) => { - validateNonceRequest(req.body); - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await nextNonce(chain, req.body)); - } - ) - ); - - router.post( - '/nonce', - asyncHandler( - async ( - req: Request<{}, {}, NonceRequest>, - res: Response - ) => { - validateNonceRequest(req.body); - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await nonce(chain, req.body)); - } - ) - ); - - router.post( - '/allowances', - asyncHandler( - async ( - req: Request<{}, {}, AllowancesRequest>, - res: Response - ) => { - if (req.body.chain === 'xdc') { - validateXdcAllowancesRequest(req.body); - } else { - validateAllowancesRequest(req.body); - } - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await allowances(chain, req.body)); - } - ) - ); - - router.post( - '/approve', - asyncHandler( - async ( - req: Request<{}, {}, ApproveRequest>, - res: Response - ) => { - if (req.body.chain === 'xdc') { - validateXdcApproveRequest(req.body); - } else { - validateApproveRequest(req.body); - } - - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await approve(chain, req.body)); - } - ) - ); - - router.post( - '/cancel', - asyncHandler( - async ( - req: Request<{}, {}, CancelRequest>, - res: Response - ) => { - validateCancelRequest(req.body); - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - res.status(200).json(await cancel(chain, req.body)); - } - ) - ); -} diff --git a/src/network/network.controllers.ts b/src/network/network.controllers.ts index 9a5a7af320..8e17b35b8d 100644 --- a/src/network/network.controllers.ts +++ b/src/network/network.controllers.ts @@ -1,9 +1,4 @@ -import { - StatusRequest, - StatusResponse, - TokensRequest, - TokensResponse, -} from './network.requests'; +import { StatusRequest, StatusResponse } from './network.requests'; import { Avalanche } from '../chains/avalanche/avalanche'; import { BinanceSmartChain } from '../chains/binance-smart-chain/binance-smart-chain'; import { Ethereum } from '../chains/ethereum/ethereum'; @@ -16,10 +11,8 @@ import { UNKNOWN_CHAIN_ERROR_CODE, UNKNOWN_KNOWN_CHAIN_ERROR_MESSAGE, } from '../services/error-handler'; -import { EthereumBase, TokenInfo } from '../chains/ethereum/ethereum-base'; import { Cronos } from '../chains/cronos/cronos'; import { Near } from '../chains/near/near'; -import { Nearish, Xdcish } from '../services/common-interfaces'; import { Algorand } from '../chains/algorand/algorand'; import { getInitializedChain, @@ -127,43 +120,3 @@ export async function getStatus( return req.chain ? statuses[0] : statuses; } - -export async function getTokens(req: TokensRequest): Promise { - type connectionType = EthereumBase | Nearish | Injective | Xdcish; - let connection: connectionType; - let tokens: TokenInfo[] = []; - - if (req.chain && req.network) { - try { - connection = (await getInitializedChain( - req.chain as string, - req.network as string - )) as connectionType; - } catch (e) { - if (e instanceof UnsupportedChainException) { - throw new HttpException( - 500, - UNKNOWN_KNOWN_CHAIN_ERROR_MESSAGE(req.chain), - UNKNOWN_CHAIN_ERROR_CODE - ); - } - throw e; - } - } else { - throw new HttpException( - 500, - UNKNOWN_KNOWN_CHAIN_ERROR_MESSAGE(req.chain), - UNKNOWN_CHAIN_ERROR_CODE - ); - } - - if (!req.tokenSymbols) { - tokens = connection.storedTokenList; - } else { - for (const t of req.tokenSymbols as []) { - tokens.push(connection.getTokenForSymbol(t) as TokenInfo); - } - } - - return { tokens }; -} diff --git a/src/network/network.routes.ts b/src/network/network.routes.ts deleted file mode 100644 index 8abefae8d7..0000000000 --- a/src/network/network.routes.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ -import { NextFunction, Request, Response, Router } from 'express'; -import * as ethereumControllers from '../chains/ethereum/ethereum.controllers'; -import { Ethereumish } from '../services/common-interfaces'; -import { ConfigManagerV2 } from '../services/config-manager-v2'; -import { getInitializedChain } from '../services/connection-manager'; -import { asyncHandler } from '../services/error-handler'; -import { - mkRequestValidator, - RequestValidator, - validateTxHash, -} from '../services/validators'; -import { getStatus, getTokens } from './network.controllers'; -import { - BalanceRequest, - BalanceResponse, - PollRequest, - PollResponse, - StatusRequest, - StatusResponse, - TokensRequest, - TokensResponse, -} from './network.requests'; -import { - validateBalanceRequest as validateEthereumBalanceRequest, - validateChain as validateEthereumChain, - validateNetwork as validateEthereumNetwork, -} from '../chains/ethereum/ethereum.validators'; - -export const validatePollRequest: RequestValidator = mkRequestValidator([ - validateTxHash, -]); - -export const validateTokensRequest: RequestValidator = mkRequestValidator([ - validateEthereumChain, - validateEthereumNetwork, -]); - -export namespace NetworkRoutes { - export const router = Router(); - - router.get( - '/status', - asyncHandler( - async ( - req: Request<{}, {}, {}, StatusRequest>, - res: Response - ) => { - res.status(200).json(await getStatus(req.query)); - } - ) - ); - - router.get('/config', (_req: Request, res: Response) => { - res.status(200).json(ConfigManagerV2.getInstance().allConfigurations); - }); - - router.post( - '/balances', - asyncHandler( - async ( - req: Request<{}, {}, BalanceRequest>, - res: Response, - _next: NextFunction - ) => { - validateEthereumBalanceRequest(req.body); - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - - res - .status(200) - .json(await ethereumControllers.balances(chain, req.body)); - } - ) - ); - - router.post( - '/poll', - asyncHandler( - async ( - req: Request<{}, {}, PollRequest>, - res: Response - ) => { - validatePollRequest(req.body); - - const chain = await getInitializedChain( - req.body.chain, - req.body.network - ); - - res.status(200).json(await ethereumControllers.poll(chain, req.body)); - } - ) - ); - - router.get( - '/tokens', - asyncHandler( - async ( - req: Request<{}, {}, {}, TokensRequest>, - res: Response - ) => { - validateTokensRequest(req.query); - res.status(200).json(await getTokens(req.query)); - } - ) - ); -} diff --git a/src/services/base.ts b/src/services/base.ts index 772039c5db..7d152a7b50 100644 --- a/src/services/base.ts +++ b/src/services/base.ts @@ -71,8 +71,10 @@ export interface TokenValue { } // we should turn Token into a string when we return as a value in an API call -export const tokenValueToString = (t: TokenValue): string => { - return bigNumberWithDecimalToStr(t.value, t.decimals); +export const tokenValueToString = (t: TokenValue | string): string => { + return typeof t === 'string' + ? t + : bigNumberWithDecimalToStr(t.value, t.decimals); }; // safely parse a JSON from a string to a type. diff --git a/src/services/common-interfaces.ts b/src/services/common-interfaces.ts index d9ff980963..7418ae03d4 100644 --- a/src/services/common-interfaces.ts +++ b/src/services/common-interfaces.ts @@ -674,7 +674,8 @@ export interface BasicChainMethods { chain: string; } -export interface Ethereumish extends BasicChainMethods, EthereumBase { +export interface Chain extends BasicChainMethods, EthereumBase { + controller: any; cancelTx(wallet: Wallet, nonce: number): Promise; getContract( tokenAddress: string, @@ -682,6 +683,8 @@ export interface Ethereumish extends BasicChainMethods, EthereumBase { ): Contract; } +export type Ethereumish = Chain; + export interface Xdcish extends BasicChainMethods, XdcBase { cancelTx(wallet: XdcWallet, nonce: number): Promise; getContract( diff --git a/test-helpers/curl/curl.sh b/test-helpers/curl/curl.sh index bbaffbf6ec..1941928397 100644 --- a/test-helpers/curl/curl.sh +++ b/test-helpers/curl/curl.sh @@ -22,37 +22,37 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app # Network -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT https://localhost:15888/network/status | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT https://localhost:15888/chain/status | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=ethereum&network=goerli" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=ethereum&network=goerli" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=avalanche&network=avalanche" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=avalanche&network=avalanche" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=harmony&network=harmony" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=harmony&network=harmony" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=cronos&network=mainnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=cronos&network=mainnet" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=algorand&network=mainnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=algorand&network=mainnet" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT https://localhost:15888/network/config | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT https://localhost:15888/chain/config | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/network_poll.json)" https://localhost:15888/network/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/network_poll.json)" https://localhost:15888/chain/poll | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/tokens?chain=ethereum&network=goerli" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=ethereum&network=goerli" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/tokens?chain=polygon&network=mainnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=polygon&network=mainnet" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/tokens?chain=polygon&network=mumbai" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=polygon&network=mumbai" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/tokens?chain=cronos&network=mainnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=cronos&network=mainnet" | jq -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/tokens?chain=xdc&network=xinfin" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=xdc&network=xinfin" | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/network_balances.json)" https://localhost:15888/network/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/network_balances.json)" https://localhost:15888/chain/balances | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_balances.json)" https://localhost:15888/network/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_balances.json)" https://localhost:15888/chain/balances | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_balances.json)" https://localhost:15888/network/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_balances.json)" https://localhost:15888/chain/balances | jq # Wallet @@ -213,61 +213,61 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app # EVM ## nonce -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_nonce.json)" https://localhost:15888/evm/nonce | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_nonce.json)" https://localhost:15888/chain/nonce | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/avalanche_nonce.json)" https://localhost:15888/evm/nonce | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/avalanche_nonce.json)" https://localhost:15888/chain/nonce | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_nonce.json)" https://localhost:15888/evm/nonce | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_nonce.json)" https://localhost:15888/chain/nonce | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_nonce.json)" https://localhost:15888/evm/nonce | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_nonce.json)" https://localhost:15888/chain/nonce | jq ## allowances -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_allowances.json)" https://localhost:15888/evm/allowances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_allowances.json)" https://localhost:15888/chain/allowances | jq ## approve -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_approve.json)" https://localhost:15888/chain/approve | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_perp_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_perp_approve.json)" https://localhost:15888/chain/approve | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/avalanche_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/avalanche_approve.json)" https://localhost:15888/chain/approve | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_approve.json)" https://localhost:15888/chain/approve | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/bsc_approve.json)" https://localhost:15888/chain/approve | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_approve.json)" https://localhost:15888/chain/approve | jq # Algorand ## post poll -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_poll.json)" https://localhost:15888/algorand/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_poll.json)" https://localhost:15888/chain/poll | jq ## get balances -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_balances.json)" https://localhost:15888/algorand/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_balances.json)" https://localhost:15888/chain/balances | jq ## get assets -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/algorand/assets?network=mainnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?network=mainnet&chain=algorand" | jq ## post opt-in -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_opt_in.json)" https://localhost:15888/algorand/opt-in | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_opt_in.json)" https://localhost:15888/chain/approve | jq # NEAR ## get balances -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/near_network_balances.json)" https://localhost:15888/near/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/near_network_balances.json)" https://localhost:15888/chain/balances | jq ## get token -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/near/tokens?chain=near&network=testnet" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/tokens?chain=near&network=testnet" | jq ## post poll -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/near_post_poll.json)" https://localhost:15888/near/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/near_post_poll.json)" https://localhost:15888/chain/poll | jq # XDC and XSSWAP ## check for network status, let's us know that gateway knows about xdc -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/network/status?chain=xdc&network=apothem" | jq +curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/chain/status?chain=xdc&network=apothem" | jq ## add xdc private key curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/add_xdc_key.json)" https://localhost:15888/wallet/add | jq @@ -279,7 +279,7 @@ curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT https://localhost:1588 curl -s -X DELETE -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/remove_xdc_key.json)" https://localhost:15888/wallet/remove | jq ## test transaction polling -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_poll.json)" https://localhost:15888/network/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_poll.json)" https://localhost:15888/chain/poll | jq ## get xdc swap price curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_xdc_xsswap.json)" https://localhost:15888/amm/price | jq @@ -291,10 +291,10 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_xsswap_sell.json)" https://localhost:15888/amm/trade | jq ## allowances check -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_xsswap_allowances.json)" https://localhost:15888/evm/allowances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_xsswap_allowances.json)" https://localhost:15888/chain/allowances | jq ## approve -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_approve.json)" https://localhost:15888/evm/approve | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/xdc_approve.json)" https://localhost:15888/chain/approve | jq # CLOB @@ -368,19 +368,15 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT "https://localhost:15888/clob/perp/lastTradePrice?chain=injective&network=mainnet&connector=injective_perpetual&market=INJ-USDT" | jq ### get balances -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_balances.json)" https://localhost:15888/injective/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_balances.json)" https://localhost:15888/chain/balances | jq -### get block number -curl -s -X GET -k --key $GATEWAY_KEY --cert $GATEWAY_CERT 'https://localhost:15888/injective/block/current?chain=injective&network=mainnet' | jq - -### get transaction status -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_poll.json)" https://localhost:15888/injective/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_poll.json)" https://localhost:15888/chain/poll | jq ### transfer to bank -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_transfer_to_bank.json)" https://localhost:15888/injective/transfer/to/bank | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_transfer_to_bank.json)" https://localhost:15888/chain/transfer | jq ### transfer from bank -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_transfer_to_sub.json)" https://localhost:15888/injective/transfer/to/sub | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/injective_transfer_to_sub.json)" https://localhost:15888/chain/transfer | jq ## dexalot ### get markets @@ -408,7 +404,7 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/dexalot_batch_delete.json)" https://localhost:15888/clob/batchOrders | jq ### get balances -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/dexalot_balances.json)" https://localhost:15888/network/balances | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/dexalot_balances.json)" https://localhost:15888/chain/balances | jq ### get transaction status -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/dexalot_poll.json)" https://localhost:15888/network/poll | jq +curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/dexalot_poll.json)" https://localhost:15888/chain/poll | jq diff --git a/test-helpers/curl/requests/add_polygon_key.json.json b/test-helpers/curl/requests/add_polygon_key.json similarity index 100% rename from test-helpers/curl/requests/add_polygon_key.json.json rename to test-helpers/curl/requests/add_polygon_key.json diff --git a/test-helpers/curl/requests/eth_allowances.json b/test-helpers/curl/requests/eth_allowances.json index e6a2118c53..d693d95889 100644 --- a/test-helpers/curl/requests/eth_allowances.json +++ b/test-helpers/curl/requests/eth_allowances.json @@ -1,7 +1,7 @@ { "chain": "ethereum", - "network": "goerli", - "address": "$ETH_ADDRESS", + "network": "mainnet", + "address": "0x010216bB52E46807a07d0101Bb828bA547534F37", "spender": "uniswap", "tokenSymbols": ["DAI", "WETH"] } diff --git a/test-helpers/curl/requests/eth_nonce.json b/test-helpers/curl/requests/eth_nonce.json index a50dd6c245..81c81c6d9d 100644 --- a/test-helpers/curl/requests/eth_nonce.json +++ b/test-helpers/curl/requests/eth_nonce.json @@ -1,5 +1,5 @@ { "chain": "ethereum", - "network": "goerli", - "address": "$ETH_ADDRESS" + "network": "mainnet", + "address": "0x010216bB52E46807a07d0101Bb828bA547534F37" } diff --git a/test-helpers/curl/requests/injective_transfer_to_bank.json b/test-helpers/curl/requests/injective_transfer_to_bank.json index 0d0960311c..a17b7be6bf 100644 --- a/test-helpers/curl/requests/injective_transfer_to_bank.json +++ b/test-helpers/curl/requests/injective_transfer_to_bank.json @@ -2,7 +2,8 @@ "chain": "injective", "network": "mainnet", "connector": "injective", - "address": "$INJECTIVE_SUBACCOUNTID", + "to": "$INJECTIVE_ACCOUNTID", + "from": "$INJECTIVE_SUBACCOUNTID", "amount": "0.10", "token": "USDT" } diff --git a/test-helpers/curl/requests/injective_transfer_to_sub.json b/test-helpers/curl/requests/injective_transfer_to_sub.json index def67c247b..2500d35781 100644 --- a/test-helpers/curl/requests/injective_transfer_to_sub.json +++ b/test-helpers/curl/requests/injective_transfer_to_sub.json @@ -2,7 +2,8 @@ "chain": "injective", "network": "mainnet", "connector": "injective", - "address": "$INJECTIVE_SUBACCOUNTID", + "from": "$INJECTIVE_ACCOUNTID", + "to": "$INJECTIVE_SUBACCOUNTID", "amount": "0.123", "token": "USDT" } diff --git a/test/chains/ethereum/ethereum.controllers.test.ts b/test/chains/ethereum/ethereum.controllers.test.ts index 44fc213d58..6a1fc7d960 100644 --- a/test/chains/ethereum/ethereum.controllers.test.ts +++ b/test/chains/ethereum/ethereum.controllers.test.ts @@ -2,16 +2,6 @@ import { BigNumber } from 'ethers'; import { Ethereum } from '../../../src/chains/ethereum/ethereum'; import { patch, unpatch } from '../../services/patch'; import { TokenInfo } from '../../../src/chains/ethereum/ethereum-base'; -import { - nonce, - nextNonce, - getTokenSymbolsToTokens, - allowances, - approve, - balances, - cancel, - willTxSucceed, -} from '../../../src/chains/ethereum/ethereum.controllers'; import { HttpException, LOAD_WALLET_ERROR_CODE, @@ -20,6 +10,10 @@ import { TOKEN_NOT_SUPPORTED_ERROR_CODE, } from '../../../src/services/error-handler'; import { patchEVMNonceManager } from '../../evm.nonce.mock'; +import { + EVMController, + willTxSucceed, +} from '../../../src/chains/ethereum/evm.controllers'; let eth: Ethereum; beforeAll(async () => { @@ -53,7 +47,7 @@ describe('nonce', () => { }; }); patch(eth.nonceManager, 'getNonce', () => 2); - const n = await nonce(eth, { + const n = await EVMController.nonce(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -68,7 +62,7 @@ describe('nonce', () => { }; }); patch(eth.nonceManager, 'getNextNonce', () => 3); - const n = await nextNonce(eth, { + const n = await EVMController.nextNonce(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -89,7 +83,9 @@ describe('getTokenSymbolsToTokens', () => { patch(eth, 'getTokenBySymbol', () => { return weth; }); - expect(getTokenSymbolsToTokens(eth, ['WETH'])).toEqual({ WETH: weth }); + expect(EVMController.getTokenSymbolsToTokens(eth, ['WETH'])).toEqual({ + WETH: weth, + }); }); }); @@ -118,7 +114,7 @@ describe('allowances', () => { }; }); - const result = await allowances(eth, { + const result = await EVMController.allowances(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -159,7 +155,7 @@ describe('approve', () => { }; }); - const result = await approve(eth, { + const result = await EVMController.approve(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -180,7 +176,7 @@ describe('approve', () => { }); await expect( - approve(eth, { + EVMController.approve(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -212,7 +208,7 @@ describe('approve', () => { }); await expect( - approve(eth, { + EVMController.approve(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -237,7 +233,7 @@ describe('balances', () => { }); await expect( - balances(eth, { + EVMController.balances(eth, { chain: 'ethereum', network: 'goerli', address: zeroAddress, @@ -261,7 +257,7 @@ describe('cancel', () => { }); await expect( - cancel(eth, { + EVMController.cancel(eth, { chain: 'ethereum', network: 'goerli', nonce: 123, diff --git a/test/chains/ethereum/evm.nonce.test.ts b/test/chains/ethereum/evm.nonce.test.ts index ceda3f1a03..edf369ffb5 100644 --- a/test/chains/ethereum/evm.nonce.test.ts +++ b/test/chains/ethereum/evm.nonce.test.ts @@ -12,7 +12,7 @@ import { SERVICE_UNITIALIZED_ERROR_CODE, SERVICE_UNITIALIZED_ERROR_MESSAGE, } from '../../../src/services/error-handler'; -import { EVMNonceManager } from '../../../src/evm/evm.nonce'; +import { EVMNonceManager } from '../../../src/chains/ethereum/evm.nonce'; import { patch, unpatch } from '../../services/patch'; import 'jest-extended'; diff --git a/test/chains/harmony/harmony.controllers.test.ts b/test/chains/harmony/harmony.controllers.test.ts index b5aad06de8..f15f93a670 100644 --- a/test/chains/harmony/harmony.controllers.test.ts +++ b/test/chains/harmony/harmony.controllers.test.ts @@ -2,15 +2,6 @@ import { BigNumber } from 'ethers'; import { Harmony } from '../../../src/chains/harmony/harmony'; import { patch, unpatch } from '../../services/patch'; import { TokenInfo } from '../../../src/chains/ethereum/ethereum-base'; -import { - nonce, - getTokenSymbolsToTokens, - allowances, - approve, - balances, - cancel, - willTxSucceed, -} from '../../../src/chains/ethereum/ethereum.controllers'; import { HttpException, LOAD_WALLET_ERROR_CODE, @@ -19,6 +10,10 @@ import { TOKEN_NOT_SUPPORTED_ERROR_CODE, } from '../../../src/services/error-handler'; import { patchEVMNonceManager } from '../../evm.nonce.mock'; +import { + EVMController, + willTxSucceed, +} from '../../../src/chains/ethereum/evm.controllers'; jest.useFakeTimers(); let harmony: Harmony; @@ -52,7 +47,7 @@ describe('nonce', () => { }; }); patch(harmony.nonceManager, 'getNonce', () => 2); - const n = await nonce(harmony, { + const n = await EVMController.nonce(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -73,7 +68,9 @@ describe('getTokenSymbolsToTokens', () => { patch(harmony, 'getTokenBySymbol', () => { return wone; }); - expect(getTokenSymbolsToTokens(harmony, ['WONE'])).toEqual({ WONE: wone }); + expect(EVMController.getTokenSymbolsToTokens(harmony, ['WONE'])).toEqual({ + WONE: wone, + }); }); }); @@ -102,7 +99,7 @@ describe('allowances', () => { }; }); - const result = await allowances(harmony, { + const result = await EVMController.allowances(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -143,7 +140,7 @@ describe('approve', () => { }; }); - const result = await approve(harmony, { + const result = await EVMController.approve(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -164,7 +161,7 @@ describe('approve', () => { }); await expect( - approve(harmony, { + EVMController.approve(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -196,7 +193,7 @@ describe('approve', () => { }); await expect( - approve(harmony, { + EVMController.approve(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -221,7 +218,7 @@ describe('balances', () => { }); await expect( - balances(harmony, { + EVMController.balances(harmony, { chain: 'harmony', network: 'testnet', address: zeroAddress, @@ -245,7 +242,7 @@ describe('cancel', () => { }); await expect( - cancel(harmony, { + EVMController.cancel(harmony, { chain: 'harmony', network: 'testnet', nonce: 123, diff --git a/test/chains/near/near.controllers.test.ts b/test/chains/near/near.controllers.test.ts index 6caec96273..d2ccf558b9 100644 --- a/test/chains/near/near.controllers.test.ts +++ b/test/chains/near/near.controllers.test.ts @@ -1,12 +1,6 @@ import { Near } from '../../../src/chains/near/near'; import { TokenInfo } from '../../../src/chains/near/near.base'; -import { - balances, - cancel, - getTokenSymbolsToTokens, - poll, -} from '../../../src/chains/near/near.controllers'; -import { PollResponse } from '../../../src/chains/near/near.requests'; +import { NearController } from '../../../src/chains/near/near.controllers'; import { Nearish } from '../../../src/services/common-interfaces'; import { HttpException, @@ -50,9 +44,11 @@ describe('poll', () => { it('return transaction data for given signature', async () => { patchGetCurrentBlockNumber(); patchGetTransaction(); - const n: PollResponse = await poll(near, publicKey, txHash); - expect(n.network).toBe(near.network); - expect(n.timestamp).toBeNumber(); + const n = await NearController.poll(near, { + address: publicKey, + txHash, + network: '', + }); expect(n.currentBlock).toBe(CurrentBlockNumber); expect(n.txHash).toBe(txHash); expect(n.txStatus).toBe(1); @@ -67,7 +63,7 @@ describe('balances', () => { }); await expect( - balances(near, { + NearController.balances(near, { chain: 'near', network: 'testnet', address: publicKey, @@ -91,7 +87,7 @@ describe('cancel', () => { }); await expect( - cancel(near, { + NearController.cancel(near, { chain: 'near', network: 'testnet', nonce: 123, @@ -119,6 +115,8 @@ describe('getTokenSymbolsToTokens', () => { patch(near, 'getTokenBySymbol', () => { return eth; }); - expect(getTokenSymbolsToTokens(near, ['ETH'])).toEqual({ ETH: eth }); + expect(NearController.getTokenSymbolsToTokens(near, ['ETH'])).toEqual({ + ETH: eth, + }); }); }); diff --git a/test/evm.nonce.mock.ts b/test/evm.nonce.mock.ts index 8b94337697..f2232d44a6 100644 --- a/test/evm.nonce.mock.ts +++ b/test/evm.nonce.mock.ts @@ -1,5 +1,5 @@ import { patch } from './services/patch'; -import { EVMNonceManager } from '../src/evm/evm.nonce'; +import { EVMNonceManager } from '../src/chains/ethereum/evm.nonce'; // override values so that nonceManager doesn't crash due to lack of provider // connection diff --git a/test/services/evm.nonce.test.ts b/test/services/evm.nonce.test.ts index a5e375d8ab..541f90de8a 100644 --- a/test/services/evm.nonce.test.ts +++ b/test/services/evm.nonce.test.ts @@ -9,7 +9,7 @@ import { EVMNonceManager, // NonceInfo, // NonceLocalStorage, -} from '../../src/evm/evm.nonce'; +} from '../../src/chains/ethereum/evm.nonce'; // import { ReferenceCountingCloseable } from '../../src/services/refcounting-closeable'; import { patch } from './patch'; diff --git a/test/services/evm.tx-storage.test.ts b/test/services/evm.tx-storage.test.ts index 35d4bbf405..7e4b6fc86d 100644 --- a/test/services/evm.tx-storage.test.ts +++ b/test/services/evm.tx-storage.test.ts @@ -3,7 +3,7 @@ import fsp from 'fs/promises'; import fse from 'fs-extra'; import os from 'os'; import path from 'path'; -import { EvmTxStorage } from '../../src/evm/evm.tx-storage'; +import { EvmTxStorage } from '../../src/chains/ethereum/evm.tx-storage'; import 'jest-extended'; import { ReferenceCountingCloseable } from '../../src/services/refcounting-closeable'; From 1bf611e1ccb5c887ed894b123f37d3ccc41cdab0 Mon Sep 17 00:00:00 2001 From: david-hummingbot <85695272+david-hummingbot@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:44:49 +0800 Subject: [PATCH 06/17] Update CONTRIBUTING.md - minor changes to contribution guidelines --- CONTRIBUTING.md | 136 ++++++++++++++++-------------------------------- 1 file changed, 45 insertions(+), 91 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 195b88610e..416ea25ff1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,50 +1,50 @@ # Contribution Guidelines -## General workflow +## General Workflow -1. Fork the [hummingbot/gateway](https://github.com/hummingbot/gateway) repository. +1. Fork the `hummingbot/gateway` repository. 2. Create a new branch from the `development` branch in your fork. -3. Make commits to your branch. -4. When you have finished with your fix / feature / connector / documentation: +3. Commit your changes to your branch. +4. Once you've completed your fix, feature, connector, or documentation: - - Rebase upstream changes into your branch - - Create a pull request to the `development` branch - - Include a description of your changes - - Ensure to **Allow edits by maintainers** before submitting the pull request + - Rebase upstream changes into your branch. + - Create a pull request to the `development` branch. + - Include a detailed description of your changes. + - Ensure to `allow edits by maintainers` before submitting the pull request. -5. Your code changes will be reviewed/tested by Hummingbot Foundation's engineering and QA teams. -6. Fix any changes requested by your reviewers and testers, and push your fixes as a single new commit. -7. Once the pull request has been approved, it will be merged by a member of the Hummingbot Foundation team. +5. Your code changes will be reviewed and tested by the Foundation QA team. +6. Address any changes requested by your reviewer, fix issues raised, and push your fixes as a single new commit. +7. Once the pull request has been reviewed and accepted, it will be merged by a member of the Hummingbot Foundation team. -**NOTE:** Tests are very important. Submit tests if your pull request contains new, testable behavior. See [Unit test coverage](#unit-test-coverage) for more information. +**Note:** Tests are crucial. If your pull request contains new, testable behavior, please submit tests. Refer to the 'Unit Test Coverage' section for more information. -## Detailed workflow +## Detailed Workflow -### 1. Fork the repository +### 1. Fork the Repository -Use GitHub's interface to make a fork of the repo, add the Gateway repo as an upstream remote, and fetch upstream data: +Use GitHub's interface to fork the repo, add the Hummingbot repo as an upstream remote, and fetch upstream data: -``` +```bash git remote add upstream https://github.com/hummingbot/gateway.git git fetch upstream ``` -### 2. Creating your branch +### 2. Create Your Branch -Create your local branch and should follow this naming convention: +Create your local branch following this naming convention: -- feat/ ... -- fix/ ... -- refactor/ ... -- doc/ ... +- feat/... +- fix/... +- refactor/... +- doc/... -Create and switch to a new local branch called `feat/[branch_name]` based on `development` of the remote `upstream`. +Create and switch to a new local branch called feat/[branch_name] based on the development branch of the remote upstream: -``` +```bash git checkout -b feat/[branch_name] upstream/development ``` -### 3. Commit changes to a branch +### 3. Commit Changes to Your Branch Make commits to your branch. Prefix each commit like so: @@ -54,89 +54,43 @@ Make commits to your branch. Prefix each commit like so: - (cleanup) ... - (doc) ... -Make changes and commits on your branch, and make sure that you only make relevant changes. If you find yourself making unrelated changes, create a new branch for those changes. +Commit messages should be written in the present tense, e.g., "(feat) add unit tests". The first line of your commit message should be a summary of what the commit changes, aiming for about 70 characters max. If you want to explain the commit in more depth, provide a more detailed description after a blank line following the first line. -Commit message guidelines: +### 4. Rebase Upstream Changes -- Commit messages should be written in the present tense, e.g. "(feat) add unit tests". -- The first line of your commit message should be a summary of what the commit changes. Aim for about 70 characters max. Remember: This is a summary, not a detailed description of everything that changed. -- If you want to explain the commit in more depth, following the first line should be blank and then a more detailed description of the commit. This can be as detailed as you want, so dig into details here and keep the first line short. - -### 4. Rebase upstream changes - -Once you are done making changes, you can begin the process of getting -your code merged into the main repo. Step 1 is to rebase upstream -changes to the `development` branch into yours by running this command -from your branch: +Rebase upstream changes to the development branch into yours by running this command from your branch: ```bash git pull --rebase upstream development ``` -This will start the rebase process. You must commit all of your changes -before doing this. If there are no conflicts, this should just roll all -of your changes back on top of the changes from upstream, leading to a -nice, clean, linear commit history. - -If there are conflicting changes, git will start yelling at you part way -through the rebasing process. Git will pause rebasing to allow you to sort -out the conflicts. You do this the same way you solve merge conflicts, -by checking all of the files git says have been changed in both histories -and picking the versions you want. Be aware that these changes will show -up in your pull request, so try and incorporate upstream changes as much -as possible. - -You pick a file by `git add`ing it - you do not make commits during a -rebase. - -Once you are done fixing conflicts for a specific commit, run: +If there are conflicting changes, git will pause rebasing to allow you to sort out the conflicts. Once you are done fixing conflicts for a specific commit, run: ```bash git rebase --continue ``` -This will continue the rebasing process. Once you are done fixing all -conflicts you should run the existing tests to make sure you didn’t break -anything, then run your new tests (there are new tests, right?) and -make sure they work also. - -If rebasing broke anything, fix it, then repeat the above process until -you get here again and nothing is broken and all the tests pass. - -### 5. Create a pull request - -Make a clear pull request from your fork and branch to the upstream `development` -branch, detailing exactly what changes you made and what feature this -should add. The clearer your pull request is the faster you can get -your changes incorporated into this repo. - -It is important to check **Allow edits by maintainers** for the Hummingbot Foundation team to update your branch with `development` whenever needed. - -If the development team requests changes, you should make more commits to your -branch to address these, then follow this process again from rebasing onwards. +Ensure all tests pass after rebasing. -Once you get back here, make a comment requesting further review and -someone will look at your code again. If it addresses the requests, it will -get merged, else, just repeat again. +### 5. Create a Pull Request -Thanks for contributing! +Create a clear pull request from your fork and branch to the upstream `development` branch, detailing your changes. Check 'Allow edits by maintainers' for the Foundation team to update your branch with development whenever needed. -## Unit test coverage +If the Foundation team requests changes, make more commits to your branch to address these, then follow this process again from rebasing onwards. Once you've addressed the requests, request further review. -It is required to present a minimum unit test coverage for the changes included in a pull request. Some components may be excluded from this validation. To calculate the diff-coverage locally on your computer, run `yarn tes:cov`. +## Unit Test Coverage -## Checklist: +A minimum of 75% unit test coverage is required for all changes included in a pull request. Some components may be excluded from this validation. -This is just to help you organize your process +To calculate the diff-coverage locally on your computer, run `yarn test:cov`. -- [ ] Did I create my branch from `development` (don't create new branches from existing feature branches)? -- [ ] Did I follow the correct naming convention for my branch? -- [ ] Is my branch focused on a single main change? - - [ ] Do all of my changes directly relate to this change? -- [ ] Did I rebase the upstream `development` branch after I finished all my - work? -- [ ] Did I write a clear pull request message detailing what changes I made? -- [ ] Did I get a code review? - - [ ] Did I make any requested changes from that code review? +## Checklist -If you follow all of these guidelines and make good changes, you should have no problem getting your changes merged in. +- Did I create my branch from `development` (don't create new branches from existing feature branches)? +- Did I follow the correct naming convention for my branch? +- Is my branch focused on a single main change? +- Do all of my changes directly relate to this change? +- Did I rebase the upstream development branch after I finished all my work? +- Did I write a clear pull request message detailing what changes I made? +- Did I get a code review? +- Did I make any requested changes from that code review? From c59e5c2179496c45a8dda137e3fd0268fe013030 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Tue, 11 Jul 2023 16:45:53 -0700 Subject: [PATCH 07/17] dont use router in uniswaplp --- src/connectors/uniswap/uniswap.lp.helper.ts | 85 +++++++++++---------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/connectors/uniswap/uniswap.lp.helper.ts b/src/connectors/uniswap/uniswap.lp.helper.ts index a5728384a4..5ce58f146d 100644 --- a/src/connectors/uniswap/uniswap.lp.helper.ts +++ b/src/connectors/uniswap/uniswap.lp.helper.ts @@ -7,7 +7,7 @@ import { UniswapConfig } from './uniswap.config'; import { Contract, ContractInterface } from '@ethersproject/contracts'; import { Token, - Fraction, + // Fraction, CurrencyAmount, Percent, Price, @@ -15,8 +15,8 @@ import { import * as uniV3 from '@uniswap/v3-sdk'; import { AlphaRouter, - SwapToRatioResponse, - SwapToRatioStatus, + // SwapToRatioResponse, + // SwapToRatioStatus, } from '@uniswap/smart-order-router'; import { providers, Wallet, Signer, utils } from 'ethers'; import { percentRegexp } from '../../services/config-manager-v2'; @@ -384,44 +384,47 @@ export class UniswapLPHelper { useFullPrecision: true, }); - const autorouterRoute: SwapToRatioResponse = - await this.alphaRouter.routeToRatio( - CurrencyAmount.fromRawAmount( - token0, - utils.parseUnits(amount0, token0.decimals).toString() - ), - CurrencyAmount.fromRawAmount( - token1, - utils.parseUnits(amount1, token1.decimals).toString() - ), - position, - { - ratioErrorTolerance: new Fraction(1, 100), - maxIterations: 6, - }, - { - swapOptions: swapOptions, - addLiquidityOptions: addLiquidityOptions, - } - ); - - let methodParameters: uniV3.MethodParameters; - let swapReq = false; - if (autorouterRoute.status === SwapToRatioStatus.SUCCESS) { - swapReq = true; - methodParameters = autorouterRoute.result - .methodParameters as uniV3.MethodParameters; - } else if (autorouterRoute.status === SwapToRatioStatus.NO_SWAP_NEEDED) { - methodParameters = uniV3.NonfungiblePositionManager.addCallParameters( - position, - { ...swapOptions, ...addLiquidityOptions } - ); - } else { - throw new Error( - `Unable to add liquidity - ${SwapToRatioStatus[autorouterRoute.status]}` - ); - } - return { ...methodParameters, swapRequired: swapReq }; + // const autorouterRoute: SwapToRatioResponse = + // await this.alphaRouter.routeToRatio( + // CurrencyAmount.fromRawAmount( + // token0, + // utils.parseUnits(amount0, token0.decimals).toString() + // ), + // CurrencyAmount.fromRawAmount( + // token1, + // utils.parseUnits(amount1, token1.decimals).toString() + // ), + // position, + // { + // ratioErrorTolerance: new Fraction(1, 100), + // maxIterations: 6, + // }, + // { + // swapOptions: swapOptions, + // addLiquidityOptions: addLiquidityOptions, + // } + // ); + // let methodParameters: uniV3.MethodParameters; + // let swapReq = false; + // if (autorouterRoute.status === SwapToRatioStatus.SUCCESS) { + // swapReq = true; + // methodParameters = autorouterRoute.result + // .methodParameters as uniV3.MethodParameters; + // } else if (autorouterRoute.status === SwapToRatioStatus.NO_SWAP_NEEDED) { + // methodParameters = uniV3.NonfungiblePositionManager.addCallParameters( + // position, + // { ...swapOptions, ...addLiquidityOptions } + // ); + // } else { + // throw new Error( + // `Unable to add liquidity - ${SwapToRatioStatus[autorouterRoute.status]}` + // ); + // } + const methodParameters = uniV3.NonfungiblePositionManager.addCallParameters( + position, + { ...swapOptions, ...addLiquidityOptions } + ); + return { ...methodParameters, swapRequired: false }; } async reducePositionHelper( From f0486b5b2c14633c0fba81750a5d4548962ece8a Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Thu, 13 Jul 2023 15:59:21 -0700 Subject: [PATCH 08/17] remove commented code --- src/connectors/uniswap/uniswap.lp.helper.ts | 50 +-------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/src/connectors/uniswap/uniswap.lp.helper.ts b/src/connectors/uniswap/uniswap.lp.helper.ts index 5ce58f146d..bd50ac5d4c 100644 --- a/src/connectors/uniswap/uniswap.lp.helper.ts +++ b/src/connectors/uniswap/uniswap.lp.helper.ts @@ -5,19 +5,9 @@ import { } from '../../services/error-handler'; import { UniswapConfig } from './uniswap.config'; import { Contract, ContractInterface } from '@ethersproject/contracts'; -import { - Token, - // Fraction, - CurrencyAmount, - Percent, - Price, -} from '@uniswap/sdk-core'; +import { Token, CurrencyAmount, Percent, Price } from '@uniswap/sdk-core'; import * as uniV3 from '@uniswap/v3-sdk'; -import { - AlphaRouter, - // SwapToRatioResponse, - // SwapToRatioStatus, -} from '@uniswap/smart-order-router'; +import { AlphaRouter } from '@uniswap/smart-order-router'; import { providers, Wallet, Signer, utils } from 'ethers'; import { percentRegexp } from '../../services/config-manager-v2'; import { Ethereum } from '../../chains/ethereum/ethereum'; @@ -384,42 +374,6 @@ export class UniswapLPHelper { useFullPrecision: true, }); - // const autorouterRoute: SwapToRatioResponse = - // await this.alphaRouter.routeToRatio( - // CurrencyAmount.fromRawAmount( - // token0, - // utils.parseUnits(amount0, token0.decimals).toString() - // ), - // CurrencyAmount.fromRawAmount( - // token1, - // utils.parseUnits(amount1, token1.decimals).toString() - // ), - // position, - // { - // ratioErrorTolerance: new Fraction(1, 100), - // maxIterations: 6, - // }, - // { - // swapOptions: swapOptions, - // addLiquidityOptions: addLiquidityOptions, - // } - // ); - // let methodParameters: uniV3.MethodParameters; - // let swapReq = false; - // if (autorouterRoute.status === SwapToRatioStatus.SUCCESS) { - // swapReq = true; - // methodParameters = autorouterRoute.result - // .methodParameters as uniV3.MethodParameters; - // } else if (autorouterRoute.status === SwapToRatioStatus.NO_SWAP_NEEDED) { - // methodParameters = uniV3.NonfungiblePositionManager.addCallParameters( - // position, - // { ...swapOptions, ...addLiquidityOptions } - // ); - // } else { - // throw new Error( - // `Unable to add liquidity - ${SwapToRatioStatus[autorouterRoute.status]}` - // ); - // } const methodParameters = uniV3.NonfungiblePositionManager.addCallParameters( position, { ...swapOptions, ...addLiquidityOptions } From 8d63bb2c4b9aa247bd99b6d34f2f4f8e8886c0f0 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Thu, 13 Jul 2023 16:10:07 -0700 Subject: [PATCH 09/17] replace workflow lists path --- .github/workflows/workflow.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index f79ceedc1f..b1229ef70d 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -73,10 +73,11 @@ jobs: - name: Build project run: yarn build - - name: Replace testnet nodeURL for local hardhat node + - name: Replace testnet nodeURL and lists path run: | mkdir conf db - cp -r src/templates/* conf + cp -rf src/templates/* conf + sed -i 's|/home/gateway/conf/lists/|/conf/lists/|g' ./conf/*.yml sed -i 's/https:\/\/rpc.ankr.com\/eth_goerli/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml sed -i 's/https:\/\/arbitrum-rinkeby.infura.io\/v3/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml sed -i 's/https:\/\/rpc.ankr.com\/optimism/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml From 23edc3f9d47ab1c65f20b994295f3a41eb922509 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Thu, 13 Jul 2023 16:16:30 -0700 Subject: [PATCH 10/17] fix folder link --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index b1229ef70d..9f1c6a4f25 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -77,7 +77,7 @@ jobs: run: | mkdir conf db cp -rf src/templates/* conf - sed -i 's|/home/gateway/conf/lists/|/conf/lists/|g' ./conf/*.yml + sed -i 's|/home/gateway/conf/lists/|conf/lists/|g' ./conf/*.yml sed -i 's/https:\/\/rpc.ankr.com\/eth_goerli/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml sed -i 's/https:\/\/arbitrum-rinkeby.infura.io\/v3/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml sed -i 's/https:\/\/rpc.ankr.com\/optimism/http:\/\/127.0.0.1:8545\//g' ./conf/ethereum.yml From 5ec7cadd2b8dc3d6d85ef0defbed326e2666aa06 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Sat, 15 Jul 2023 16:22:52 -0700 Subject: [PATCH 11/17] (feat) copy lists upon startup --- src/services/config-manager-v2.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/services/config-manager-v2.ts b/src/services/config-manager-v2.ts index b891142c69..5e11305117 100644 --- a/src/services/config-manager-v2.ts +++ b/src/services/config-manager-v2.ts @@ -269,6 +269,13 @@ export class ConfigManagerV2 { // copy from template fs.copyFileSync(path.join(ConfigTemplatesDir, 'root.yml'), rootPath); } + + const listsPath = path.join(ConfigDir, 'lists'); + if (!fs.existsSync(listsPath)) { + // copy from template + fse.copySync(path.join(ConfigTemplatesDir, 'lists'), listsPath); + } + ConfigManagerV2._instance = new ConfigManagerV2(rootPath); } return ConfigManagerV2._instance; From ce7ddd1b464a367f0c8b60ec55ee487c0ba6caa1 Mon Sep 17 00:00:00 2001 From: nikita Date: Mon, 17 Jul 2023 06:26:57 +0000 Subject: [PATCH 12/17] delete_zig_zag_defikingdoms --- jest.config.js | 1 - src/chains/ethereum/ethereum.validators.ts | 2 - src/chains/harmony/harmony.ts | 4 +- src/chains/harmony/harmony.validators.ts | 2 - src/connectors/connectors.routes.ts | 13 - .../defikingdoms/defikingdoms.config.ts | 33 - src/connectors/defikingdoms/defikingdoms.ts | 291 --- .../defikingdoms/defikingdoms_router_abi.json | 1625 ----------------- src/connectors/zigzag/zigzag.config.ts | 32 - src/connectors/zigzag/zigzag.controllers.ts | 233 --- .../zigzag/zigzag.exchange.abi.json | 725 -------- src/connectors/zigzag/zigzag.ts | 410 ----- src/services/common-interfaces.ts | 40 - src/services/connection-manager.ts | 6 - src/services/schema/defikingdoms-schema.json | 25 - src/services/schema/zigzag-schema.json | 23 - src/templates/defikingdoms.yml | 14 - src/templates/root.yml | 8 - src/templates/zigzag.yml | 4 - test-helpers/curl/curl.sh | 8 - .../curl/requests/eth_zigzag_trade.json | 10 - .../curl/requests/harmony_dfk_trade.json | 10 - test-helpers/curl/requests/price_dfk.json | 9 - test-helpers/curl/requests/price_zigzag.json | 9 - test/chains/harmony/harmony.test.ts | 9 - .../defikingdoms/defikingdoms.routes.test.ts | 669 ------- .../defikingdoms/defikingdoms.test.ts | 151 -- test/connectors/zigzag/zigzag.test.ts | 435 ----- 28 files changed, 1 insertion(+), 4800 deletions(-) delete mode 100644 src/connectors/defikingdoms/defikingdoms.config.ts delete mode 100644 src/connectors/defikingdoms/defikingdoms.ts delete mode 100644 src/connectors/defikingdoms/defikingdoms_router_abi.json delete mode 100644 src/connectors/zigzag/zigzag.config.ts delete mode 100644 src/connectors/zigzag/zigzag.controllers.ts delete mode 100644 src/connectors/zigzag/zigzag.exchange.abi.json delete mode 100644 src/connectors/zigzag/zigzag.ts delete mode 100644 src/services/schema/defikingdoms-schema.json delete mode 100644 src/services/schema/zigzag-schema.json delete mode 100644 src/templates/defikingdoms.yml delete mode 100644 src/templates/zigzag.yml delete mode 100644 test-helpers/curl/requests/eth_zigzag_trade.json delete mode 100644 test-helpers/curl/requests/harmony_dfk_trade.json delete mode 100644 test-helpers/curl/requests/price_dfk.json delete mode 100644 test-helpers/curl/requests/price_zigzag.json delete mode 100644 test/connectors/defikingdoms/defikingdoms.routes.test.ts delete mode 100644 test/connectors/defikingdoms/defikingdoms.test.ts delete mode 100644 test/connectors/zigzag/zigzag.test.ts diff --git a/jest.config.js b/jest.config.js index dd748e9226..f72369feda 100644 --- a/jest.config.js +++ b/jest.config.js @@ -21,7 +21,6 @@ module.exports = { 'src/connectors/uniswap/uniswap.config.ts', 'src/connectors/uniswap/uniswap.ts', 'src/connectors/uniswap/uniswap.lp.helper.ts', - 'src/connectors/defikingdoms/defikingdoms.ts', 'src/connectors/defira/defira.ts', 'src/connectors/openocean/openocean.ts', 'src/connectors/pangolin/pangolin.ts', diff --git a/src/chains/ethereum/ethereum.validators.ts b/src/chains/ethereum/ethereum.validators.ts index d8d8e9f672..78d7df8454 100644 --- a/src/chains/ethereum/ethereum.validators.ts +++ b/src/chains/ethereum/ethereum.validators.ts @@ -57,13 +57,11 @@ export const validateSpender: Validator = mkValidator( val === 'viperswap' || val === 'openocean' || val === 'quickswap' || - val === 'defikingdoms' || val === 'defira' || val === 'mad_meerkat' || val === 'vvs' || val === 'pancakeswap' || val === 'xsswap' || - val === 'zigzag' || isAddress(val)) ); diff --git a/src/chains/harmony/harmony.ts b/src/chains/harmony/harmony.ts index fb994ca795..9a1288cde9 100644 --- a/src/chains/harmony/harmony.ts +++ b/src/chains/harmony/harmony.ts @@ -146,9 +146,7 @@ export class Harmony extends EthereumBase implements Ethereumish { getSpender(reqSpender: string): string { let spender: string; - if (reqSpender === 'defikingdoms') { - spender = '0x24ad62502d1C652Cc7684081169D04896aC20f30'; - } else if (reqSpender === 'defira') { + if (reqSpender === 'defira') { spender = '0x3C8BF7e25EbfAaFb863256A4380A8a93490d8065'; } else if (reqSpender === 'openocean') { spender = OpenoceanConfig.config.routerAddress('ethereum', this._chain); diff --git a/src/chains/harmony/harmony.validators.ts b/src/chains/harmony/harmony.validators.ts index 44ac944a5d..c3111bd5e5 100644 --- a/src/chains/harmony/harmony.validators.ts +++ b/src/chains/harmony/harmony.validators.ts @@ -43,8 +43,6 @@ export const validateSpender: Validator = mkValidator( (val) => typeof val === 'string' && (val === 'sushiswap' || - val === 'viperswap' || - val === 'defikingdoms' || val === 'defira' || val === 'openocean' || isValidAddress(val)) diff --git a/src/connectors/connectors.routes.ts b/src/connectors/connectors.routes.ts index 7cf67624c0..b05f53d52b 100644 --- a/src/connectors/connectors.routes.ts +++ b/src/connectors/connectors.routes.ts @@ -3,7 +3,6 @@ import { Router, Response } from 'express'; import { asyncHandler } from '../services/error-handler'; import { DefiraConfig } from './defira/defira.config'; -import { DefikingdomsConfig } from './defikingdoms/defikingdoms.config'; import { MadMeerkatConfig } from './mad_meerkat/mad_meerkat.config'; import { OpenoceanConfig } from './openocean/openocean.config'; import { PangolinConfig } from './pangolin/pangolin.config'; @@ -81,12 +80,6 @@ export namespace ConnectorsRoutes { chain_type: TraderjoeConfig.config.chainType, available_networks: TraderjoeConfig.config.availableNetworks, }, - { - name: 'defikingdoms', - trading_type: DefikingdomsConfig.config.tradingTypes, - chain_type: DefikingdomsConfig.config.chainType, - available_networks: DefikingdomsConfig.config.availableNetworks, - }, { name: 'defira', trading_type: DefiraConfig.config.tradingTypes, @@ -153,12 +146,6 @@ export namespace ConnectorsRoutes { 'Enter a Dexalot API Key if you have one, otherwise hit return >>> ', }, }, - { - name: 'zigzag', - trading_type: ZigZagConfig.config.tradingTypes, - chain_type: ZigZagConfig.config.chainType, - available_networks: ZigZagConfig.config.availableNetworks, - }, { name: 'tinyman', trading_type: TinymanConfig.config.tradingTypes, diff --git a/src/connectors/defikingdoms/defikingdoms.config.ts b/src/connectors/defikingdoms/defikingdoms.config.ts deleted file mode 100644 index cd6ffd041c..0000000000 --- a/src/connectors/defikingdoms/defikingdoms.config.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ConfigManagerV2 } from '../../services/config-manager-v2'; -import { AvailableNetworks } from '../../services/config-manager-types'; -export namespace DefikingdomsConfig { - export interface NetworkConfig { - allowedSlippage: string; - gasLimit: number; - ttl: number; - routerAddress: (network: string) => string; - tradingTypes: Array; - chainType: string; - availableNetworks: Array; - } - - export const config: NetworkConfig = { - allowedSlippage: ConfigManagerV2.getInstance().get( - `defikingdoms.allowedSlippage` - ), - gasLimit: ConfigManagerV2.getInstance().get(`defikingdoms.gasLimit`), - ttl: ConfigManagerV2.getInstance().get(`defikingdoms.ttl`), - routerAddress: (network: string) => - ConfigManagerV2.getInstance().get( - `defikingdoms.contractAddresses.${network}.routerAddress` - ), - tradingTypes: ['AMM'], - chainType: 'EVM', - availableNetworks: [ - { - chain: 'harmony', - networks: ['mainnet'], - }, - ], - }; -} diff --git a/src/connectors/defikingdoms/defikingdoms.ts b/src/connectors/defikingdoms/defikingdoms.ts deleted file mode 100644 index a1d2460b07..0000000000 --- a/src/connectors/defikingdoms/defikingdoms.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { UniswapishPriceError } from '../../services/error-handler'; -import { isFractionString } from '../../services/validators'; -import { DefikingdomsConfig } from './defikingdoms.config'; -import routerAbi from './defikingdoms_router_abi.json'; -import { - Contract, - ContractInterface, - ContractTransaction, -} from '@ethersproject/contracts'; -import { - Fetcher, - Percent, - Router, - Token, - TokenAmount, - Trade, - Pair, - SwapParameters, - // } from '@defikingdoms/sdk'; -} from '@switchboard-xyz/defikingdoms-sdk'; -import { BigNumber, Transaction, Wallet } from 'ethers'; -import { logger } from '../../services/logger'; -import { percentRegexp } from '../../services/config-manager-v2'; -// import { Ethereum } from '../../chains/ethereum/ethereum'; -import { ExpectedTrade, Uniswapish } from '../../services/common-interfaces'; -import { Harmony } from '../../chains/harmony/harmony'; - -export class Defikingdoms implements Uniswapish { - private static _instances: { [name: string]: Defikingdoms }; - private harmony: Harmony; - private _router: string; - private _routerAbi: ContractInterface; - private _gasLimitEstimate: number; - private _ttl: number; - private chainId; - private tokenList: Record = {}; - private _ready: boolean = false; - - private constructor(network: string) { - const config = DefikingdomsConfig.config; - this.harmony = Harmony.getInstance(network); - this.chainId = this.harmony.chainId; - this._ttl = DefikingdomsConfig.config.ttl; - this._routerAbi = routerAbi.abi; - this._gasLimitEstimate = DefikingdomsConfig.config.gasLimit; - this._router = config.routerAddress(network); - } - - public static getInstance(chain: string, network: string): Defikingdoms { - if (Defikingdoms._instances === undefined) { - Defikingdoms._instances = {}; - } - if (!(chain + network in Defikingdoms._instances)) { - // eslint-disable-next-line prettier/prettier - Defikingdoms._instances[chain + network] = new Defikingdoms(network); - } - - return Defikingdoms._instances[chain + network]; - } - - /** - * Given a token's address, return the connector's native representation of - * the token. - * - * @param address Token address - */ - public getTokenByAddress(address: string): Token { - return this.tokenList[address]; - } - - public async init() { - if (!this.harmony.ready()) { - await this.harmony.init(); - } - for (const token of this.harmony.storedTokenList) { - this.tokenList[token.address] = new Token( - this.chainId, - token.address, - token.decimals, - token.symbol, - token.name - ); - } - this._ready = true; - } - - public ready(): boolean { - return this._ready; - } - - /** - * Router address. - */ - public get router(): string { - return this._router; - } - - /** - * Router smart contract ABI. - */ - public get routerAbi(): ContractInterface { - return this._routerAbi; - } - - /** - * Default gas limit for swap transactions. - */ - public get gasLimitEstimate(): number { - return this._gasLimitEstimate; - } - - /** - * Default time-to-live for swap transactions, in seconds. - */ - public get ttl(): number { - return this._ttl; - } - - /** - * Gets the allowed slippage percent from the optional parameter or the value - * in the configuration. - * - * @param allowedSlippageStr (Optional) should be of the form '1/10'. - */ - public getAllowedSlippage(allowedSlippageStr?: string): Percent { - if (allowedSlippageStr != null && isFractionString(allowedSlippageStr)) { - const fractionSplit = allowedSlippageStr.split('/'); - return new Percent(fractionSplit[0], fractionSplit[1]); - } - - const allowedSlippage = DefikingdomsConfig.config.allowedSlippage; - const nd = allowedSlippage.match(percentRegexp); - if (nd) return new Percent(nd[1], nd[2]); - throw new Error( - 'Encountered a malformed percent string in the config for ALLOWED_SLIPPAGE.' - ); - } - - /** - * Given the amount of `baseToken` to put into a transaction, calculate the - * amount of `quoteToken` that can be expected from the transaction. - * - * This is typically used for calculating token sell prices. - * - * @param baseToken Token input for the transaction - * @param quoteToken Output from the transaction - * @param amount Amount of `baseToken` to put into the transaction - */ - async estimateSellTrade( - baseToken: Token, - quoteToken: Token, - amount: BigNumber, - allowedSlippage?: string - ): Promise { - const nativeTokenAmount: TokenAmount = new TokenAmount( - baseToken, - amount.toString() - ); - logger.info( - `Fetching pair data for ${baseToken.address}-${quoteToken.address}.` - ); - - const pair: Pair = await this.fetchPairData(baseToken, quoteToken); - const trades: Trade[] = Trade.bestTradeExactIn( - [pair], - nativeTokenAmount, - quoteToken, - { maxHops: 1 } - ); - if (!trades || trades.length === 0) { - throw new UniswapishPriceError( - `priceSwapIn: no trade pair found for ${baseToken} to ${quoteToken}.` - ); - } - logger.info( - `Best trade for ${baseToken.address}-${quoteToken.address}: ` + - `${trades[0].executionPrice.toFixed(6)}` + - `${baseToken.name}.` - ); - const expectedAmount = trades[0].minimumAmountOut( - this.getAllowedSlippage(allowedSlippage) - ); - return { trade: trades[0], expectedAmount }; - } - - /** - * Given the amount of `baseToken` desired to acquire from a transaction, - * calculate the amount of `quoteToken` needed for the transaction. - * - * This is typically used for calculating token buy prices. - * - * @param quoteToken Token input for the transaction - * @param baseToken Token output from the transaction - * @param amount Amount of `baseToken` desired from the transaction - */ - async estimateBuyTrade( - quoteToken: Token, - baseToken: Token, - amount: BigNumber, - allowedSlippage?: string - ): Promise { - const nativeTokenAmount: TokenAmount = new TokenAmount( - baseToken, - amount.toString() - ); - logger.info( - `Fetching pair data for ${quoteToken.address}-${baseToken.address}.` - ); - logger.info( - JSON.stringify({ quoteToken, baseToken, provider: this.harmony.provider }) - ); - const pair: Pair = await this.fetchPairData(quoteToken, baseToken); - const trades: Trade[] = Trade.bestTradeExactOut( - [pair], - quoteToken, - nativeTokenAmount, - { maxHops: 1 } - ); - if (!trades || trades.length === 0) { - throw new UniswapishPriceError( - `priceSwapOut: no trade pair found for ${quoteToken.address} to ${baseToken.address}.` - ); - } - logger.info( - `Best trade for ${quoteToken.address}-${baseToken.address}: ` + - `${trades[0].executionPrice.invert().toFixed(6)} ` + - `${baseToken.name}.` - ); - - const expectedAmount = trades[0].maximumAmountIn( - this.getAllowedSlippage(allowedSlippage) - ); - return { trade: trades[0], expectedAmount }; - } - - /** - * Given a wallet and a Defikingdoms trade, try to execute it on blockchain. - * - * @param wallet Wallet - * @param trade Expected trade - * @param gasPrice Base gas price, for pre-EIP1559 transactions - * @param defikingdomsRouter Router smart contract address - * @param ttl How long the swap is valid before expiry, in seconds - * @param abi Router contract ABI - * @param gasLimit Gas limit - * @param nonce (Optional) EVM transaction nonce - */ - async executeTrade( - wallet: Wallet, - trade: Trade, - gasPrice: number, - defikingdomsRouter: string, - ttl: number, - abi: ContractInterface, - gasLimit: number, - nonce?: number, - _1?: BigNumber, - _2?: BigNumber, - allowedSlippage?: string - ): Promise { - const result: SwapParameters = Router.swapCallParameters(trade, { - ttl, - recipient: wallet.address, - allowedSlippage: this.getAllowedSlippage(allowedSlippage), - }); - - const contract: Contract = new Contract(defikingdomsRouter, abi, wallet); - return this.harmony.nonceManager.provideNonce( - nonce, - wallet.address, - async (nextNonce) => { - const tx: ContractTransaction = await contract[result.methodName]( - ...result.args, - { - gasPrice: (gasPrice * 1e9).toFixed(0), - gasLimit: gasLimit.toFixed(0), - value: result.value, - nonce: nextNonce, - } - ); - - logger.info(JSON.stringify(tx)); - return tx; - } - ); - } - - async fetchPairData(tokenA: Token, tokenB: Token): Promise { - return await Fetcher.fetchPairData(tokenA, tokenB, this.harmony.provider); - } -} diff --git a/src/connectors/defikingdoms/defikingdoms_router_abi.json b/src/connectors/defikingdoms/defikingdoms_router_abi.json deleted file mode 100644 index 5a0d96a6f1..0000000000 --- a/src/connectors/defikingdoms/defikingdoms_router_abi.json +++ /dev/null @@ -1,1625 +0,0 @@ -{ - "abi": [ - { - "inputs": [], - "name": "WETH", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "tokenA", - "type": "address" - }, - { - "internalType": "address", - "name": "tokenB", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amountADesired", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountBDesired", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountAMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountBMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "addLiquidity", - "outputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amountTokenDesired", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountTokenMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETHMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "addLiquidityETH", - "outputs": [ - { - "internalType": "uint256", - "name": "amountToken", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETH", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "factory", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveOut", - "type": "uint256" - } - ], - "name": "getAmountIn", - "outputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveOut", - "type": "uint256" - } - ], - "name": "getAmountOut", - "outputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - } - ], - "name": "getAmountsIn", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - } - ], - "name": "getAmountsOut", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveB", - "type": "uint256" - } - ], - "name": "quote", - "outputs": [ - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "tokenA", - "type": "address" - }, - { - "internalType": "address", - "name": "tokenB", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountAMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountBMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "removeLiquidity", - "outputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountTokenMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETHMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "removeLiquidityETH", - "outputs": [ - { - "internalType": "uint256", - "name": "amountToken", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETH", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountTokenMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETHMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "removeLiquidityETHSupportingFeeOnTransferTokens", - "outputs": [ - { - "internalType": "uint256", - "name": "amountETH", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountTokenMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETHMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "approveMax", - "type": "bool" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "removeLiquidityETHWithPermit", - "outputs": [ - { - "internalType": "uint256", - "name": "amountToken", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETH", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountTokenMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountETHMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "approveMax", - "type": "bool" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", - "outputs": [ - { - "internalType": "uint256", - "name": "amountETH", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "tokenA", - "type": "address" - }, - { - "internalType": "address", - "name": "tokenB", - "type": "address" - }, - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountAMin", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountBMin", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "approveMax", - "type": "bool" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "removeLiquidityWithPermit", - "outputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapETHForExactTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactETHForTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactTokensForETH", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactTokensForTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMin", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMax", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapTokensForExactETH", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMax", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapTokensForExactTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "evm": { - "bytecode": { - "linkReferences": {}, - "object": "", - "opcodes": "", - "sourceMap": "" - }, - "deployedBytecode": { - "immutableReferences": {}, - "linkReferences": {}, - "object": "", - "opcodes": "", - "sourceMap": "" - } - }, - "metadata": "{\"compiler\":{\"version\":\"0.6.12+commit.27d51765\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0In\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1In\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0Out\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1Out\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint112\",\"name\":\"reserve0\",\"type\":\"uint112\"},{\"indexed\":false,\"internalType\":\"uint112\",\"name\":\"reserve1\",\"type\":\"uint112\"}],\"name\":\"Sync\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINIMUM_LIQUIDITY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PERMIT_TYPEHASH\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReserves\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"reserve0\",\"type\":\"uint112\"},{\"internalType\":\"uint112\",\"name\":\"reserve1\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"blockTimestampLast\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"kLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"liquidity\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"price0CumulativeLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"price1CumulativeLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"skim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0Out\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Out\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sync\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/interfaces/IUniswapV2Pair.sol\":\"IUniswapV2Pair\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"contracts/interfaces/IUniswapV2Pair.sol\":{\"keccak256\":\"0x3368b1700fc4a77b780967cdd03c731da787a99f054f69f4b404d3cd3691712d\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://47521585cb5e7f2a8a1586b7d4f09e5ffc80929af8f9ed18012a1b4a82920b9f\",\"dweb:/ipfs/QmdHmVCdnyDq9GFDuRKXe69ATcY4ABXehHzoKRnzxtWNFv\"]}},\"version\":1}", - "interface": [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount0", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount1", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "Burn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount0", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount1", - "type": "uint256" - } - ], - "name": "Mint", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount0In", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount1In", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount0Out", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount1Out", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "Swap", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint112", - "name": "reserve0", - "type": "uint112" - }, - { - "indexed": false, - "internalType": "uint112", - "name": "reserve1", - "type": "uint112" - } - ], - "name": "Sync", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MINIMUM_LIQUIDITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "PERMIT_TYPEHASH", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "burn", - "outputs": [ - { - "internalType": "uint256", - "name": "amount0", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount1", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "factory", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getReserves", - "outputs": [ - { - "internalType": "uint112", - "name": "reserve0", - "type": "uint112" - }, - { - "internalType": "uint112", - "name": "reserve1", - "type": "uint112" - }, - { - "internalType": "uint32", - "name": "blockTimestampLast", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "kLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "mint", - "outputs": [ - { - "internalType": "uint256", - "name": "liquidity", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "price0CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "price1CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "skim", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount0Out", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount1Out", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "swap", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "sync", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "token0", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "token1", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "" -} diff --git a/src/connectors/zigzag/zigzag.config.ts b/src/connectors/zigzag/zigzag.config.ts deleted file mode 100644 index f6f7f465d9..0000000000 --- a/src/connectors/zigzag/zigzag.config.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AvailableNetworks } from '../../services/config-manager-types'; -import { ConfigManagerV2 } from '../../services/config-manager-v2'; - -export namespace ZigZagConfig { - export interface NetworkConfig { - contractAddress: (network: string) => string; - tradingTypes: Array; - chainType: string; - availableNetworks: Array; - } - - export const config: NetworkConfig = { - contractAddress: (network: string) => - ConfigManagerV2.getInstance().get( - `zigzag.networks.${network}.contractAddress` - ), - tradingTypes: ['AMM'], - chainType: 'EVM', - availableNetworks: [ - { - chain: 'ethereum', - networks: Object.keys( - ConfigManagerV2.getInstance().get('zigzag.networks') - ).filter((network) => - Object.keys( - ConfigManagerV2.getInstance().get('ethereum.networks') - ).includes(network) - ), - }, - ], - }; -} diff --git a/src/connectors/zigzag/zigzag.controllers.ts b/src/connectors/zigzag/zigzag.controllers.ts deleted file mode 100644 index f0bb95c994..0000000000 --- a/src/connectors/zigzag/zigzag.controllers.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { ZigZagish, ZigZagTrade } from '../../services/common-interfaces'; -import { Ethereumish, Tokenish } from '../../services/common-interfaces'; -import { Token } from '@uniswap/sdk-core'; -import { TokenInfo } from '../../chains/ethereum/ethereum-base'; -import Decimal from 'decimal.js-light'; -import { Transaction, utils, Wallet } from 'ethers'; -import { - HttpException, - TOKEN_NOT_SUPPORTED_ERROR_CODE, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE, - PRICE_FAILED_ERROR_CODE, - PRICE_FAILED_ERROR_MESSAGE, - UNKNOWN_ERROR_ERROR_CODE, - UNKNOWN_ERROR_MESSAGE, - SWAP_PRICE_LOWER_THAN_LIMIT_PRICE_ERROR_MESSAGE, - SWAP_PRICE_LOWER_THAN_LIMIT_PRICE_ERROR_CODE, - SWAP_PRICE_EXCEEDS_LIMIT_PRICE_ERROR_CODE, - SWAP_PRICE_EXCEEDS_LIMIT_PRICE_ERROR_MESSAGE, - LOAD_WALLET_ERROR_MESSAGE, - LOAD_WALLET_ERROR_CODE, -} from '../../services/error-handler'; -import { latency, gasCostInEthString } from '../../services/base'; -import { - PriceRequest, - PriceResponse, - TradeRequest, - TradeResponse, -} from '../../amm/amm.requests'; -import { logger } from '../../services/logger'; - -export function getFullTokenFromSymbol( - ethereumish: Ethereumish, - zigzagish: ZigZagish, - tokenSymbol: string -): Tokenish | Token { - const tokenInfo: TokenInfo | undefined = - ethereumish.getTokenBySymbol(tokenSymbol); - let fullToken: Tokenish | Token | undefined; - if (tokenInfo) { - fullToken = zigzagish.getTokenByAddress(tokenInfo.address); - } - if (!fullToken) - throw new HttpException( - 500, - TOKEN_NOT_SUPPORTED_ERROR_MESSAGE + tokenSymbol, - TOKEN_NOT_SUPPORTED_ERROR_CODE - ); - return fullToken; -} - -export async function price( - ethereumish: Ethereumish, - zigzagish: ZigZagish, - req: PriceRequest -): Promise { - const startTimestamp: number = Date.now(); - let baseToken, quoteToken, rawAmount; - if (req.side === 'SELL') { - baseToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.base); - quoteToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.quote); - rawAmount = utils.parseUnits(req.amount, baseToken.decimals); - } else { - baseToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.quote); - quoteToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.base); - rawAmount = utils.parseUnits(req.amount, quoteToken.decimals); - } - - let tradePrice; - - try { - const tradeInfo = await zigzagish.estimate( - baseToken, - quoteToken, - rawAmount, - req.side.toLowerCase() - ); - tradePrice = tradeInfo.newSwapPrice; - } catch (e) { - if (e instanceof Error) { - throw new HttpException( - 500, - PRICE_FAILED_ERROR_MESSAGE + e.message, - PRICE_FAILED_ERROR_CODE - ); - } else { - throw new HttpException( - 500, - UNKNOWN_ERROR_MESSAGE, - UNKNOWN_ERROR_ERROR_CODE - ); - } - } - - const gasLimitTransaction = ethereumish.gasLimitTransaction; - const gasPrice = ethereumish.gasPrice; - const gasLimitEstimate = 150688; - return { - network: ethereumish.chain, - timestamp: startTimestamp, - latency: latency(startTimestamp, Date.now()), - base: baseToken.address, - quote: quoteToken.address, - amount: req.amount, - rawAmount: rawAmount.toString(), - expectedAmount: String(tradePrice * Number(req.amount)), - price: String(tradePrice), - gasPrice: gasPrice, - gasPriceToken: ethereumish.nativeTokenSymbol, - gasLimit: gasLimitTransaction, - gasCost: gasCostInEthString(gasPrice, gasLimitEstimate), - }; -} - -export async function trade( - ethereumish: Ethereumish, - zigzagish: ZigZagish, - req: TradeRequest -): Promise { - const startTimestamp: number = Date.now(); - let baseToken, quoteToken, rawAmount; - if (req.side === 'SELL') { - baseToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.base); - quoteToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.quote); - rawAmount = utils.parseUnits(req.amount, baseToken.decimals); - } else { - baseToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.quote); - quoteToken = getFullTokenFromSymbol(ethereumish, zigzagish, req.base); - rawAmount = utils.parseUnits(req.amount, quoteToken.decimals); - } - - const limitPrice = req.limitPrice; - - // Get wallet - let wallet: Wallet; - try { - wallet = await ethereumish.getWallet(req.address); - } catch (err) { - logger.error(`Wallet ${req.address} not available.`); - throw new HttpException( - 500, - LOAD_WALLET_ERROR_MESSAGE + err, - LOAD_WALLET_ERROR_CODE - ); - } - - // Get route data - const tradeInfo: ZigZagTrade = await zigzagish.estimate( - baseToken, - quoteToken, - rawAmount, - req.side.toLowerCase() - ); - const price: number = tradeInfo.newSwapPrice; - - // Basic price check - if ( - req.side === 'BUY' && - limitPrice && - new Decimal(price.toString()).gt(new Decimal(limitPrice)) - ) { - logger.error('Swap price exceeded limit price.'); - throw new HttpException( - 500, - SWAP_PRICE_EXCEEDS_LIMIT_PRICE_ERROR_MESSAGE( - price.toString(), - limitPrice - ), - SWAP_PRICE_EXCEEDS_LIMIT_PRICE_ERROR_CODE - ); - } else if ( - req.side === 'SELL' && - limitPrice && - new Decimal(price.toString()).lt(new Decimal(limitPrice)) - ) { - logger.error('Swap price lower than limit price.'); - throw new HttpException( - 500, - SWAP_PRICE_LOWER_THAN_LIMIT_PRICE_ERROR_MESSAGE( - price.toString(), - limitPrice - ), - SWAP_PRICE_LOWER_THAN_LIMIT_PRICE_ERROR_CODE - ); - } - - // Price info log - logger.info( - `Expected execution price is ${price.toString()}, ` + - `limit price is ${limitPrice}.` - ); - - // Execute trade - const tx: Transaction = await zigzagish.executeTrade( - wallet.address, - tradeInfo, - rawAmount, - req.side === 'BUY' - ); - - const gasPrice: number = ethereumish.gasPrice; - - // Save Tx - if (tx.hash) { - await ethereumish.txStorage.saveTx( - ethereumish.chain, - ethereumish.chainId, - tx.hash, - new Date(), - gasPrice - ); - } - - logger.info( - `Trade has been executed, txHash is ${tx.hash}, nonce is ${tx.nonce}, gasPrice is ${gasPrice}.` - ); - - return { - network: ethereumish.chain, - timestamp: startTimestamp, - latency: latency(startTimestamp, Date.now()), - base: baseToken.address, - quote: quoteToken.address, - amount: new Decimal(req.amount).toFixed(baseToken.decimals), - rawAmount: rawAmount.toString(), - price: price.toString(), - gasPrice: gasPrice, - gasPriceToken: ethereumish.nativeTokenSymbol, - gasLimit: ethereumish.gasLimitTransaction, - gasCost: gasCostInEthString(gasPrice, ethereumish.gasLimitTransaction), - nonce: tx.nonce, - txHash: tx.hash, - }; -} diff --git a/src/connectors/zigzag/zigzag.exchange.abi.json b/src/connectors/zigzag/zigzag.exchange.abi.json deleted file mode 100644 index ee63dbaffd..0000000000 --- a/src/connectors/zigzag/zigzag.exchange.abi.json +++ /dev/null @@ -1,725 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "address", - "name": "fee_address", - "type": "address" - }, - { - "internalType": "address", - "name": "weth_address", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - } - ], - "name": "CancelOrder", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "filled", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "remaining", - "type": "uint256" - } - ], - "name": "OrderStatus", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "makerSellToken", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "takerSellToken", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "makerSellAmount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "takerSellAmount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "makerVolumeFee", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "takerVolumeFee", - "type": "uint256" - } - ], - "name": "Swap", - "type": "event" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "order", - "type": "tuple" - } - ], - "name": "cancelOrder", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "cancelled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "makerOrder", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "makerSignature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "takerSellAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderExactInput", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "makerOrder", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "makerSignature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "takerSellAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderExactInputETH", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "makerOrder", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "makerSignature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "takerBuyAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderExactOutput", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "makerOrder", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "makerSignature", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "takerBuyAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderExactOutputETH", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order[]", - "name": "makerOrder", - "type": "tuple[]" - }, - { - "internalType": "bytes[]", - "name": "makerSignature", - "type": "bytes[]" - }, - { - "internalType": "uint256", - "name": "takerAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderRoute", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order[]", - "name": "makerOrder", - "type": "tuple[]" - }, - { - "internalType": "bytes[]", - "name": "makerSignature", - "type": "bytes[]" - }, - { - "internalType": "uint256", - "name": "takerAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "fillAvailable", - "type": "bool" - } - ], - "name": "fillOrderRouteETH", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "filled", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "order", - "type": "tuple" - } - ], - "name": "getOpenOrder", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "orderSellFilledAmount", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.OrderInfo", - "name": "orderInfo", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "address", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - } - ], - "internalType": "struct LibOrder.Order", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidOrderSignature", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ] -} \ No newline at end of file diff --git a/src/connectors/zigzag/zigzag.ts b/src/connectors/zigzag/zigzag.ts deleted file mode 100644 index b45595a640..0000000000 --- a/src/connectors/zigzag/zigzag.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { BigNumber, Contract, Transaction } from 'ethers'; -import { ethers } from 'ethers'; -import LRUCache from 'lru-cache'; -import { ZigZagConfig } from './zigzag.config'; -import axios from 'axios'; -import { Ethereum } from '../../chains/ethereum/ethereum'; -import { Token } from '@uniswap/sdk-core'; -import { ZigZagTrade } from '../../services/common-interfaces'; -import { ZigZagish } from '../../services/common-interfaces'; -import { logger } from '../../services/logger'; -import { EVMTxBroadcaster } from '../../chains/ethereum/evm.broadcaster'; -import { abi } from './zigzag.exchange.abi.json'; - -// https://api.arbitrum.zigzag.exchange/v1/info - -// https://zigzag-exchange.herokuapp.com/api/coingecko/v1/pairs/42161 -// https://zigzag-exchange.herokuapp.com/api/coingecko/v1/tickers/42161 -// https://zigzag-exchange.herokuapp.com/api/coingecko/v1/orderbook/42161/?ticker_id=eth-ust -// https://zigzag-exchange.herokuapp.com/api/coingecko/v1/historical_trades/42161?ticker_id=eth-ust&type=b - -export type ZigZagMarket = { - buyToken: string; - sellToken: string; - verified: boolean; -}; - -export type ZigZagToken = { - address: string; - symbol: string; - decimals: number; - name: string; -}; - -export type ZigZagInfo = { - markets: Array; - verifiedTokens: Array; - exchange: { - exchangeAddress: string; - makerVolumeFee: number; - takerVolumeFee: number; - // domain: EIP712DomainInfo; - // types: EIP712TypeInfo; - }; -}; - -export interface Market { - market: string; - baseSymbol: string; - quoteSymbol: string; - lastPrice: number; - lowestAsk: number; - highestBid: number; - baseVolume: number; - quoteVolume: number; - priceChange: number; - priceChangePercent_24h: number; - highestPrice_24h: number; - lowestPrice_24h: number; - numberOfTrades_24h: number; -} - -export type RouteMarket = { - buyTokenAddress: string; - sellTokenAddress: string; -}; - -export type ZigZagOrder = { - order: { - user: string; - buyToken: string; - sellToken: string; - buyAmount: string; - sellAmount: string; - expirationTimeSeconds: string; - }; - signature: string; -}; - -export class ZigZag implements ZigZagish { - private static _instances: LRUCache; - private _ready = false; - private _chain: Ethereum; - private _network: string; - private _router: Contract; - private tokenList: Record = {}; // keep track of tokens that are in a ZigZag market - // public markets: Array = []; // keep track of ZigZag markets, ZZ-USDT - public markets: Array = []; // keep track of ZigZag markets, 0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9-0xf4037f59c92c9893c43c2372286699430310cfe7 - public config; - gasLimitEstimate: number; - - private constructor(network: string) { - this._chain = Ethereum.getInstance(network); - this.config = ZigZagConfig.config; - this._network = network; - this._router = new Contract( - this.config.contractAddress(this._network), - abi, - this._chain.provider - ); - this.gasLimitEstimate = this._chain.gasLimitTransaction; - } - - public static getInstance(network: string): ZigZag { - if (ZigZag._instances === undefined) { - ZigZag._instances = new LRUCache({ - max: 2, - }); - } - const instanceKey = network; - if (!ZigZag._instances.has(instanceKey)) { - ZigZag._instances.set(instanceKey, new ZigZag(network)); - } - - return ZigZag._instances.get(instanceKey) as ZigZag; - } - - // public async loadMarkets() { - // this.parsedMarkets = await axios.get( - // 'https://zigzag-exchange.herokuapp.com/api/v1/markets' - // ); - // } - - public getTokenByAddress(address: string): Token { - return this.tokenList[address.toLowerCase()]; - } - - public async init() { - await this._chain.init(); - const response = await axios.get( - 'https://api.arbitrum.zigzag.exchange/v1/info' - ); - if (response.status === 200) { - const zigZagData: ZigZagInfo = response.data; - for (const token of zigZagData.verifiedTokens) { - this.tokenList[token.address.toLowerCase()] = new Token( - this._chain.chainId, - token.address.toLowerCase(), - token.decimals, - token.symbol, - token.name - ); - } - for (const market of zigZagData.markets) { - const base = this.tokenList[market.buyToken]; - const quote = this.tokenList[market.sellToken]; - // this.markets.push(base.symbol + '-' + quote.symbol); - this.markets.push( - base.address.toLowerCase() + '-' + quote.address.toLowerCase() - ); - } - } - - this._ready = true; - } - - public ready(): boolean { - return this._ready; - } - - public async getMarketOrders( - buyTokenAddress: string, - sellTokenAddress: string, - minExpires: string - ): Promise> { - const response = await axios.get( - `https://api.arbitrum.zigzag.exchange/v1/orders?buyToken=${buyTokenAddress}&sellToken=${sellTokenAddress}&minExpires=${minExpires}` - ); - - return response.data.orders; - } - - // For an array of possible routes, get recent orders for the corresponding markets - public async getOrderBook( - possibleRoutes: Array> - ): Promise<{ [key: string]: Array }> { - const minExpires = (Date.now() / 1000 + 11).toFixed(0); - const minTimeStamp: number = Date.now() / 1000 + 10; - const newOrderBook: { [key: string]: Array } = {}; - - const promise0 = possibleRoutes.map(async (routes: Array) => { - const promise1 = routes.map(async (market: RouteMarket) => { - const requestSellTokenAddress = market.sellTokenAddress; - const requestBuyTokenAddress = market.buyTokenAddress; - const orders = await this.getMarketOrders( - requestBuyTokenAddress, - requestSellTokenAddress, - minExpires - ); - const goodOrders = orders.filter( - (order: ZigZagOrder) => - minTimeStamp < Number(order.order.expirationTimeSeconds) - ); - const key = `${requestBuyTokenAddress}-${requestSellTokenAddress}`; - newOrderBook[key] = goodOrders; - }); - await Promise.all(promise1); - }); - await Promise.all(promise0); - - return newOrderBook; - } - - // if a direct market between two pairs exists, use it. Otherwise generate - // routes using stable coins. - public getPossibleRoutes( - sellToken: Token, - buyToken: Token - ): Array> { - const newRoute: Array> = []; - const tradeMarket = `${sellToken.address.toLowerCase()}-${buyToken.address.toLowerCase()}`; - - // check for a direct route between pairs, if this exists, use it. - if (this.markets.includes(tradeMarket)) { - newRoute.push([ - { - buyTokenAddress: sellToken.address.toLowerCase(), - sellTokenAddress: buyToken.address.toLowerCase(), - }, - ]); - } - - // check routes via other tokens - if (newRoute.length === 0) { - const possibleRoutes = [ - '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', // WETH - '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', // USDC - '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', // USDT - ]; - possibleRoutes.forEach((routeTokenAddress) => { - const firstTradeMarket = `${sellToken.address.toLowerCase()}-${routeTokenAddress.toLowerCase()}`; - const secondTradeMarket = `${routeTokenAddress.toLowerCase()}-${buyToken.address.toLowerCase()}`; - if ( - this.markets.includes(firstTradeMarket) && - this.markets.includes(secondTradeMarket) - ) { - newRoute.push([ - { - buyTokenAddress: sellToken.address.toLowerCase(), - sellTokenAddress: routeTokenAddress.toLowerCase(), - }, - { - buyTokenAddress: routeTokenAddress.toLowerCase(), - sellTokenAddress: buyToken.address.toLowerCase(), - }, - ]); - } - }); - } - - return newRoute; - } - - // estimate trade details between two tokens - public async estimate( - sellToken: Token, - buyToken: Token, - buyAmount: BigNumber, - side: string - ): Promise { - let newQuoteOrderArray: Array = []; - const minTimeStamp: number = Date.now() / 1000 + 5; - let newSwapPrice: number = 0; - let bestSwapRoute: Array = []; - - const possibleRoutes = this.getPossibleRoutes(sellToken, buyToken); - const orderBook = await this.getOrderBook(possibleRoutes); - - possibleRoutes.forEach((route: Array) => { - let routeSwapPrice = 0; - const routeQuoteOrderArray: Array = []; - const stepBuyAmount = buyAmount; - route.forEach((market: RouteMarket) => { - let marketSwapPrice = 0; - let marketQuoteOrder: ZigZagOrder | undefined; - const key = `${market.buyTokenAddress}-${market.sellTokenAddress}`; - const currentOrderBook = orderBook[key]; - if (!currentOrderBook) return; - - for (let i = 0; i < currentOrderBook.length; i++) { - const { order } = currentOrderBook[i]; - if (minTimeStamp > Number(order.expirationTimeSeconds)) return; - - const quoteSellAmount = ethers.BigNumber.from(order.sellAmount); - const quoteBuyAmount = ethers.BigNumber.from(order.buyAmount); - if (side === 'buy' && quoteSellAmount.lt(stepBuyAmount)) return; - - const quoteSellToken = this.tokenList[order.sellToken]; - const quoteBuyToken = this.tokenList[order.buyToken]; - if (!quoteSellToken || !quoteBuyToken) return; - - const quoteSellAmountFormated = Number( - ethers.utils.formatUnits(quoteSellAmount, quoteSellToken.decimals) - ); - const quoteBuyAmountFormated = Number( - ethers.utils.formatUnits(quoteBuyAmount, quoteBuyToken.decimals) - ); - - const thisPrice = quoteSellAmountFormated / quoteBuyAmountFormated; - if (thisPrice > marketSwapPrice) { - marketSwapPrice = thisPrice; - marketQuoteOrder = currentOrderBook[i]; - } - } - routeSwapPrice = routeSwapPrice - ? routeSwapPrice * marketSwapPrice - : marketSwapPrice; - if (marketQuoteOrder) { - routeQuoteOrderArray.push(marketQuoteOrder); - stepBuyAmount - .mul(marketQuoteOrder.order.buyAmount) - .div(marketQuoteOrder.order.sellAmount); - } - }); - - if (routeSwapPrice > newSwapPrice) { - newSwapPrice = routeSwapPrice; - newQuoteOrderArray = routeQuoteOrderArray; - bestSwapRoute = route; - } - - if (bestSwapRoute.length === 0) bestSwapRoute = route; - }); - - return { - newSwapPrice: side === 'sell' ? newSwapPrice : 1 / newSwapPrice, - newQuoteOrderArray: newQuoteOrderArray, - bestSwapRoute: bestSwapRoute, - }; - } - - /** - * Given a wallet and a Uniswap-ish trade, try to execute it on blockchain. - * - * @param wallet Wallet - * @param trade Expected trade - */ - async executeTrade( - walletAddress: string, - trade: ZigZagTrade, - rawAmount: BigNumber, - is_buy: boolean - ): Promise { - let txData; - if (trade.newQuoteOrderArray.length === 0) - throw new Error('No route available.'); - else if (trade.newQuoteOrderArray.length === 1) { - if (is_buy === true) { - // buy - txData = await this._router.populateTransaction.fillOrderExactOutput( - [ - trade.newQuoteOrderArray[0].order.user, - trade.newQuoteOrderArray[0].order.sellToken, - trade.newQuoteOrderArray[0].order.buyToken, - trade.newQuoteOrderArray[0].order.sellAmount, - trade.newQuoteOrderArray[0].order.buyAmount, - trade.newQuoteOrderArray[0].order.expirationTimeSeconds, - ], - trade.newQuoteOrderArray[0].signature, - rawAmount.toString(), - false - ); - } else { - // sell - txData = await this._router.populateTransaction.fillOrderExactInput( - [ - trade.newQuoteOrderArray[0].order.user, - trade.newQuoteOrderArray[0].order.sellToken, - trade.newQuoteOrderArray[0].order.buyToken, - trade.newQuoteOrderArray[0].order.sellAmount, - trade.newQuoteOrderArray[0].order.buyAmount, - trade.newQuoteOrderArray[0].order.expirationTimeSeconds, - ], - trade.newQuoteOrderArray[0].signature, - rawAmount.toString(), - false - ); - } - } else { - const quoteOrderCalldataArray = trade.newQuoteOrderArray.map( - (quoteOrder: ZigZagOrder) => { - return [ - quoteOrder.order.user, - quoteOrder.order.sellToken, - quoteOrder.order.buyToken, - quoteOrder.order.sellAmount, - quoteOrder.order.buyAmount, - quoteOrder.order.expirationTimeSeconds, - ]; - } - ); - const signatureCalldataArray = trade.newQuoteOrderArray.map( - (quoteOrder: ZigZagOrder) => quoteOrder.signature - ); - txData = await this._router.populateTransaction.fillOrderRoute( - Object.values(quoteOrderCalldataArray), - Object.values(signatureCalldataArray), - rawAmount.toString(), - false - ); - } - txData.gasLimit = BigNumber.from(String(this._chain.gasLimitTransaction)); - const txResponse = await EVMTxBroadcaster.getInstance( - this._chain, - walletAddress - ).broadcast(txData); - - logger.info(txResponse); - return txResponse; - } -} diff --git a/src/services/common-interfaces.ts b/src/services/common-interfaces.ts index 4fdd31a7f2..332409ccb6 100644 --- a/src/services/common-interfaces.ts +++ b/src/services/common-interfaces.ts @@ -26,13 +26,6 @@ import { Token as UniswapCoreToken, Fraction as UniswapFraction, } from '@uniswap/sdk-core'; -import { - Token as TokenDefikingdoms, - CurrencyAmount as CurrencyAmountDefikingdoms, - Trade as TradeDefikingdoms, - Fraction as DefikingdomsFraction, - // } from '@defikingdoms/sdk'; -} from '@switchboard-xyz/defikingdoms-sdk'; import { Token as TokenPangolin, CurrencyAmount as CurrencyAmountPangolin, @@ -114,7 +107,6 @@ import { ClobTickerRequest, } from '../clob/clob.requests'; import { BalanceRequest } from '../network/network.requests'; -import { RouteMarket, ZigZagOrder } from '../connectors/zigzag/zigzag'; import { TradeV2 } from '@traderjoe-xyz/sdk-v2'; // TODO Check the possibility to have clob/solana/serum equivalents here @@ -127,7 +119,6 @@ export type Tokenish = | TokenTraderjoe | UniswapCoreToken | SushiToken - | TokenDefikingdoms | PancakeSwapToken | MMFToken | VVSToken @@ -149,7 +140,6 @@ export type UniswapishTrade = | TradeTraderjoe | SushiswapTrade | TradeUniswap - | TradeDefikingdoms | DefiraTrade | PancakeSwapTrade | MMFTrade @@ -172,7 +162,6 @@ export type UniswapishAmount = | UniswapCoreCurrencyAmount | CurrencyAmountTraderjoe | SushiCurrencyAmount - | CurrencyAmountDefikingdoms | PancakeSwapCurrencyAmount | CurrencyAmountMMF | CurrencyAmountVVS @@ -184,7 +173,6 @@ export type Fractionish = | QuickswapFraction | TraderjoeFraction | SushiFraction - | DefikingdomsFraction | PancakeSwapFraction | FractionMMF | FractionVVS @@ -310,34 +298,6 @@ export interface Uniswapish { ): Promise; } -export interface ZigZagTrade { - newSwapPrice: number; - bestSwapRoute: RouteMarket[]; - newQuoteOrderArray: ZigZagOrder[]; -} - -export interface ZigZagish { - init(): Promise; - - ready(): boolean; - - getTokenByAddress(address: string): Tokenish; - - estimate( - sellToken: Tokenish, - buyToken: Tokenish, - buyAmount: BigNumber, - side: string - ): Promise; - - executeTrade( - walletAddress: string, - trade: ZigZagTrade, - rawAmount: BigNumber, - is_buy: boolean - ): Promise; -} - export interface RefAMMish { /** * Router address. diff --git a/src/services/connection-manager.ts b/src/services/connection-manager.ts index 37af1d8411..6d0c89912c 100644 --- a/src/services/connection-manager.ts +++ b/src/services/connection-manager.ts @@ -17,7 +17,6 @@ import { VVSConnector } from '../connectors/vvs/vvs'; import { InjectiveCLOB } from '../connectors/injective/injective'; import { InjectiveClobPerp } from '../connectors/injective_perpetual/injective.perp'; import { Injective } from '../chains/injective/injective'; -import { ZigZag } from '../connectors/zigzag/zigzag'; import { CLOBish, Ethereumish, @@ -30,7 +29,6 @@ import { } from './common-interfaces'; import { Traderjoe } from '../connectors/traderjoe/traderjoe'; import { Sushiswap } from '../connectors/sushiswap/sushiswap'; -import { Defikingdoms } from '../connectors/defikingdoms/defikingdoms'; import { Defira } from '../connectors/defira/defira'; import { Near } from '../chains/near/near'; import { Ref } from '../connectors/ref/ref'; @@ -182,8 +180,6 @@ export async function getConnector( connectorInstance = Openocean.getInstance(chain, network); } else if (chain === 'avalanche' && connector === 'traderjoe') { connectorInstance = Traderjoe.getInstance(chain, network); - } else if (chain === 'harmony' && connector === 'defikingdoms') { - connectorInstance = Defikingdoms.getInstance(chain, network); } else if (chain === 'harmony' && connector === 'defira') { connectorInstance = Defira.getInstance(chain, network); } else if (chain === 'cronos' && connector === 'mad_meerkat') { @@ -204,8 +200,6 @@ export async function getConnector( connectorInstance = InjectiveCLOB.getInstance(chain, network); } else if (chain === 'avalanche' && connector === 'dexalot') { connectorInstance = DexalotCLOB.getInstance(network); - } else if (chain === 'ethereum' && connector === 'zigzag') { - connectorInstance = ZigZag.getInstance(network); } else if (chain == 'algorand' && connector == 'tinyman') { connectorInstance = Tinyman.getInstance(network); } else { diff --git a/src/services/schema/defikingdoms-schema.json b/src/services/schema/defikingdoms-schema.json deleted file mode 100644 index 1f5a967e68..0000000000 --- a/src/services/schema/defikingdoms-schema.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "allowedSlippage": { "type": "string" }, - "gasLimit": { "type": "integer" }, - "ttl": { "type": "integer" }, - "contractAddresses": { - "type": "object", - "patternProperties": { - "^\\w+$": { - "type": "object", - "properties": { - "routerAddress": { "type": "string" } - }, - "required": ["routerAddress"], - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false, - "required": ["allowedSlippage", "gasLimit", "ttl", "contractAddresses"] -} diff --git a/src/services/schema/zigzag-schema.json b/src/services/schema/zigzag-schema.json deleted file mode 100644 index c6008f96a2..0000000000 --- a/src/services/schema/zigzag-schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "networks": { - "type": "object", - "patternProperties": { - "^\\w+$": { - "type": "object", - "properties": { - "contractAddress": { "type": "string" }, - "exchangeApiUrl": { "type": "string" } - }, - "required": ["contractAddress", "exchangeApiUrl"], - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false, - "required": ["networks"] -} diff --git a/src/templates/defikingdoms.yml b/src/templates/defikingdoms.yml deleted file mode 100644 index 86956e6323..0000000000 --- a/src/templates/defikingdoms.yml +++ /dev/null @@ -1,14 +0,0 @@ -# how much the execution price is allowed to move unfavorably from the trade -# execution price. It uses a rational number for precision. -allowedSlippage: '2/100' - -# the maximum gas allowed for a defikingdoms trade. -gasLimit: 2000000 - -# how long a trade is valid in seconds. After time passes defikingdoms will not -# perform the trade, but the gas will still be spent. -ttl: 300 - -contractAddresses: - mainnet: - routerAddress: '0x24ad62502d1C652Cc7684081169D04896aC20f30' diff --git a/src/templates/root.yml b/src/templates/root.yml index ea919906ec..1d4ada5601 100644 --- a/src/templates/root.yml +++ b/src/templates/root.yml @@ -72,10 +72,6 @@ configurations: configurationPath: openocean.yml schemaPath: openocean-schema.json - $namespace defikingdoms: - configurationPath: defikingdoms.yml - schemaPath: defikingdoms-schema.json - $namespace cosmos: configurationPath: cosmos.yml schemaPath: cosmos-schema.json @@ -111,7 +107,3 @@ configurations: $namespace xsswap: configurationPath: xsswap.yml schemaPath: xsswap-schema.json - - $namespace zigzag: - configurationPath: zigzag.yml - schemaPath: zigzag-schema.json diff --git a/src/templates/zigzag.yml b/src/templates/zigzag.yml deleted file mode 100644 index abd6cb70e9..0000000000 --- a/src/templates/zigzag.yml +++ /dev/null @@ -1,4 +0,0 @@ -networks: - arbitrum_one: - exchangeApiUrl: https://zigzag-exchange.herokuapp.com - contractAddress: '0x6fCdBD2Aa4cBd9d01741EFC152a7fFB833dd9A47' diff --git a/test-helpers/curl/curl.sh b/test-helpers/curl/curl.sh index 1941928397..426368a956 100644 --- a/test-helpers/curl/curl.sh +++ b/test-helpers/curl/curl.sh @@ -108,8 +108,6 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_traderjoe.json)" https://localhost:15888/amm/price | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_dfk.json)" https://localhost:15888/amm/price - curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_defira.json)" https://localhost:15888/amm/price | jq curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_mad_meerkat.json)" https://localhost:15888/amm/price | jq @@ -128,8 +126,6 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_xdc_xsswap.json)" https://localhost:15888/amm/price | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_zigzag.json)" https://localhost:15888/amm/price | jq - curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/price_tinyman.json)" https://localhost:15888/amm/price | jq ## trade @@ -138,8 +134,6 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/avalanche_traderjoe_trade.json)" https://localhost:15888/amm/trade | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/harmony_dfk_trade.json)" https://localhost:15888/amm/trade | jq - curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/harmony_testnet_defira_trade.json)" https://localhost:15888/amm/trade | jq curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/cronos_mmf_trade.json)" https://localhost:15888/amm/trade | jq @@ -156,8 +150,6 @@ curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: app curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/polygon_sushiswap_trade_sell.json)" https://localhost:15888/amm/trade | jq -curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/eth_zigzag_trade.json)" https://localhost:15888/amm/trade | jq - curl -s -X POST -k --key $GATEWAY_KEY --cert $GATEWAY_CERT -H "Content-Type: application/json" -d "$(envsubst < ./requests/algorand_tinyman_trade.json)" https://localhost:15888/amm/trade | jq ## Perp - curie diff --git a/test-helpers/curl/requests/eth_zigzag_trade.json b/test-helpers/curl/requests/eth_zigzag_trade.json deleted file mode 100644 index 95d3386b75..0000000000 --- a/test-helpers/curl/requests/eth_zigzag_trade.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "address": "$ETH_ADDRESS", - "quote": "USDC", - "base": "WETH", - "amount": "1", - "side": "SELL", - "chain": "ethereum", - "network": "arbitrum_one", - "connector": "zigzag" -} diff --git a/test-helpers/curl/requests/harmony_dfk_trade.json b/test-helpers/curl/requests/harmony_dfk_trade.json deleted file mode 100644 index debdd0374b..0000000000 --- a/test-helpers/curl/requests/harmony_dfk_trade.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "address": "$ETH_ADDRESS", - "quote": "WONE", - "base": "ETH", - "amount": "0.01", - "side": "SELL", - "chain": "harmony", - "network": "mainnet", - "connector": "defikingdoms" -} diff --git a/test-helpers/curl/requests/price_dfk.json b/test-helpers/curl/requests/price_dfk.json deleted file mode 100644 index f35328cf06..0000000000 --- a/test-helpers/curl/requests/price_dfk.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "connector": "defikingdoms", - "chain": "harmony", - "network": "mainnet", - "quote": "USDC", - "base": "ETH", - "amount": "0.01", - "side": "SELL" -} diff --git a/test-helpers/curl/requests/price_zigzag.json b/test-helpers/curl/requests/price_zigzag.json deleted file mode 100644 index cf0ba81299..0000000000 --- a/test-helpers/curl/requests/price_zigzag.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "connector": "zigzag", - "chain": "ethereum", - "network": "arbitrum_one", - "quote": "USDC", - "base": "WETH", - "amount": "2", - "side": "SELL" -} diff --git a/test/chains/harmony/harmony.test.ts b/test/chains/harmony/harmony.test.ts index 441eba300c..13aea00305 100644 --- a/test/chains/harmony/harmony.test.ts +++ b/test/chains/harmony/harmony.test.ts @@ -1,6 +1,5 @@ import { Harmony } from '../../../src/chains/harmony/harmony'; import { patchEVMNonceManager } from '../../evm.nonce.mock'; -import { DefikingdomsConfig } from '../../../src/connectors/defikingdoms/defikingdoms.config'; import { DefiraConfig } from '../../../src/connectors/defira/defira.config'; let harmony: Harmony; @@ -24,14 +23,6 @@ describe('getSpender', () => { ); }); }); - describe('get defikingdoms', () => { - it('returns defikingdoms mainnet router address', () => { - const dfkAddress = harmony.getSpender('defikingdoms'); - expect(dfkAddress.toLowerCase()).toEqual( - DefikingdomsConfig.config.routerAddress('mainnet').toLowerCase() - ); - }); - }); describe('get defira', () => { it('returns defira mainnet router address', () => { const dfkAddress = harmony.getSpender('defira'); diff --git a/test/connectors/defikingdoms/defikingdoms.routes.test.ts b/test/connectors/defikingdoms/defikingdoms.routes.test.ts deleted file mode 100644 index 3f14cec6f8..0000000000 --- a/test/connectors/defikingdoms/defikingdoms.routes.test.ts +++ /dev/null @@ -1,669 +0,0 @@ -import express from 'express'; -import { Express } from 'express-serve-static-core'; -import request from 'supertest'; -import { Harmony } from '../../../src/chains/harmony/harmony'; -import { Defikingdoms } from '../../../src/connectors/defikingdoms/defikingdoms'; -import { AmmRoutes } from '../../../src/amm/amm.routes'; -import { patch, unpatch } from '../../services/patch'; -import { gasCostInEthString } from '../../../src/services/base'; -let app: Express; -let harmony: Harmony; -let defikingdoms: Defikingdoms; - -beforeAll(async () => { - app = express(); - app.use(express.json()); - harmony = Harmony.getInstance('testnet'); - await harmony.init(); - defikingdoms = Defikingdoms.getInstance('harmony', 'testnet'); - await defikingdoms.init(); - app.use('/amm', AmmRoutes.router); -}); - -afterEach(() => { - unpatch(); -}); - -afterAll(async () => { - await harmony.close(); -}); - -const address: string = '0xFaA12FD102FE8623C9299c72B03E45107F2772B5'; - -const patchGetWallet = () => { - patch(harmony, 'getWallet', () => { - return { - address: '0xFaA12FD102FE8623C9299c72B03E45107F2772B5', - }; - }); -}; - -const patchInit = () => { - patch(defikingdoms, 'init', async () => { - return; - }); -}; - -const patchStoredTokenList = () => { - patch(harmony, 'tokenList', () => { - return [ - { - chainId: 1666700000, - name: 'WONE74', - symbol: 'WONE74', - address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa', - decimals: 18, - }, - { - chainId: 1666700000, - name: 'OneETH', - symbol: '1ETH', - address: '0x1E120B3b4aF96e7F394ECAF84375b1C661830013', - decimals: 18, - }, - ]; - }); -}; - -const patchGetTokenBySymbol = () => { - patch(harmony, 'getTokenBySymbol', (symbol: string) => { - if (symbol === 'WONE74') { - return { - chainId: 1666700000, - name: 'WONE74', - symbol: 'WONE74', - address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa', - decimals: 18, - }; - } else { - return { - chainId: 1666700000, - name: 'OneETH', - symbol: '1ETH', - address: '0x1E120B3b4aF96e7F394ECAF84375b1C661830013', - decimals: 18, - }; - } - }); -}; - -const patchGetTokenByAddress = () => { - patch(defikingdoms, 'getTokenByAddress', () => { - return { - chainId: 1666700000, - name: 'WONE74', - symbol: 'WONE74', - address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa', - decimals: 18, - }; - }); -}; - -const patchGasPrice = () => { - patch(harmony, 'gasPrice', () => 100); -}; - -const patchEstimateBuyTrade = () => { - patch(defikingdoms, 'estimateBuyTrade', () => { - return { - expectedAmount: { - toSignificant: () => 100, - }, - trade: { - executionPrice: { - invert: jest.fn().mockReturnValue({ - toSignificant: () => 100, - toFixed: () => '100', - }), - }, - }, - }; - }); -}; - -const patchEstimateSellTrade = () => { - patch(defikingdoms, 'estimateSellTrade', () => { - return { - expectedAmount: { - toSignificant: () => 100, - }, - trade: { - executionPrice: { - toSignificant: () => 100, - toFixed: () => '100', - }, - }, - }; - }); -}; - -const patchGetNonce = () => { - patch(harmony.nonceManager, 'getNonce', () => 21); -}; - -const patchExecuteTrade = () => { - patch(defikingdoms, 'executeTrade', () => { - return { nonce: 21, hash: '000000000000000' }; - }); -}; - -describe('POST /amm/price', () => { - it('should return 200 for BUY', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchEstimateBuyTrade(); - patchGetNonce(); - patchExecuteTrade(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - side: 'BUY', - }) - .set('Accept', 'application/json') - .expect(200) - .then((res: any) => { - expect(res.body.amount).toEqual('10000.000000000000000000'); - expect(res.body.rawAmount).toEqual('10000000000000000000000'); - }); - }); - - it('should return 200 for SELL', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchEstimateSellTrade(); - patchGetNonce(); - patchExecuteTrade(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - side: 'SELL', - }) - .set('Accept', 'application/json') - .expect(200) - .then((res: any) => { - expect(res.body.amount).toEqual('10000.000000000000000000'); - expect(res.body.rawAmount).toEqual('10000000000000000000000'); - }); - }); - - it('should return 500 for unrecognized quote symbol', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: 'DOGE', - base: 'WONE74', - amount: '10000', - side: 'SELL', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 for unrecognized base symbol', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'SHIBA', - amount: '10000', - side: 'SELL', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 for unrecognized base symbol with decimals in the amount and SELL', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'SHIBA', - amount: '10.000', - side: 'SELL', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 for unrecognized base symbol with decimals in the amount and BUY', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'SHIBA', - amount: '10.000', - side: 'BUY', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 when the priceSwapIn operation fails', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(defikingdoms, 'priceSwapIn', () => { - return 'error'; - }); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: 'DOGE', - base: 'WONE74', - amount: '10000', - side: 'SELL', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 when the priceSwapOut operation fails', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(defikingdoms, 'priceSwapOut', () => { - return 'error'; - }); - - await request(app) - .post(`/amm/price`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: 'DOGE', - base: 'WONE74', - amount: '10000', - side: 'BUY', - }) - .set('Accept', 'application/json') - .expect(500); - }); -}); - -describe('POST /amm/trade', () => { - const patchForBuy = () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchEstimateBuyTrade(); - patchGetNonce(); - patchExecuteTrade(); - }; - it('should return 200 for BUY', async () => { - patchForBuy(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - nonce: 21, - }) - .set('Accept', 'application/json') - .expect(200) - .then((res: any) => { - expect(res.body.nonce).toEqual(21); - }); - }); - - it('should return 200 for BUY without nonce parameter', async () => { - patchForBuy(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 200 for BUY with maxFeePerGas and maxPriorityFeePerGas', async () => { - patchForBuy(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - nonce: 21, - maxFeePerGas: '5000000000', - maxPriorityFeePerGas: '5000000000', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - const patchForSell = () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchEstimateSellTrade(); - patchGetNonce(); - patchExecuteTrade(); - }; - it('should return 200 for SELL', async () => { - patchForSell(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'SELL', - nonce: 21, - }) - .set('Accept', 'application/json') - .expect(200) - .then((res: any) => { - expect(res.body.nonce).toEqual(21); - }); - }); - - it('should return 200 for SELL with maxFeePerGas and maxPriorityFeePerGas', async () => { - patchForSell(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'SELL', - nonce: 21, - maxFeePerGas: '5000000000', - maxPriorityFeePerGas: '5000000000', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 200 for SELL with limitPrice', async () => { - patchForSell(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'SELL', - nonce: 21, - limitPrice: '9', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 200 for BUY with limitPrice', async () => { - patchForBuy(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - nonce: 21, - limitPrice: '999999999999999999999', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 500 for BUY with price smaller than limitPrice', async () => { - patchForBuy(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - nonce: 21, - limitPrice: '9', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 for SELL with price higher than limitPrice', async () => { - patchForSell(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'SELL', - nonce: 21, - limitPrice: '99999999999', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 404 when parameters are incorrect', async () => { - patchInit(); - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: 10000, - address: 'da8', - side: 'comprar', - }) - .set('Accept', 'application/json') - .expect(404); - }); - it('should return 500 when the priceSwapIn operation fails', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(defikingdoms, 'priceSwapIn', () => { - return 'error'; - }); - - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'SELL', - nonce: 21, - maxFeePerGas: '5000000000', - maxPriorityFeePerGas: '5000000000', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 500 when the priceSwapOut operation fails', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(defikingdoms, 'priceSwapOut', () => { - return 'error'; - }); - - await request(app) - .post(`/amm/trade`) - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - quote: '1ETH', - base: 'WONE74', - amount: '10000', - address, - side: 'BUY', - nonce: 21, - maxFeePerGas: '5000000000', - maxPriorityFeePerGas: '5000000000', - }) - .set('Accept', 'application/json') - .expect(500); - }); -}); - -describe('POST /amm/estimateGas', () => { - it('should return 200 for valid connector', async () => { - patchInit(); - patchGasPrice(); - - await request(app) - .post('/amm/estimateGas') - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'defikingdoms', - }) - .set('Accept', 'application/json') - .expect(200) - .then((res: any) => { - expect(res.body.network).toEqual('testnet'); - expect(res.body.gasPrice).toEqual(100); - expect(res.body.gasCost).toEqual( - gasCostInEthString(100, defikingdoms.gasLimitEstimate) - ); - }); - }); - - it('should return 500 for invalid connector', async () => { - patchInit(); - patchGasPrice(); - - await request(app) - .post('/amm/estimateGas') - .send({ - chain: 'harmony', - network: 'testnet', - connector: 'pangolin', - }) - .set('Accept', 'application/json') - .expect(500); - }); -}); diff --git a/test/connectors/defikingdoms/defikingdoms.test.ts b/test/connectors/defikingdoms/defikingdoms.test.ts deleted file mode 100644 index ce95a4fee7..0000000000 --- a/test/connectors/defikingdoms/defikingdoms.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -jest.useFakeTimers(); -import { Defikingdoms } from '../../../src/connectors/defikingdoms/defikingdoms'; -import { patch, unpatch } from '../../services/patch'; -import { UniswapishPriceError } from '../../../src/services/error-handler'; -import { - Token, - TokenAmount, - TradeType, - Trade, - Pair, - Route, - Percent, -} from '@switchboard-xyz/defikingdoms-sdk'; -import { BigNumber } from 'ethers'; -import { Harmony } from '../../../src/chains/harmony/harmony'; -import { patchEVMNonceManager } from '../../evm.nonce.mock'; -import { DefikingdomsConfig } from '../../../src/connectors/defikingdoms/defikingdoms.config'; - -let harmony: Harmony; -let defikingdoms: Defikingdoms; - -const WONE = new Token( - 1666700000, - '0x7466d7d0C21Fa05F32F5a0Fa27e12bdC06348Ce2', - 18, - 'WONE' -); -const ETH = new Token( - 1666700000, - '0x1E120B3b4aF96e7F394ECAF84375b1C661830013', - 18, - 'ETH' -); - -beforeAll(async () => { - harmony = Harmony.getInstance('testnet'); - patchEVMNonceManager(harmony.nonceManager); - - defikingdoms = Defikingdoms.getInstance('harmony', 'testnet'); - await defikingdoms.init(); -}); - -beforeEach(() => { - patchEVMNonceManager(harmony.nonceManager); -}); - -afterEach(() => { - unpatch(); -}); - -afterAll(async () => { - await harmony.close(); -}); - -const patchFetchData = () => { - patch(defikingdoms, 'fetchPairData', () => { - return new Pair( - new TokenAmount(WONE, '2000000000000000000'), - new TokenAmount(ETH, '1000000000000000000') - ); - }); -}; - -const patchTrade = (key: string, error?: Error) => { - patch(Trade, key, () => { - if (error) return []; - const WONE_ETH = new Pair( - new TokenAmount(WONE, '2000000000000000000'), - new TokenAmount(ETH, '1000000000000000000') - ); - const ETH_TO_WONE = new Route([WONE_ETH], ETH, WONE); - return [ - new Trade( - ETH_TO_WONE, - new TokenAmount(ETH, '1000000000000000'), - TradeType.EXACT_INPUT - ), - ]; - }); -}; - -describe('verify defikingdoms gasLimit', () => { - it('Should initially match the config for mainnet', () => { - expect(defikingdoms.gasLimitEstimate).toEqual( - DefikingdomsConfig.config.gasLimit - ); - }); -}); - -describe('verify defikingdoms getAllowedSlippage', () => { - it('Should parse simple fractions', () => { - expect(defikingdoms.getAllowedSlippage('3/100')).toEqual( - new Percent('3', '100') - ); - }); -}); - -describe('verify defikingdoms estimateSellTrade', () => { - it('Should return an ExpectedTrade when available', async () => { - patchFetchData(); - patchTrade('bestTradeExactIn'); - - const expectedTrade = await defikingdoms.estimateSellTrade( - WONE, - ETH, - BigNumber.from(1) - ); - expect(expectedTrade).toHaveProperty('trade'); - expect(expectedTrade).toHaveProperty('expectedAmount'); - }); - - it('Should throw an error if no pair is available', async () => { - patchFetchData(); - patchTrade('bestTradeExactIn', new Error('error getting trade')); - - await expect(async () => { - await defikingdoms.estimateSellTrade(WONE, ETH, BigNumber.from(1)); - }).rejects.toThrow(UniswapishPriceError); - }); -}); - -describe('verify defikingdoms estimateBuyTrade', () => { - it('Should return an ExpectedTrade when available', async () => { - patchFetchData(); - patchTrade('bestTradeExactOut'); - - const expectedTrade = await defikingdoms.estimateBuyTrade( - WONE, - ETH, - BigNumber.from(1) - ); - expect(expectedTrade).toHaveProperty('trade'); - expect(expectedTrade).toHaveProperty('expectedAmount'); - }); - - it('Should return an error if no pair is available', async () => { - patchFetchData(); - patchTrade('bestTradeExactOut', new Error('error getting trade')); - - await expect(async () => { - await defikingdoms.estimateBuyTrade(WONE, ETH, BigNumber.from(1)); - }).rejects.toThrow(UniswapishPriceError); - }); -}); - -describe('verify defikingdoms Token List', () => { - it('Should return a token by address', async () => { - const token = defikingdoms.getTokenByAddress(ETH.address); - expect(token).toBeInstanceOf(Token); - }); -}); diff --git a/test/connectors/zigzag/zigzag.test.ts b/test/connectors/zigzag/zigzag.test.ts deleted file mode 100644 index a7c2876e6d..0000000000 --- a/test/connectors/zigzag/zigzag.test.ts +++ /dev/null @@ -1,435 +0,0 @@ -import { ZigZag, ZigZagOrder } from '../../../src/connectors/zigzag/zigzag'; -import { patch, unpatch } from '../../services/patch'; -import { Ethereum } from '../../../src/chains/ethereum/ethereum'; -import { patchEVMNonceManager } from '../../evm.nonce.mock'; -import { BigNumber } from 'ethers'; -import { floatStringWithDecimalToBigNumber } from '../../../src/services/base'; -import { Token } from '@uniswap/sdk-core'; -import { EVMTxBroadcaster } from '../../../src/chains/ethereum/evm.broadcaster'; -import { - price, - trade, -} from '../../../src/connectors/zigzag/zigzag.controllers'; - -let ethereum: Ethereum; -let zigzag: ZigZag; - -const TX_HASH = - '0xf6f81a37796bd06a797484467302e4d6f72832409545e2e01feb86dd8b22e4b2'; // noqa: mock - -const address: string = '0xFaA12FD102FE8623C9299c72B03E45107F2772B5'; - -const ORDERS = { - orders: [ - // ZZ-USDT orders, never expire - { - hash: '0x4bc2e2e8af7378069c16635d29172f32d2afd080f6b138b0660e56d6de19c263', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xada42bb73b42e0472a994218fb3799dfcda21237', - sellToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0x3fcf8822dcfa2eac24f5dd68aabf30cff06348da93cc9e1af5824acff8e36795431a6ec8654384c4f0da10d769feb563b325d9c10bb7db4930a4647c14b816df1c', - }, - { - hash: '0xdfda8ce96d129bf219cfa4e1700a355946d95ef0f0a891c3e5e463e5f66561e6', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xada42bb73b42e0472a994218fb3799dfcda21237', - sellToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0xc59491ac88ea0322053934616e209d7d891c2329a46aab34c9b55c2beaeda614477bdf5ec388bdced0df6c5febc2d3ead10b3576df3a57ed0030d055850902401b', - }, - // WETH-USDT orders, never expire - { - hash: '0x4bc2e2e8af7378069c16635d29172f32d2afd080f6b138b0660e56d6de19c263', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - sellToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0x3fcf8822dcfa2eac24f5dd68aabf30cff06348da93cc9e1af5824acff8e36795431a6ec8654384c4f0da10d769feb563b325d9c10bb7db4930a4647c14b816df1c', - }, - { - hash: '0xdfda8ce96d129bf219cfa4e1700a355946d95ef0f0a891c3e5e463e5f66561e6', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - sellToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0xc59491ac88ea0322053934616e209d7d891c2329a46aab34c9b55c2beaeda614477bdf5ec388bdced0df6c5febc2d3ead10b3576df3a57ed0030d055850902401b', - }, - // USDT-ZZLP orders, never expire - { - hash: '0x4bc2e2e8af7378069c16635d29172f32d2afd080f6b138b0660e56d6de19c263', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - sellToken: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0x3fcf8822dcfa2eac24f5dd68aabf30cff06348da93cc9e1af5824acff8e36795431a6ec8654384c4f0da10d769feb563b325d9c10bb7db4930a4647c14b816df1c', - }, - { - hash: '0xdfda8ce96d129bf219cfa4e1700a355946d95ef0f0a891c3e5e463e5f66561e6', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - sellToken: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '1234567890123456789', - }, - signature: - '0xc59491ac88ea0322053934616e209d7d891c2329a46aab34c9b55c2beaeda614477bdf5ec388bdced0df6c5febc2d3ead10b3576df3a57ed0030d055850902401b', - }, - // ZZ-WETH orders, expired - { - hash: '0x4bc2e2e8af7378069c16635d29172f32d2afd080f6b138b0660e56d6de19c263', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xada42bb73b42e0472a994218fb3799dfcda21237', - sellToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '0', - }, - signature: - '0x3fcf8822dcfa2eac24f5dd68aabf30cff06348da93cc9e1af5824acff8e36795431a6ec8654384c4f0da10d769feb563b325d9c10bb7db4930a4647c14b816df1c', - }, - { - hash: '0xdfda8ce96d129bf219cfa4e1700a355946d95ef0f0a891c3e5e463e5f66561e6', - order: { - user: '0x27a2c7121e287478375Ec8c64FDfA31E97038c03', - buyToken: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - sellToken: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - buyAmount: '1666018405396825073694', - sellAmount: '500507844', - expirationTimeSeconds: '0', - }, - signature: - '0xc59491ac88ea0322053934616e209d7d891c2329a46aab34c9b55c2beaeda614477bdf5ec388bdced0df6c5febc2d3ead10b3576df3a57ed0030d055850902401b', - }, - ], -}; - -const WETH = new Token( - 0, - '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - 18, - 'WETH', - - 'Wrapped Ether' -); - -const ZZ = new Token( - 0, - '0xada42bb73b42e0472a994218fb3799dfcda21237', - 18, - 'ZZ', - 'ZigZag' -); - -const ZZLP = new Token( - 0, - '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - 18, - 'ZZLP', - 'ZigZag LP' -); - -const USDT = new Token( - 0, - '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - 6, - 'USDT', - 'Tether USD' -); - -const patchInit = () => { - patch(zigzag, 'init', async () => { - return; - }); -}; - -const patchStoredTokenList = () => { - patch(zigzag, 'tokenList', { - [WETH.address.toLowerCase()]: WETH, - [ZZ.address.toLowerCase()]: ZZ, - [ZZLP.address.toLowerCase()]: ZZLP, - [USDT.address.toLowerCase()]: USDT, - }); -}; - -const patchMarkets = () => { - patch(zigzag, 'markets', [ - ZZ.address.toLowerCase() + '-' + WETH.address.toLowerCase(), - ZZ.address.toLowerCase() + '-' + USDT.address.toLowerCase(), - USDT.address.toLowerCase() + '-' + ZZLP.address.toLowerCase(), - WETH.address.toLowerCase() + '-' + ZZLP.address.toLowerCase(), - WETH.address.toLowerCase() + '-' + USDT.address.toLowerCase(), - ]); -}; - -const patchGetMarketOrders = () => { - patch( - zigzag, - 'getMarketOrders', - ( - buyTokenAddress: string, - sellTokenAddress: string, - _minExpires: number - ) => { - return ORDERS.orders.filter( - (order: ZigZagOrder) => - order.order.buyToken === buyTokenAddress && - order.order.sellToken === sellTokenAddress - ); - } - ); -}; - -const patchMsgBroadcaster = () => { - patch(EVMTxBroadcaster, 'getInstance', () => { - return { - broadcast() { - return { - hash: TX_HASH, - }; - }, - }; - }); -}; - -const patchGetWallet = () => { - patch(ethereum, 'getWallet', () => { - return { - address, - }; - }); -}; - -beforeAll(async () => { - ethereum = Ethereum.getInstance('arbitrum_one'); - patchEVMNonceManager(ethereum.nonceManager); - await ethereum.init(); - - zigzag = ZigZag.getInstance('arbitrum_one'); - patchInit(); - await zigzag.init(); -}); - -beforeEach(() => { - patchInit(); - patchStoredTokenList(); - patchMarkets(); - patchEVMNonceManager(ethereum.nonceManager); -}); - -afterEach(() => { - unpatch(); -}); - -afterAll(async () => { - await ethereum.close(); -}); - -describe('getPossibleRoutes', () => { - it('ZZ-WETH has a direct route', async () => { - const routes = zigzag.getPossibleRoutes(ZZ, WETH); - expect(routes).toEqual([ - [ - { - buyTokenAddress: ZZ.address.toLowerCase(), - sellTokenAddress: WETH.address.toLowerCase(), - }, - ], - ]); - }); - - it('ZZ-ZZLP has two indirect routes', async () => { - const routes = zigzag.getPossibleRoutes(ZZ, ZZLP); - expect(routes).toEqual([ - [ - { - buyTokenAddress: ZZ.address.toLowerCase(), - sellTokenAddress: WETH.address.toLowerCase(), - }, - { - buyTokenAddress: WETH.address.toLowerCase(), - sellTokenAddress: ZZLP.address.toLowerCase(), - }, - ], - [ - { - buyTokenAddress: ZZ.address.toLowerCase(), - sellTokenAddress: USDT.address.toLowerCase(), - }, - { - buyTokenAddress: USDT.address.toLowerCase(), - sellTokenAddress: ZZLP.address.toLowerCase(), - }, - ], - ]); - }); -}); - -describe('getOrderBook', () => { - it('ZZ-WETH return no orders, they are expired', async () => { - patchGetMarketOrders(); - const orders = await zigzag.getOrderBook([ - [{ buyTokenAddress: ZZ.address, sellTokenAddress: WETH.address }], - ]); - const result: { [key: string]: Array } = {}; - result[ZZ.address + '-' + WETH.address] = []; - expect(orders).toEqual(result); - }); - - it('ZZ-USDT returns two orders, they never expire', async () => { - patchGetMarketOrders(); - const orders = await zigzag.getOrderBook([ - [{ buyTokenAddress: ZZ.address, sellTokenAddress: USDT.address }], - ]); - const result: { [key: string]: Array } = {}; - result[ZZ.address + '-' + USDT.address] = ORDERS.orders.filter( - (order: ZigZagOrder) => - order.order.buyToken === ZZ.address && - order.order.sellToken === USDT.address - ); - expect(orders).toEqual(result); - }); -}); - -describe('estimate', () => { - it('Estimate ZZ-USDT sell', async () => { - patchGetMarketOrders(); - const one = floatStringWithDecimalToBigNumber('1', ZZ.decimals); - const estimate = await zigzag.estimate(ZZ, USDT, one, 'sell'); - expect(estimate.newSwapPrice).toEqual(0.30042155739617127); - }); - - it('Estimate ZZ-USDT buy', async () => { - patchGetMarketOrders(); - const one = floatStringWithDecimalToBigNumber('1', USDT.decimals); - const estimate = await zigzag.estimate(ZZ, USDT, one, 'buy'); - expect(estimate.newSwapPrice).toEqual(3.3286559349044387); - }); -}); - -describe('executeTrade', () => { - it('Execute ZZ-USDT sell trade', async () => { - patchGetMarketOrders(); - patchMsgBroadcaster(); - const one = floatStringWithDecimalToBigNumber('1', ZZ.decimals); - const estimate = await zigzag.estimate(ZZ, USDT, one, 'sell'); - const trade = await zigzag.executeTrade( - '', - estimate, - one, - false - ); - expect(estimate.newSwapPrice).toEqual(0.30042155739617127); - expect(trade.hash).toEqual(TX_HASH); - }); - - it('Execute ZZ-USDT buy trade', async () => { - patchGetMarketOrders(); - patchMsgBroadcaster(); - const one = floatStringWithDecimalToBigNumber('1', USDT.decimals); - const estimate = await zigzag.estimate(ZZ, USDT, one, 'buy'); - const trade = await zigzag.executeTrade('', estimate, one, true); - expect(estimate.newSwapPrice).toEqual(3.3286559349044387); - expect(trade.hash).toEqual(TX_HASH); - }); - - it('Execute ZZ-ZZLP sell trade(multi-order)', async () => { - patchGetMarketOrders(); - patchMsgBroadcaster(); - const one = floatStringWithDecimalToBigNumber('1', 1); - const estimate = await zigzag.estimate(ZZ, ZZLP, one, 'sell'); - const trade = await zigzag.executeTrade( - '', - estimate, - one, - false - ); - expect(estimate.newSwapPrice).toEqual(9.025311214834104e-26); - expect(trade.hash).toEqual(TX_HASH); - }); - - it('Execute ZZ-ZZLP buy trade(multi-order)', async () => { - patchGetMarketOrders(); - patchMsgBroadcaster(); - const one = floatStringWithDecimalToBigNumber('1', 1); - const estimate = await zigzag.estimate(ZZ, ZZLP, one, 'buy'); - const trade = await zigzag.executeTrade('', estimate, one, true); - expect(estimate.newSwapPrice).toEqual(1.1079950332974543e25); - expect(trade.hash).toEqual(TX_HASH); - }); -}); - -describe('controller tests', () => { - it('price test', async () => { - patchGetMarketOrders(); - const priceResult = await price(ethereum, zigzag, { - connector: 'zigzag', - chain: 'ethereum', - network: 'arbitrum_one', - quote: 'USDT', - base: 'WETH', - amount: '2', - side: 'SELL', - }); - expect(priceResult.base).toEqual( - '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1' - ); - expect(priceResult.quote).toEqual( - '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' - ); - expect(priceResult.rawAmount).toEqual('2000000000000000000'); - expect(priceResult.price).toEqual('0.30042155739617127'); - }); - - it('trade test', async () => { - patchGetMarketOrders(); - patchGetWallet(); - patchMsgBroadcaster(); - const tradeResult = await trade(ethereum, zigzag, { - address: address, - quote: 'USDT', - base: 'WETH', - amount: '1', - side: 'SELL', - chain: 'ethereum', - network: 'arbitrum_one', - connector: 'zigzag', - }); - expect(tradeResult.base).toEqual( - '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1' - ); - expect(tradeResult.quote).toEqual( - '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' - ); - expect(tradeResult.rawAmount).toEqual('1000000000000000000'); - expect(tradeResult.txHash).toEqual(TX_HASH); - }); -}); From 9acb7e09a91a6e22351599f69ad51067acca8d14 Mon Sep 17 00:00:00 2001 From: nikita Date: Mon, 17 Jul 2023 08:52:49 +0000 Subject: [PATCH 13/17] remove zigzag --- src/amm/amm.controllers.ts | 17 ++++------------- src/chains/ethereum/ethereum.ts | 3 --- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/amm/amm.controllers.ts b/src/amm/amm.controllers.ts index 74f3d927ab..23c0d434b2 100644 --- a/src/amm/amm.controllers.ts +++ b/src/amm/amm.controllers.ts @@ -65,12 +65,7 @@ import { RefAMMish, Uniswapish, UniswapLPish, - ZigZagish, } from '../services/common-interfaces'; -import { - price as zigzagPrice, - trade as zigzagTrade, -} from '../connectors/zigzag/zigzag.controllers'; import { Algorand } from '../chains/algorand/algorand'; import { Tinyman } from '../connectors/tinyman/tinyman'; @@ -79,8 +74,8 @@ export async function price(req: PriceRequest): Promise { req.chain, req.network ); - const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish = - await getConnector( + const connector: Uniswapish | RefAMMish | Tinyman = + await getConnector( req.chain, req.network, req.connector @@ -89,8 +84,6 @@ export async function price(req: PriceRequest): Promise { // we currently use the presence of routerAbi to distinguish Uniswapish from RefAMMish if ('routerAbi' in connector) { return uniswapPrice(chain, connector, req); - } else if ('estimate' in connector) { - return zigzagPrice(chain, connector as any, req); } else if (connector instanceof Tinyman) { return tinymanPrice(chain as unknown as Algorand, connector, req); } else { @@ -103,8 +96,8 @@ export async function trade(req: TradeRequest): Promise { req.chain, req.network ); - const connector: Uniswapish | RefAMMish | Tinyman | ZigZagish = - await getConnector( + const connector: Uniswapish | RefAMMish | Tinyman = + await getConnector( req.chain, req.network, req.connector @@ -113,8 +106,6 @@ export async function trade(req: TradeRequest): Promise { // we currently use the presence of routerAbi to distinguish Uniswapish from RefAMMish if ('routerAbi' in connector) { return uniswapTrade(chain, connector, req); - } else if ('estimate' in connector) { - return zigzagTrade(chain, connector as any, req); } else if (connector instanceof Tinyman) { return tinymanTrade(chain as unknown as Algorand, connector, req); } else { diff --git a/src/chains/ethereum/ethereum.ts b/src/chains/ethereum/ethereum.ts index 915d6dfddb..383299a613 100644 --- a/src/chains/ethereum/ethereum.ts +++ b/src/chains/ethereum/ethereum.ts @@ -13,7 +13,6 @@ import { UniswapConfig } from '../../connectors/uniswap/uniswap.config'; import { Perp } from '../../connectors/perp/perp'; import { SushiswapConfig } from '../../connectors/sushiswap/sushiswap.config'; import { OpenoceanConfig } from '../../connectors/openocean/openocean.config'; -import { ZigZagConfig } from '../../connectors/zigzag/zigzag.config'; // MKR does not match the ERC20 perfectly so we need to use a separate ABI. const MKR_ADDRESS = '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2'; @@ -197,8 +196,6 @@ export class Ethereum extends EthereumBase implements Ethereumish { spender = perp.perp.contracts.vault.address; } else if (reqSpender === 'openocean') { spender = OpenoceanConfig.config.routerAddress('ethereum', this._chain); - } else if (reqSpender === 'zigzag') { - spender = ZigZagConfig.config.contractAddress(this._chain); } else { spender = reqSpender; } From d2ee22def88422a1abdba338e166a7fc95ecbc35 Mon Sep 17 00:00:00 2001 From: nikita Date: Mon, 17 Jul 2023 09:10:27 +0000 Subject: [PATCH 14/17] remove zigzag config --- src/connectors/connectors.routes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/connectors/connectors.routes.ts b/src/connectors/connectors.routes.ts index b05f53d52b..2c3244cd7a 100644 --- a/src/connectors/connectors.routes.ts +++ b/src/connectors/connectors.routes.ts @@ -18,7 +18,6 @@ import { InjectiveCLOBConfig } from './injective/injective.clob.config'; import { XsswapConfig } from './xsswap/xsswap.config'; import { ConnectorsResponse } from './connectors.request'; import { DexalotCLOBConfig } from './dexalot/dexalot.clob.config'; -import { ZigZagConfig } from './zigzag/zigzag.config'; import { TinymanConfig } from './tinyman/tinyman.config'; export namespace ConnectorsRoutes { From 0c5ab3ef42a6a653629f62afb30e6a370fc97aec Mon Sep 17 00:00:00 2001 From: nikita Date: Mon, 17 Jul 2023 09:11:23 +0000 Subject: [PATCH 15/17] remove zigzag configs --- src/services/connection-manager.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/services/connection-manager.ts b/src/services/connection-manager.ts index 6d0c89912c..82a78d2503 100644 --- a/src/services/connection-manager.ts +++ b/src/services/connection-manager.ts @@ -130,7 +130,6 @@ export type ConnectorUnion = | Perpish | RefAMMish | CLOBish - | ZigZag | InjectiveClobPerp | Tinyman; @@ -144,8 +143,6 @@ export type Connector = T extends Uniswapish ? RefAMMish : T extends CLOBish ? CLOBish - : T extends ZigZag - ? ZigZag : T extends InjectiveClobPerp ? InjectiveClobPerp : T extends Tinyman From 39f62e7da8e38ded7adcaa83c64f257ca19355af Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Mon, 17 Jul 2023 09:09:45 -0700 Subject: [PATCH 16/17] (fix) remove defikingdoms lib --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c4c0e1ec69..e00ed8c06a 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "@pangolindex/sdk": "^1.1.0", "@perp/sdk-curie": "^1.16.0", "@sushiswap/sdk": "^5.0.0-canary.116", - "@switchboard-xyz/defikingdoms-sdk": "^1.0.7", "@tinymanorg/tinyman-js-sdk": "^3.0.0", "@traderjoe-xyz/sdk-v2": "^2.0.5", "@types/fs-extra": "^9.0.13", From 6022430346c81d32d0cb2520dd7445b5a27a7217 Mon Sep 17 00:00:00 2001 From: nikspz <83953535+nikspz@users.noreply.github.com> Date: Mon, 24 Jul 2023 17:38:54 +0700 Subject: [PATCH 17/17] fix/ Update package.json version to 1.18.0 on staging --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e00ed8c06a..6b056f7af4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hummingbot-gateway", - "version": "1.17.0", + "version": "1.18.0", "description": "Middleware that helps Hummingbot clients access standardized DEX API endpoints on different blockchain networks", "main": "index.js", "license": "Apache-2.0",