diff --git a/modules/balancer/balancer.gql b/modules/balancer/balancer.gql deleted file mode 100644 index 228429a2f..000000000 --- a/modules/balancer/balancer.gql +++ /dev/null @@ -1,39 +0,0 @@ -extend type Mutation { - balancerMutationTest: String! -} - -extend type Query { - sorGetCowSwaps( - chain: GqlChain! - tokenIn: String! - tokenOut: String! - swapType: GqlSorSwapType! - swapAmount: BigDecimal! #expected in raw amount - ): GqlCowSwapApiResponse! -} - -enum GqlSorSwapType { - EXACT_IN - EXACT_OUT -} - -type GqlCowSwapApiResponse { - tokenAddresses: [String!]! - swaps: [GqlSwap!]! - swapAmount: String! - swapAmountForSwaps: String! - returnAmount: String! - returnAmountFromSwaps: String! - returnAmountConsideringFees: String! - tokenIn: String! - tokenOut: String! - marketSp: String! -} - -type GqlSwap { - poolId: String! - assetInIndex: Int! - assetOutIndex: Int! - amount: String! - userData: String! -} diff --git a/modules/balancer/balancer.resolvers.ts b/modules/balancer/balancer.resolvers.ts deleted file mode 100644 index 3369aa1e0..000000000 --- a/modules/balancer/balancer.resolvers.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Resolvers } from '../../schema'; -import { sorService } from '../sor/sor.service'; -import { getTokenAmountRaw } from '../sor/utils'; - -const balancerResolvers: Resolvers = { - Query: { - sorGetCowSwaps: async (parent, args, context) => { - const amountToken = args.swapType === 'EXACT_IN' ? args.tokenIn : args.tokenOut; - // Use TokenAmount to help follow scaling requirements in later logic - // args.swapAmount is RawScale, e.g. 1USDC should be passed as 1000000 - const amount = await getTokenAmountRaw(amountToken, args.swapAmount, args.chain); - const swaps = await sorService.getCowSwaps({ ...args, swapAmount: amount, swapOptions: {} }); - return { ...swaps, __typename: 'GqlCowSwapApiResponse' }; - }, - }, - Mutation: { - balancerMutationTest: async (parent, {}, context) => { - return 'test'; - }, - }, -}; - -export default balancerResolvers; diff --git a/modules/beethoven/balancer-sdk.resolvers.ts b/modules/beethoven/balancer-sdk.resolvers.ts deleted file mode 100644 index a755a1e90..000000000 --- a/modules/beethoven/balancer-sdk.resolvers.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Resolvers } from '../../schema'; -import { balancerSorService } from './balancer-sor.service'; -import { tokenService } from '../token/token.service'; -import { sorService } from '../sor/sor.service'; -import { getTokenAmountHuman } from '../sor/utils'; -import { headerChain } from '../context/header-chain'; - -const balancerSdkResolvers: Resolvers = { - Query: { - sorGetSwaps: async (parent, args, context) => { - console.log('sorGetSwaps args', JSON.stringify(args)); - - const currentChain = headerChain(); - if (!args.chain && currentChain) { - args.chain = currentChain; - } else if (!args.chain) { - throw new Error('sorGetSwaps error: Provide "chain" param'); - } - const chain = args.chain; - const tokenIn = args.tokenIn.toLowerCase(); - const tokenOut = args.tokenOut.toLowerCase(); - const amountToken = args.swapType === 'EXACT_IN' ? tokenIn : tokenOut; - // Use TokenAmount to help follow scaling requirements in later logic - // args.swapAmount is HumanScale - const amount = await getTokenAmountHuman(amountToken, args.swapAmount, args.chain); - - const swaps = await sorService.getBeetsSwaps({ - ...args, - chain, - tokenIn, - tokenOut, - swapAmount: amount, - }); - - return { ...swaps, __typename: 'GqlSorGetSwapsResponse' }; - }, - sorGetBatchSwapForTokensIn: async (parent, args, context) => { - const tokens = await tokenService.getTokens(); - - return balancerSorService.getBatchSwapForTokensIn({ ...args, tokens }); - }, - }, -}; - -export default balancerSdkResolvers; diff --git a/modules/beethoven/balancer-sor.test.ts b/modules/sor/balancer-sor.test.ts similarity index 100% rename from modules/beethoven/balancer-sor.test.ts rename to modules/sor/balancer-sor.test.ts diff --git a/modules/sor/constants.ts b/modules/sor/constants.ts index 0fa69e5be..8c73cdc23 100644 --- a/modules/sor/constants.ts +++ b/modules/sor/constants.ts @@ -1,14 +1,14 @@ import { TokenAmount } from '@balancer/sdk'; import { GqlCowSwapApiResponse, GqlSorSwapType } from '../../schema'; -export const EMPTY_COWSWAP_RESPONSE = (assetIn: string, assetOut: string, amount: TokenAmount): GqlCowSwapApiResponse => { +export const EMPTY_COWSWAP_RESPONSE = ( + assetIn: string, + assetOut: string, + amount: TokenAmount, +): GqlCowSwapApiResponse => { return { - marketSp: '0', returnAmount: '0', - returnAmountConsideringFees: '0', - returnAmountFromSwaps: '0', swapAmount: amount.amount.toString(), - swapAmountForSwaps: '0', swaps: [], tokenAddresses: [], tokenIn: assetIn, @@ -352,4 +352,3 @@ export const poolsToIgnore = [ '0xbfd65c6160cfd638a85c645e6e6d8acac5dac935000000000000000000000004', '0xe274c9deb6ed34cfe4130f8d0a8a948dea5bb28600000000000000000000000d', ]; - diff --git a/modules/beethoven/balancer-sdk.gql b/modules/sor/sor.gql similarity index 93% rename from modules/beethoven/balancer-sdk.gql rename to modules/sor/sor.gql index 530ab20c2..9bee51655 100644 --- a/modules/beethoven/balancer-sdk.gql +++ b/modules/sor/sor.gql @@ -7,6 +7,13 @@ extend type Query { swapAmount: BigDecimal! #expected in human readable form swapOptions: GqlSorSwapOptionsInput! ): GqlSorGetSwapsResponse! + sorGetCowSwaps( + chain: GqlChain! + tokenIn: String! + tokenOut: String! + swapType: GqlSorSwapType! + swapAmount: BigDecimal! #expected in raw amount + ): GqlCowSwapApiResponse! sorGetBatchSwapForTokensIn( tokensIn: [GqlTokenAmountHumanReadable!]! tokenOut: String! @@ -14,6 +21,23 @@ extend type Query { ): GqlSorGetBatchSwapForTokensInResponse! } +type GqlCowSwapApiResponse { + tokenAddresses: [String!]! + swaps: [GqlSwap!]! + swapAmount: String! + returnAmount: String! + tokenIn: String! + tokenOut: String! +} + +type GqlSwap { + poolId: String! + assetInIndex: Int! + assetOutIndex: Int! + amount: String! + userData: String! +} + enum GqlSorSwapType { EXACT_IN EXACT_OUT @@ -109,24 +133,3 @@ type GqlSorGetBatchSwapForTokensInResponse { swaps: [GqlSorSwap!]! assets: [String!]! } - -type GqlCowSwapApiResponse { - tokenAddresses: [String!]! - swaps: [GqlSwap!]! - swapAmount: String! - swapAmountForSwaps: String! - returnAmount: String! - returnAmountFromSwaps: String! - returnAmountConsideringFees: String! - tokenIn: String! - tokenOut: String! - marketSp: String! -} - -type GqlSwap { - poolId: String! - assetInIndex: Int! - assetOutIndex: Int! - amount: String! - userData: String! -} diff --git a/modules/sor/sor.resolvers.ts b/modules/sor/sor.resolvers.ts new file mode 100644 index 000000000..31fb1c044 --- /dev/null +++ b/modules/sor/sor.resolvers.ts @@ -0,0 +1,31 @@ +import { Resolvers } from '../../schema'; +import { balancerSorService } from './sorV1Beets/balancer-sor.service'; +import { tokenService } from '../token/token.service'; +import { sorService } from './sor.service'; +import { getTokenAmountHuman } from './utils'; +import { headerChain } from '../context/header-chain'; + +const balancerSdkResolvers: Resolvers = { + Query: { + sorGetSwaps: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.chain && currentChain) { + args.chain = currentChain; + } else if (!args.chain) { + throw new Error('sorGetSwaps error: Provide "chain" param'); + } + + return sorService.getSorSwaps(args); + }, + sorGetBatchSwapForTokensIn: async (parent, args, context) => { + const tokens = await tokenService.getTokens(); + + return balancerSorService.getBatchSwapForTokensIn({ ...args, tokens }); + }, + sorGetCowSwaps: async (parent, args, context) => { + return sorService.getCowSwaps(args); + }, + }, +}; + +export default balancerSdkResolvers; diff --git a/modules/sor/sor.service.ts b/modules/sor/sor.service.ts index dc5ac98ce..573ab289c 100644 --- a/modules/sor/sor.service.ts +++ b/modules/sor/sor.service.ts @@ -1,54 +1,81 @@ -import { GqlCowSwapApiResponse, GqlSorSwapType, GqlSorGetSwapsResponse, GqlSorSwapOptionsInput } from '../../schema'; -import { sorV1BalancerService } from './sorV1Balancer/sorV1Balancer.service'; +import { + GqlCowSwapApiResponse, + GqlSorSwapType, + GqlSorGetSwapsResponse, + QuerySorGetSwapsArgs, + QuerySorGetCowSwapsArgs, +} from '../../schema'; import { sorV1BeetsService } from './sorV1Beets/sorV1Beets.service'; import { sorV2Service } from './sorV2/sorV2.service'; -import { GetSwapsInput, SwapResult, SwapService } from './types'; +import { GetSwapsInput, SwapResult } from './types'; import { EMPTY_COWSWAP_RESPONSE } from './constants'; -import { publishMetric } from '../metrics/sor.metric'; import { Chain } from '@prisma/client'; import { parseUnits, formatUnits } from '@ethersproject/units'; import { tokenService } from '../token/token.service'; +import { getTokenAmountHuman, getTokenAmountRaw } from './utils'; export class SorService { - async getCowSwaps(input: GetSwapsInput): Promise { - const swap = await this.getSwap({ ...input, swapOptions: {} }); - const emptyResponse = EMPTY_COWSWAP_RESPONSE(input.tokenIn, input.tokenOut, input.swapAmount); + async getCowSwaps(args: QuerySorGetCowSwapsArgs): Promise { + console.log('getCowSwaps args', JSON.stringify(args)); + const amountToken = args.swapType === 'EXACT_IN' ? args.tokenIn : args.tokenOut; + // Use TokenAmount to help follow scaling requirements in later logic + // args.swapAmount is RawScale, e.g. 1USDC should be passed as 1000000 + const amount = await getTokenAmountRaw(amountToken, args.swapAmount, args.chain!); + + const swap = await sorV2Service.getSwapResult({ + chain: args.chain!, + swapAmount: amount, + swapType: args.swapType, + tokenIn: args.tokenIn.toLowerCase(), + tokenOut: args.tokenOut.toLowerCase(), + swapOptions: {}, + }); + const emptyResponse = EMPTY_COWSWAP_RESPONSE(args.tokenIn, args.tokenOut, amount); if (!swap) return emptyResponse; try { // Updates with latest onchain data before returning - return await swap.getCowSwapResponse(input.chain, true); + return await swap.getCowSwapResponse(true); } catch (err) { console.log(`Error Retrieving QuerySwap`, err); return emptyResponse; } } - async getBeetsSwaps(input: GetSwapsInput): Promise { - console.log('getBeetsSwaps input', JSON.stringify(input)); - const swap = await this.getSwap(input, sorV1BeetsService); - const emptyResponse = sorV1BeetsService.zeroResponse( - input.swapType, - input.tokenIn, - input.tokenOut, - input.swapAmount, - ); + async getSorSwaps(args: QuerySorGetSwapsArgs): Promise { + console.log('getSorSwaps args', JSON.stringify(args)); + const tokenIn = args.tokenIn.toLowerCase(); + const tokenOut = args.tokenOut.toLowerCase(); + const amountToken = args.swapType === 'EXACT_IN' ? tokenIn : tokenOut; + // Use TokenAmount to help follow scaling requirements in later logic + // args.swapAmount is HumanScale + const amount = await getTokenAmountHuman(amountToken, args.swapAmount, args.chain!); + + const swap = await this.getComparingSwap({ + chain: args.chain!, + swapAmount: amount, + swapOptions: args.swapOptions, + swapType: args.swapType, + tokenIn: tokenIn, + tokenOut: tokenOut, + }); + const emptyResponse = sorV1BeetsService.zeroResponse(args.swapType, args.tokenIn, args.tokenOut, amount); if (!swap) return emptyResponse; try { // Updates with latest onchain data before returning - return swap.getBeetsSwapResponse(true); + return swap.getSorSwapResponse(true); } catch (err) { console.log(`Error Retrieving QuerySwap`, err); return emptyResponse; } } - private async getSwap(input: GetSwapsInput, v1Service: SwapService = sorV1BalancerService) { + private async getComparingSwap(input: GetSwapsInput) { const v1Start = +new Date(); - const swapV1 = await v1Service.getSwapResult(input); + const swapV1 = await sorV1BeetsService.getSwapResult(input); const v1Time = +new Date() - v1Start; const v2Start = +new Date(); @@ -122,9 +149,6 @@ export class SorService { v1Time: number, v2Time: number, ) { - // await publishMetric(chain, `SOR_VALID_V1`, v1.isValid ? 1 : 0); - // await publishMetric(chain, `SOR_VALID_V2`, v2.isValid ? 1 : 0); - if (!version) return; let v1ResultAmount = v1.inputAmount; @@ -154,10 +178,6 @@ export class SorService { let diff = bn(diffN.toFixed(decimals), decimals); let bestResultAmount = version === 'V1' ? v1ResultAmount : v2ResultAmount; - // await publishMetric(chain, `SOR_TIME_V1`, v1Time); - // await publishMetric(chain, `SOR_TIME_V2`, v2Time); - // await publishMetric(chain, `SOR_V2_PERFORMACE`, v2Perf); - console.log( [ 'SOR_RESULT', diff --git a/modules/sor/sorV1Balancer/sorV1Balancer.service.ts b/modules/sor/sorV1Balancer/sorV1Balancer.service.ts deleted file mode 100644 index f35d98914..000000000 --- a/modules/sor/sorV1Balancer/sorV1Balancer.service.ts +++ /dev/null @@ -1,135 +0,0 @@ -import axios from 'axios'; -import * as Sentry from '@sentry/node'; -import { AddressZero } from '@ethersproject/constants'; -import { Contract } from '@ethersproject/contracts'; -import { GqlSorSwapType, GqlCowSwapApiResponse, GqlSorGetSwapsResponse } from '../../../schema'; -import { GetSwapsInput, SwapService, SwapResult } from '../types'; -import { FundManagement, SwapTypes, SwapV2 } from '@balancer-labs/sdk'; -import { env } from '../../../app/env'; -import { AllNetworkConfigs, AllNetworkConfigsKeyedOnChain, chainToIdMap } from '../../network/network-config'; -import { DeploymentEnv } from '../../network/network-config-types'; - -import VaultAbi from '../../pool/abi/Vault.json'; -import { BigNumber } from 'ethers'; -import { TokenAmount } from '@balancer/sdk'; -import { Chain } from '@prisma/client'; - -type CowSwapSwapType = 'buy' | 'sell'; - -class SwapResultV1 implements SwapResult { - public inputAmount: bigint = BigInt(0); - public outputAmount: bigint = BigInt(0); - public isValid: boolean; - - constructor(private swap: GqlCowSwapApiResponse | null, private swapType: GqlSorSwapType) { - if (swap === null) { - this.isValid = false; - this.swap = null; - } else { - this.inputAmount = swapType === 'EXACT_IN' ? BigInt(swap.swapAmount) : BigInt(swap.returnAmount); - this.outputAmount = swapType === 'EXACT_IN' ? BigInt(swap.returnAmount) : BigInt(swap.swapAmount); - this.isValid = swap.swaps.length === 0 ? false : true; - } - } - - async getCowSwapResponse(chain: Chain, queryFirst = false): Promise { - if (!this.isValid || this.swap === null) throw new Error('No Response - Invalid Swap'); - - if (queryFirst) { - const swapType = this.mapSwapType(this.swapType); - const deltas = await this.queryBatchSwap(swapType, this.swap.swaps, this.swap.tokenAddresses, chain); - const tokenInAmount = deltas[this.swap.tokenAddresses.indexOf(this.swap.tokenIn)].toString(); - const tokenOutAmount = deltas[this.swap.tokenAddresses.indexOf(this.swap.tokenOut)].abs().toString(); - // console.log(`UPDATE:`, this.inputAmount, this.outputAmount, tokenInAmount, tokenOutAmount, deltas.toString()); - return { - ...this.swap, - returnAmount: swapType === SwapTypes.SwapExactIn ? tokenOutAmount : tokenInAmount, - swapAmount: swapType === SwapTypes.SwapExactIn ? tokenInAmount : tokenOutAmount, - }; - } - return this.swap; - } - - async getBeetsSwapResponse(queryFirst: boolean): Promise { - throw new Error('Use Beets service.'); - } - - private queryBatchSwap(swapType: SwapTypes, swaps: SwapV2[], assets: string[], chain: Chain): Promise { - const vault = AllNetworkConfigsKeyedOnChain[chain].data.balancer.vault; - const provider = AllNetworkConfigsKeyedOnChain[chain].provider; - - const vaultContract = new Contract(vault, VaultAbi, provider); - const funds: FundManagement = { - sender: AddressZero, - recipient: AddressZero, - fromInternalBalance: false, - toInternalBalance: false, - }; - - return vaultContract.queryBatchSwap(swapType, swaps, assets, funds); - } - - private mapSwapType(swapType: GqlSorSwapType): SwapTypes { - return swapType === 'EXACT_IN' ? SwapTypes.SwapExactIn : SwapTypes.SwapExactOut; - } -} -export class SorV1BalancerService implements SwapService { - public async getSwapResult({ chain, tokenIn, tokenOut, swapType, swapAmount }: GetSwapsInput): Promise { - try { - const swap = await this.querySorBalancer(chain, swapType, tokenIn, tokenOut, swapAmount); - return new SwapResultV1(swap, swapType); - } catch (err: any) { - console.error( - `SOR_V1_ERROR ${err.message} - tokenIn: ${tokenIn} - tokenOut: ${tokenOut} - swapAmount: ${swapAmount.amount} - swapType: ${swapType} - chain: ${chain}`, - ); - Sentry.captureException(err.message, { - tags: { - service: 'sorV1', - tokenIn, - tokenOut, - swapAmount: swapAmount.amount, - swapType, - chain, - }, - }); - return new SwapResultV1(null, swapType); - } - } - - /** - * Query Balancer API CowSwap/SOR endpoint. - * @param swapType - * @param tokenIn - * @param tokenOut - * @param swapAmountScaled - * @param swapOptions - * @returns - */ - private async querySorBalancer( - chain: Chain, - swapType: GqlSorSwapType, - tokenIn: string, - tokenOut: string, - swapAmount: TokenAmount, - ): Promise { - const chainId = chainToIdMap[chain]; - const endPoint = `https://api.balancer.fi/sor/${chainId}`; - const gasPrice = AllNetworkConfigs[chainId].data.sor[env.DEPLOYMENT_ENV as DeploymentEnv].gasPrice.toString(); - const swapData = { - orderKind: this.mapSwapType(swapType), - sellToken: tokenIn, - buyToken: tokenOut, - amount: swapAmount.amount.toString(), - gasPrice, - }; - - const { data } = await axios.post(endPoint, swapData); - return data; - } - - private mapSwapType(swapType: GqlSorSwapType): CowSwapSwapType { - return swapType === 'EXACT_IN' ? 'sell' : 'buy'; - } -} - -export const sorV1BalancerService = new SorV1BalancerService(); diff --git a/modules/beethoven/balancer-sor.service.ts b/modules/sor/sorV1Beets/balancer-sor.service.ts similarity index 95% rename from modules/beethoven/balancer-sor.service.ts rename to modules/sor/sorV1Beets/balancer-sor.service.ts index 7452f5ea0..19d5c2b3a 100644 --- a/modules/beethoven/balancer-sor.service.ts +++ b/modules/sor/sorV1Beets/balancer-sor.service.ts @@ -1,19 +1,19 @@ -import { GqlSorGetSwapsResponse, GqlSorSwapOptionsInput, GqlSorSwapType, GqlPoolMinimal } from '../../schema'; +import { GqlSorGetSwapsResponse, GqlSorSwapOptionsInput, GqlSorSwapType, GqlPoolMinimal } from '../../../schema'; import { formatFixed, parseFixed } from '@ethersproject/bignumber'; import { PrismaToken } from '@prisma/client'; -import { poolService } from '../pool/pool.service'; -import { oldBnum } from '../big-number/old-big-number'; +import { poolService } from '../../pool/pool.service'; +import { oldBnum } from '../../big-number/old-big-number'; import axios from 'axios'; import { FundManagement, SwapInfo, SwapTypes, SwapV2 } from '@balancer-labs/sdk'; -import { replaceEthWithZeroAddress, replaceZeroAddressWithEth } from '../web3/addresses'; +import { replaceEthWithZeroAddress, replaceZeroAddressWithEth } from '../../web3/addresses'; import { BigNumber } from 'ethers'; -import { TokenAmountHumanReadable } from '../common/global-types'; +import { TokenAmountHumanReadable } from '../../common/global-types'; import { AddressZero } from '@ethersproject/constants'; import { Contract } from '@ethersproject/contracts'; -import VaultAbi from '../pool/abi/Vault.json'; -import { env } from '../../app/env'; -import { networkContext } from '../network/network-context.service'; -import { DeploymentEnv } from '../network/network-config-types'; +import VaultAbi from '../../pool/abi/Vault.json'; +import { env } from '../../../app/env'; +import { networkContext } from '../../network/network-context.service'; +import { DeploymentEnv } from '../../network/network-config-types'; import * as Sentry from '@sentry/node'; import _ from 'lodash'; import { Logger } from '@ethersproject/logger'; @@ -332,7 +332,11 @@ export class BalancerSorService { } private getTokenDecimals(tokenAddress: string, tokens: PrismaToken[]): number { - if (tokenAddress === ZERO_ADDRESS || tokenAddress === NATIVE_ADDRESS) { + if ( + tokenAddress === ZERO_ADDRESS || + tokenAddress === NATIVE_ADDRESS || + tokenAddress === '0x0000000000000000000000000000000000001010' + ) { return 18; } diff --git a/modules/sor/sorV1Beets/sorV1Beets.service.ts b/modules/sor/sorV1Beets/sorV1Beets.service.ts index 067e5f87c..3b299996f 100644 --- a/modules/sor/sorV1Beets/sorV1Beets.service.ts +++ b/modules/sor/sorV1Beets/sorV1Beets.service.ts @@ -1,7 +1,7 @@ import { formatEther } from 'viem'; import { GqlSorSwapType, GqlCowSwapApiResponse, GqlSorGetSwapsResponse, GqlSorSwapOptionsInput } from '../../../schema'; import { GetSwapsInput, SwapService, SwapResult } from '../types'; -import { BalancerSorService } from '../../beethoven/balancer-sor.service'; +import { BalancerSorService } from './balancer-sor.service'; import { tokenService } from '../../token/token.service'; import { TokenAmount } from '@balancer/sdk'; @@ -23,11 +23,11 @@ class SwapResultV1 implements SwapResult { } } - async getCowSwapResponse(chain = 'MAINNET', queryFirst = false): Promise { + async getCowSwapResponse(queryFirst = false): Promise { throw new Error('Use Balancer Service'); } - async getBeetsSwapResponse(queryFirst: boolean): Promise { + async getSorSwapResponse(queryFirst: boolean): Promise { if (!this.isValid || this.swap === null) throw new Error('No Response - Invalid Swap'); // Beets service is already querying onchain return this.swap; @@ -42,7 +42,7 @@ export class SorV1BeetsService implements SwapService { public async getSwapResult(input: GetSwapsInput & { swapOptions: GqlSorSwapOptionsInput }): Promise { try { - const swap = await this.querySorBeets(input); + const swap = await this.querySorV1(input); return new SwapResultV1(swap, input.swapType); } catch (err) { console.log(`sorV1 Service Error`, err); @@ -59,7 +59,7 @@ export class SorV1BeetsService implements SwapService { return this.sorService.zeroResponse(swapType, tokenIn, tokenOut, formatEther(swapAmount.scale18)); } - private async querySorBeets( + private async querySorV1( input: GetSwapsInput & { swapOptions: GqlSorSwapOptionsInput }, ): Promise { const tokens = await tokenService.getTokens(); diff --git a/modules/sor/sorV2/sorV2.service.ts b/modules/sor/sorV2/sorV2.service.ts index 733d8f659..0c8f72f6d 100644 --- a/modules/sor/sorV2/sorV2.service.ts +++ b/modules/sor/sorV2/sorV2.service.ts @@ -32,7 +32,7 @@ import { prisma } from '../../../prisma/prisma-client'; import { GetSwapsInput, SwapResult, SwapService } from '../types'; import { poolService } from '../../pool/pool.service'; import { tokenService } from '../../token/token.service'; -import { BalancerSorService } from '../../beethoven/balancer-sor.service'; +import { BalancerSorService } from '../sorV1Beets/balancer-sor.service'; import { env } from '../../../app/env'; import { DeploymentEnv } from '../../network/network-config-types'; import { Cache, CacheClass } from 'memory-cache'; @@ -49,43 +49,53 @@ const ALL_BASEPOOLS_CACHE_KEY = `basePools:all`; class SwapResultV2 implements SwapResult { private swap: SwapSdk | null; + private chain: Chain; public inputAmount: bigint = BigInt(0); public outputAmount: bigint = BigInt(0); public isValid: boolean; - constructor(swap: SwapSdk | null) { + constructor(swap: SwapSdk | null, chain: Chain) { if (swap === null) { this.isValid = false; this.swap = null; + this.chain = chain; } else { this.isValid = true; this.swap = swap; this.inputAmount = swap.inputAmount.amount; this.outputAmount = swap.outputAmount.amount; + this.chain = chain; } } - async getCowSwapResponse(chain: Chain, queryFirst = false): Promise { + async getCowSwapResponse(queryFirst = false): Promise { if (!this.isValid || this.swap === null) throw new Error('No Response - Invalid Swap'); if (!queryFirst) return this.mapResultToCowSwap(this.swap, this.swap.inputAmount, this.swap.outputAmount); else { - const rpcUrl = AllNetworkConfigsKeyedOnChain[chain].data.rpcUrl; - // Needs node >= 18 (https://github.com/wagmi-dev/viem/discussions/147) + const rpcUrl = AllNetworkConfigsKeyedOnChain[this.chain].data.rpcUrl; const updatedResult = await this.swap.query(rpcUrl); - // console.log(`UPDATE:`, this.swap.quote.amount.toString(), updatedResult.amount.toString()); - const ip = this.swap.swapKind === SwapKind.GivenIn ? this.swap.inputAmount : updatedResult; - const op = this.swap.swapKind === SwapKind.GivenIn ? updatedResult : this.swap.outputAmount; + const inputAmount = this.swap.swapKind === SwapKind.GivenIn ? this.swap.inputAmount : updatedResult; + const outputAmount = this.swap.swapKind === SwapKind.GivenIn ? updatedResult : this.swap.outputAmount; - return this.mapResultToCowSwap(this.swap, ip, op); + return this.mapResultToCowSwap(this.swap, inputAmount, outputAmount); } } - async getBeetsSwapResponse(queryFirst: boolean): Promise { + async getSorSwapResponse(queryFirst = false): Promise { if (!this.isValid || this.swap === null) throw new Error('No Response - Invalid Swap'); - return await this.mapResultToBeetsSwap(this.swap, this.swap.inputAmount, this.swap.outputAmount); + if (!queryFirst) return this.mapResultToBeetsSwap(this.swap, this.swap.inputAmount, this.swap.outputAmount); + else { + const rpcUrl = AllNetworkConfigsKeyedOnChain[this.chain].data.rpcUrl; + const updatedResult = await this.swap.query(rpcUrl); + + const inputAmount = this.swap.swapKind === SwapKind.GivenIn ? this.swap.inputAmount : updatedResult; + const outputAmount = this.swap.swapKind === SwapKind.GivenIn ? updatedResult : this.swap.outputAmount; + + return this.mapResultToBeetsSwap(this.swap, inputAmount, outputAmount); + } } private async mapResultToBeetsSwap( @@ -257,12 +267,8 @@ class SwapResultV2 implements SwapResult { const swapAmount = swap.swapKind === SwapKind.GivenIn ? inputAmount.amount.toString() : outputAmount.amount.toString(); return { - marketSp: '', // CowSwap is not using this field, confirmed. returnAmount, - returnAmountConsideringFees: returnAmount, // CowSwap is not using this field, confirmed. - returnAmountFromSwaps: returnAmount, // CowSwap is not using this field, confirmed. swapAmount, - swapAmountForSwaps: swapAmount, // CowSwap is not using this field, confirmed. swaps, tokenAddresses: swap.assets, tokenIn: swap.inputAmount.token.address, @@ -280,7 +286,7 @@ export class SorV2Service implements SwapService { public async getSwapResult( { chain, tokenIn, tokenOut, swapType, swapAmount, graphTraversalConfig }: GetSwapsInput, - maxNonBoostedPathDepth = 3, + maxNonBoostedPathDepth = 4, ): Promise { try { const poolsFromDb = await this.getBasePools(chain); @@ -308,7 +314,7 @@ export class SorV2Service implements SwapService { if (!swap && maxNonBoostedPathDepth < 4) { return this.getSwapResult(arguments[0], maxNonBoostedPathDepth + 1); } - return new SwapResultV2(swap); + return new SwapResultV2(swap, chain); } catch (err: any) { console.error( `SOR_V2_ERROR ${err.message} - tokenIn: ${tokenIn} - tokenOut: ${tokenOut} - swapAmount: ${swapAmount.amount} - swapType: ${swapType} - chain: ${chain}`, @@ -323,7 +329,7 @@ export class SorV2Service implements SwapService { chain, }, }); - return new SwapResultV2(null); + return new SwapResultV2(null, chain); } } @@ -354,6 +360,9 @@ export class SorV2Service implements SwapService { gt: 0.000000000001, }, swapEnabled: true, + totalLiquidity: { + gt: 50, + }, }, id: { notIn: [...poolIdsToExclude, ...poolsToIgnore], @@ -510,6 +519,8 @@ export class SorV2Service implements SwapService { case PrismaPoolType.PHANTOM_STABLE: // Composablestables are PHANTOM_STABLE in Prisma. b-sdk treats Phantoms as ComposableStable. return 'ComposableStable'; + case PrismaPoolType.COMPOSABLE_STABLE: + return 'ComposableStable'; case PrismaPoolType.GYRO: return 'Gyro2'; case PrismaPoolType.GYRO3: diff --git a/modules/sor/types.ts b/modules/sor/types.ts index 564647c84..2059332ec 100644 --- a/modules/sor/types.ts +++ b/modules/sor/types.ts @@ -19,8 +19,8 @@ export interface GraphTraversalConfig { } export interface SwapResult { - getCowSwapResponse(chain: Chain, queryFirst: boolean): Promise; - getBeetsSwapResponse(queryFirst: boolean): Promise; + getCowSwapResponse(queryFirst: boolean): Promise; + getSorSwapResponse(queryFirst: boolean): Promise; isValid: boolean; outputAmount: bigint; inputAmount: bigint; diff --git a/modules/sor/utils.ts b/modules/sor/utils.ts index ab47ae2b2..4e10b55c8 100644 --- a/modules/sor/utils.ts +++ b/modules/sor/utils.ts @@ -22,7 +22,11 @@ export async function getTokenAmountRaw(tokenAddr: string, rawAmount: string, ch export const getToken = async (tokenAddr: string, chain: Chain): Promise => { const chainId = Number(chainToIdMap[chain]); - if (tokenAddr === NATIVE_ADDRESS && chainId in NATIVE_ASSETS) { + // also check for the polygon native asset + if ( + (tokenAddr === NATIVE_ADDRESS || tokenAddr === '0x0000000000000000000000000000000000001010') && + chainId in NATIVE_ASSETS + ) { return NATIVE_ASSETS[chainId as keyof typeof NATIVE_ASSETS]; } else { const prismaToken = await tokenService.getToken(tokenAddr, chain);