diff --git a/src/dex/index.ts b/src/dex/index.ts index 432b433dc..267d531cf 100644 --- a/src/dex/index.ts +++ b/src/dex/index.ts @@ -91,11 +91,11 @@ import { ConcentratorArusd } from './concentrator-arusd/concentrator-arusd'; import { FxProtocolRusd } from './fx-protocol-rusd/fx-protocol-rusd'; import { AaveGsm } from './aave-gsm/aave-gsm'; import { LitePsm } from './lite-psm/lite-psm'; -import { UsualBond } from './usual-bond/usual-bond'; import { StkGHO } from './stkgho/stkgho'; import { SkyConverter } from './sky-converter/sky-converter'; -import { UsualMSmartM } from './usual-m-smart-m/usual-m-smart-m'; -import { UsualMUsd0 } from './usual-m-usd0/usual-m-usd0'; +import { UsualBond } from './usual/usual-bond'; +import { UsualMSmartM } from './usual/usual-m-smart-m'; +import { UsualMUsd0 } from './usual/usual-m-usd0'; const LegacyDexes = [ CurveV2, diff --git a/src/dex/usual/types.ts b/src/dex/usual/types.ts new file mode 100644 index 000000000..ef8151986 --- /dev/null +++ b/src/dex/usual/types.ts @@ -0,0 +1,10 @@ +import { Address } from '../../types'; + +export type PoolState = {}; + +export type UsualBondData = {}; + +export type DexParams = { + fromToken: { address: Address; decimals: number }; + toToken: { address: Address; decimals: number }; +}; diff --git a/src/dex/usual/usual-bond.ts b/src/dex/usual/usual-bond.ts new file mode 100644 index 000000000..ac39a92bc --- /dev/null +++ b/src/dex/usual/usual-bond.ts @@ -0,0 +1,69 @@ +import { + Address, + NumberAsString, + DexExchangeParam, + DexConfigMap, +} from '../../types'; +import { SwapSide, Network } from '../../constants'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { UsualBondData, DexParams } from './types'; +import { Interface, JsonFragment } from '@ethersproject/abi'; +import USD0PP_ABI from '../../abi/usual-bond/usd0pp.abi.json'; +import { Usual } from './usual'; +import { getDexKeysWithNetwork } from '../../utils'; + +const Config: DexConfigMap = { + UsualBond: { + [Network.MAINNET]: { + fromToken: { + address: '0x73a15fed60bf67631dc6cd7bc5b6e8da8190acf5', + decimals: 18, + }, + toToken: { + address: '0x35d8949372d46b7a3d5a56006ae77b215fc69bc0', + decimals: 18, + }, + }, + }, +}; + +export class UsualBond extends Usual { + public static dexKeysWithNetwork: { key: string; networks: Network[] }[] = + getDexKeysWithNetwork(Config); + + usd0ppIface: Interface; + + constructor( + readonly network: Network, + readonly dexKey: string, + readonly dexHelper: IDexHelper, + ) { + super(network, dexKey, dexHelper, Config[dexKey][network]); + this.usd0ppIface = new Interface(USD0PP_ABI as JsonFragment[]); + } + + async getDexParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + recipient: Address, + data: UsualBondData, + side: SwapSide, + ): Promise { + if (this.isFromToken(srcToken) && this.isToToken(destToken)) { + const exchangeData = this.usd0ppIface.encodeFunctionData('mint', [ + srcAmount, + ]); + + return { + needWrapNative: false, + dexFuncHasRecipient: false, + exchangeData, + targetExchange: this.config.toToken.address, + returnAmountPos: undefined, + }; + } + throw new Error('LOGIC ERROR'); + } +} diff --git a/src/dex/usual/usual-e2e.test.ts b/src/dex/usual/usual-e2e.test.ts new file mode 100644 index 000000000..3b918308b --- /dev/null +++ b/src/dex/usual/usual-e2e.test.ts @@ -0,0 +1,122 @@ +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { testE2E } from '../../../tests/utils-e2e'; +import { Tokens, Holders } from '../../../tests/constants-e2e'; +import { Network, ContractMethod, SwapSide } from '../../constants'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { generateConfig } from '../../config'; + +function testForNetwork( + network: Network, + dexKey: string, + tokenASymbol: string, + tokenBSymbol: string, + tokenAAmount: string, + tokenBAmount: string, +) { + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + const tokens = Tokens[network]; + const holders = Holders[network]; + + const sideToContractMethods = new Map([ + [SwapSide.SELL, [ContractMethod.swapExactAmountIn]], + ]); + + describe(`${network}`, () => { + sideToContractMethods.forEach((contractMethods, side) => + describe(`${side}`, () => { + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }); + }), + ); + }); +} + +describe('UsualBond E2E', () => { + const dexKey = 'UsualBond'; + + describe('Mainnet', () => { + const network = Network.MAINNET; + + const tokenASymbol: string = 'USD0'; + const tokenBSymbol: string = 'USD0++'; + + const tokenAAmount: string = '100000'; + const tokenBAmount: string = '100000'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + ); + }); +}); + +describe('UsualMSmartM E2E', () => { + const dexKey = 'UsualMSmartM'; + + describe('Mainnet', () => { + const network = Network.MAINNET; + + const tokenASymbol: string = 'SmartM'; + const tokenBSymbol: string = 'UsualM'; + + const tokenAAmount: string = '100000'; + const tokenBAmount: string = '100000'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + ); + }); +}); + +describe('UsualM<>Usd0 E2E', () => { + const dexKey = 'UsualMUsd0'; + + describe('Mainnet', () => { + const network = Network.MAINNET; + + const tokenASymbol: string = 'UsualM'; + const tokenBSymbol: string = 'USD0'; + + const tokenAAmount: string = '100000'; + const tokenBAmount: string = '100000'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + ); + }); +}); diff --git a/src/dex/usual/usual-integration.test.ts b/src/dex/usual/usual-integration.test.ts new file mode 100644 index 000000000..e3c741d85 --- /dev/null +++ b/src/dex/usual/usual-integration.test.ts @@ -0,0 +1,319 @@ +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { Interface } from '@ethersproject/abi'; +import { DummyDexHelper } from '../../dex-helper/index'; +import { Network, SwapSide } from '../../constants'; +import { BI_POWS } from '../../bigint-constants'; +import { + checkPoolPrices, + checkConstantPoolPrices, + checkPoolsLiquidity, +} from '../../../tests/utils'; +import { Tokens } from '../../../tests/constants-e2e'; +import { UsualMSmartM } from './usual-m-smart-m'; +import { UsualMUsd0 } from './usual-m-usd0'; +import { Usual } from './usual'; +import { UsualBond } from './usual-bond'; + +async function testPricingOnNetwork( + usual: Usual, + network: Network, + dexKey: string, + blockNumber: number, + srcTokenSymbol: string, + destTokenSymbol: string, + side: SwapSide, + amounts: bigint[], + funcNameToCheck: string, +) { + const networkTokens = Tokens[network]; + + console.log(amounts); + + const pools = await usual.getPoolIdentifiers( + networkTokens[srcTokenSymbol], + networkTokens[destTokenSymbol], + side, + blockNumber, + ); + console.log( + `${srcTokenSymbol} <> ${destTokenSymbol} Pool Identifiers: `, + pools, + ); + + expect(pools.length).toBeGreaterThan(0); + + const poolPrices = await usual.getPricesVolume( + networkTokens[srcTokenSymbol], + networkTokens[destTokenSymbol], + amounts, + side, + blockNumber, + pools, + ); + console.log( + `${srcTokenSymbol} <> ${destTokenSymbol} Pool Prices: `, + poolPrices, + ); + + expect(poolPrices).not.toBeNull(); + if (usual.hasConstantPriceLargeAmounts) { + checkConstantPoolPrices(poolPrices!, amounts, dexKey); + } else { + checkPoolPrices(poolPrices!, amounts, side, dexKey); + } + + // Check if onchain pricing equals to calculated ones + checkPoolPrices(poolPrices!, amounts, side, dexKey); +} + +describe('UsualBond', function () { + const dexKey = 'UsualBond'; + let blockNumber: number; + let usualBond: UsualBond; + + describe('Mainnet', () => { + const network = Network.MAINNET; + const dexHelper = new DummyDexHelper(network); + + // Don't forget to update relevant tokens in constant-e2e.ts + + const amountsForSell = [ + 0n, + 1n * BI_POWS[18], + 2n * BI_POWS[18], + 3n * BI_POWS[18], + 4n * BI_POWS[18], + 5n * BI_POWS[18], + 6n * BI_POWS[18], + 7n * BI_POWS[18], + 8n * BI_POWS[18], + 9n * BI_POWS[18], + 10n * BI_POWS[18], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + usualBond = new UsualBond(network, dexKey, dexHelper); + if (usualBond.initializePricing) { + await usualBond.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + usualBond, + network, + dexKey, + blockNumber, + 'USD0', + 'USD0++', + SwapSide.SELL, + amountsForSell, + '', + ); + }); + + it('getTopPoolsForToken: USD0', async function () { + const tokenA = Tokens[network]['USD0']; + const dexHelper = new DummyDexHelper(network); + const usualBond = new UsualBond(network, dexKey, dexHelper); + + const poolLiquidity = await usualBond.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + + it('getTopPoolsForToken: USD0++', async function () { + const tokenA = Tokens[network]['USD0++']; + const dexHelper = new DummyDexHelper(network); + const usualBond = new UsualBond(network, dexKey, dexHelper); + + const poolLiquidity = await usualBond.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + }); +}); + +describe('SmartM<>UsualM', function () { + const dexKey = 'UsualMSmartM'; + let blockNumber: number; + let usualMSmartM: UsualMSmartM; + + describe('Mainnet', () => { + const network = Network.MAINNET; + const dexHelper = new DummyDexHelper(network); + + // Don't forget to update relevant tokens in constant-e2e.ts + + const amountsForSell = [ + 0n, + 1n * BI_POWS[18], + 2n * BI_POWS[18], + 3n * BI_POWS[18], + 4n * BI_POWS[18], + 5n * BI_POWS[18], + 6n * BI_POWS[18], + 7n * BI_POWS[18], + 8n * BI_POWS[18], + 9n * BI_POWS[18], + 10n * BI_POWS[18], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + usualMSmartM = new UsualMSmartM(network, dexKey, dexHelper); + if (usualMSmartM.initializePricing) { + await usualMSmartM.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + usualMSmartM, + network, + dexKey, + blockNumber, + 'SmartM', + 'UsualM', + SwapSide.SELL, + amountsForSell, + '', + ); + }); + + it('getTopPoolsForToken: SmartM', async function () { + const tokenA = Tokens[network]['SmartM']; + const dexHelper = new DummyDexHelper(network); + const usualMSmartM = new UsualMSmartM(network, dexKey, dexHelper); + + const poolLiquidity = await usualMSmartM.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + + it('getTopPoolsForToken: UsualM', async function () { + const tokenA = Tokens[network]['UsualM']; + const dexHelper = new DummyDexHelper(network); + const usualMSmartM = new UsualMSmartM(network, dexKey, dexHelper); + + const poolLiquidity = await usualMSmartM.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + }); +}); + +describe('UsualM<>USD0', function () { + const dexKey = 'UsualMUsd0'; + let blockNumber: number; + let usualMUsd0: UsualMUsd0; + + describe('Mainnet', () => { + const network = Network.MAINNET; + const dexHelper = new DummyDexHelper(network); + + // Don't forget to update relevant tokens in constant-e2e.ts + + const amountsForSell = [ + 0n, + 1n * BI_POWS[18], + 2n * BI_POWS[18], + 3n * BI_POWS[18], + 4n * BI_POWS[18], + 5n * BI_POWS[18], + 6n * BI_POWS[18], + 7n * BI_POWS[18], + 8n * BI_POWS[18], + 9n * BI_POWS[18], + 10n * BI_POWS[18], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + usualMUsd0 = new UsualMUsd0(network, dexKey, dexHelper); + if (usualMUsd0.initializePricing) { + await usualMUsd0.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + usualMUsd0, + network, + dexKey, + blockNumber, + 'UsualM', + 'USD0', + SwapSide.SELL, + amountsForSell, + '', + ); + }); + + it('getTopPoolsForToken: UsualM', async function () { + const tokenA = Tokens[network]['UsualM']; + const dexHelper = new DummyDexHelper(network); + const usualMUsd0 = new UsualMUsd0(network, dexKey, dexHelper); + + const poolLiquidity = await usualMUsd0.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + + it('getTopPoolsForToken: USD0', async function () { + const tokenA = Tokens[network]['USD0']; + const dexHelper = new DummyDexHelper(network); + const usualMUsd0 = new UsualMUsd0(network, dexKey, dexHelper); + + const poolLiquidity = await usualMUsd0.getTopPoolsForToken( + tokenA.address, + 10, + ); + console.log( + `${tokenA.symbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); + }); + }); +}); diff --git a/src/dex/usual/usual-m-smart-m.ts b/src/dex/usual/usual-m-smart-m.ts new file mode 100644 index 000000000..316211e25 --- /dev/null +++ b/src/dex/usual/usual-m-smart-m.ts @@ -0,0 +1,71 @@ +import { + Address, + NumberAsString, + DexExchangeParam, + DexConfigMap, +} from '../../types'; +import { SwapSide, Network } from '../../constants'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { DexParams } from './types'; +import { Interface, JsonFragment } from '@ethersproject/abi'; +import { Usual } from './usual'; +import { getDexKeysWithNetwork } from '../../utils'; +import USUALM_ABI from '../../abi/usual-m-smart-m/usualM.abi.json'; + +const Config: DexConfigMap = { + UsualMSmartM: { + [Network.MAINNET]: { + fromToken: { + address: '0x437cc33344a0b27a429f795ff6b469c72698b291', + decimals: 6, + }, + toToken: { + address: '0xfe274c305b365dc38e188e8f01c4fae2171ce927', + decimals: 6, + }, + }, + }, +}; + +export class UsualMSmartM extends Usual { + public static dexKeysWithNetwork: { key: string; networks: Network[] }[] = + getDexKeysWithNetwork(Config); + + usualMIface: Interface; + + constructor( + readonly network: Network, + readonly dexKey: string, + readonly dexHelper: IDexHelper, + ) { + super(network, dexKey, dexHelper, Config[dexKey][network]); + this.usualMIface = new Interface(USUALM_ABI as JsonFragment[]); + } + + async getDexParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + recipient: Address, + data: {}, + side: SwapSide, + ): Promise { + if (this.isFromToken(srcToken) && this.isToToken(destToken)) { + const exchangeData = this.usualMIface.encodeFunctionData( + 'wrap(address, uint256)', + [recipient, srcAmount], + ); + + return { + needWrapNative: false, + dexFuncHasRecipient: true, + exchangeData, + targetExchange: this.config.toToken.address, + returnAmountPos: undefined, + }; + } + + throw new Error('LOGIC ERROR'); + } +} diff --git a/src/dex/usual/usual-m-usd0.ts b/src/dex/usual/usual-m-usd0.ts new file mode 100644 index 000000000..a1649d344 --- /dev/null +++ b/src/dex/usual/usual-m-usd0.ts @@ -0,0 +1,76 @@ +import { + Address, + NumberAsString, + DexExchangeParam, + DexConfigMap, +} from '../../types'; +import { SwapSide, Network } from '../../constants'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { DexParams } from './types'; +import { Interface, JsonFragment } from '@ethersproject/abi'; +import { Usual } from './usual'; +import { getDexKeysWithNetwork } from '../../utils'; +import USUAL_DAO_COLLATERAL_ABI from '../../abi/usual-m-usd0/usualCollateralDao.abi.json'; + +const Config: DexConfigMap = + { + UsualMUsd0: { + [Network.MAINNET]: { + usualDaoCollateralAddress: '0xde6e1F680C4816446C8D515989E2358636A38b04', + fromToken: { + address: '0xfe274c305b365dc38e188e8f01c4fae2171ce927', + decimals: 6, + }, + toToken: { + address: '0x73a15fed60bf67631dc6cd7bc5b6e8da8190acf5', + decimals: 18, + }, + }, + }, + }; + +export class UsualMUsd0 extends Usual { + public static dexKeysWithNetwork: { key: string; networks: Network[] }[] = + getDexKeysWithNetwork(Config); + + usualDaoCollateralIface: Interface; + + constructor( + readonly network: Network, + readonly dexKey: string, + readonly dexHelper: IDexHelper, + ) { + super(network, dexKey, dexHelper, Config[dexKey][network]); + this.usualDaoCollateralIface = new Interface( + USUAL_DAO_COLLATERAL_ABI as JsonFragment[], + ); + } + + async getDexParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + recipient: Address, + data: {}, + side: SwapSide, + ): Promise { + if (this.isFromToken(srcToken) && this.isToToken(destToken)) { + const exchangeData = this.usualDaoCollateralIface.encodeFunctionData( + 'swap', + [srcToken, srcAmount, destAmount], + ); + + return { + needWrapNative: false, + dexFuncHasRecipient: false, + exchangeData, + targetExchange: + Config[this.dexKey][this.network].usualDaoCollateralAddress, + returnAmountPos: undefined, + }; + } + + throw new Error('LOGIC ERROR'); + } +} diff --git a/src/dex/usual/usual.ts b/src/dex/usual/usual.ts new file mode 100644 index 000000000..872b75904 --- /dev/null +++ b/src/dex/usual/usual.ts @@ -0,0 +1,156 @@ +import { + Token, + Address, + ExchangePrices, + PoolPrices, + AdapterExchangeParam, + Logger, + PoolLiquidity, +} from '../../types'; +import { SwapSide, Network } from '../../constants'; +import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; +import { IDex } from '../idex'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { UsualBondData, DexParams } from './types'; +import { SimpleExchange } from '../simple-exchange'; +import { BI_POWS } from '../../bigint-constants'; + +export class Usual extends SimpleExchange implements IDex { + readonly hasConstantPriceLargeAmounts = true; + readonly needWrapNative = false; + readonly isFeeOnTransferSupported = false; + + logger: Logger; + + constructor( + readonly network: Network, + readonly dexKey: string, + readonly dexHelper: IDexHelper, + readonly config: DexParams, + ) { + super(dexHelper, dexKey); + this.logger = dexHelper.getLogger(dexKey); + } + + async initializePricing(blockNumber: number) { + // No initialization needed for constant price + } + + isFromToken(token: string) { + return token.toLowerCase() === this.config.fromToken.address.toLowerCase(); + } + + isToToken(token: string) { + return token.toLowerCase() === this.config.toToken.address.toLowerCase(); + } + + isValidTokens(srcToken: string, destToken: string) { + return this.isFromToken(srcToken) && this.isToToken(destToken); + } + + getAdapters() { + return null; + } + + async getPoolIdentifiers( + srcToken: Token, + destToken: Token, + side: SwapSide, + blockNumber: number, + ): Promise { + if (!srcToken || !destToken) { + this.logger.error('Source or destination token is undefined'); + return []; + } + + const srcTokenAddress = srcToken.address?.toLowerCase(); + const destTokenAddress = destToken.address?.toLowerCase(); + + if (!srcTokenAddress || !destTokenAddress) { + this.logger.error('Source or destination token address is undefined'); + return []; + } + + if (this.isValidTokens(srcTokenAddress, destTokenAddress)) { + return [`${this.dexKey}_${this.config.toToken}`]; + } + + return []; + } + + async getPricesVolume( + srcToken: Token, + destToken: Token, + amounts: bigint[], + side: SwapSide, + blockNumber: number, + limitPools?: string[], + ): Promise> { + if (side === SwapSide.BUY) { + return null; + } + + const isValidSwap = this.isValidTokens(srcToken.address, destToken.address); + + if (!isValidSwap) { + return null; + } + + const unitOut = BI_POWS[18]; // 1:1 swap + const amountsOut = amounts; // 1:1 swap, so output amounts are the same as input + + return [ + { + unit: unitOut, + prices: amountsOut, + data: {}, + poolAddresses: [this.config.toToken.address], + exchange: this.dexKey, + gasCost: 70000, + poolIdentifier: this.dexKey, + }, + ]; + } + + getCalldataGasCost(poolPrices: PoolPrices): number | number[] { + return CALLDATA_GAS_COST.DEX_NO_PAYLOAD; + } + + getAdapterParam( + srcToken: string, + destToken: string, + srcAmount: string, + destAmount: string, + data: UsualBondData, + side: SwapSide, + ): AdapterExchangeParam { + const payload = '0x'; + + return { + targetExchange: this.config.toToken.address, + payload, + networkFee: '0', + }; + } + + async getTopPoolsForToken( + tokenAddress: Address, + limit: number, + ): Promise { + const isFromToken = this.isFromToken(tokenAddress); + const isToToken = this.isToToken(tokenAddress); + + if (!(isFromToken || isToToken)) return []; + + return [ + { + exchange: this.dexKey, + address: this.config.toToken.address, + connectorTokens: [ + isFromToken ? this.config.toToken : this.config.fromToken, + ], + liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred + }, + ]; + } +} diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index bf069309d..030395e53 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1738,7 +1738,8 @@ export const Holders: { weETH: '0x267ed5f71EE47D3E45Bb1569Aa37889a2d10f91e', rUSD: '0xEC2eda1C4F981E468ABF62424a10B69B738b498E', arUSD: '0xeFc24206053a452e2299BF3b8f964512b041Db4C', - USD0: '0x6A5d5Af0E266a24648a9d7E8D388EAEc7AbD8433', + USD0: '0x224762e69169E425239EeEE0012d1B0e041C123D', + SmartM: '0xE0663f2372cAa1459b7ade90812Dc737CE587FA6', 'USD0++': '0x2227b6806339906707b43F36a1f07B52FF7Fa776', USDM: '0x57F5E098CaD7A3D1Eed53991D4d66C45C9AF7812', wUSDM: '0x3B95bC951EE0f553ba487327278cAc44f29715E5',