diff --git a/modules/sor/sor.gql b/modules/sor/sor.gql index 85b7d72b2..658b15aaf 100644 --- a/modules/sor/sor.gql +++ b/modules/sor/sor.gql @@ -13,7 +13,7 @@ extend type Query { """ Get swap quote from the SOR v2 for the V2 vault """ - sorV2GetSwaps( + sorGetSwapPaths( """ The Chain to query """ @@ -26,10 +26,11 @@ extend type Query { swapType: GqlSorSwapType! swapAmount: BigDecimal! #expected in human readable form queryBatchSwap: Boolean #run queryBatchSwap to update with onchain values, default: true - ): GqlSorGetSwaps! + useVaultVersion: Int #defaults that it gets the best swap from v2 and v3, can force to use only one vault version + ): GqlSorGetSwapPaths! } -type GqlSorGetSwaps { +type GqlSorGetSwapPaths { vaultVersion: Int! """ The token address of the tokenIn provided @@ -39,9 +40,8 @@ type GqlSorGetSwaps { The token address of the tokenOut provided """ tokenOut: String! - tokenAddresses: [String!]! - swapType: GqlSorSwapType! - swaps: [GqlSorSwap!]! + swaps: [GqlSorSwap!]! #used by cowswap + paths: [GqlSorPath!]! #used by b-sdk tokenInAmount: AmountHumanReadable! tokenOutAmount: AmountHumanReadable! swapAmount: AmountHumanReadable! @@ -54,6 +54,19 @@ type GqlSorGetSwaps { priceImpact: AmountHumanReadable! } +type GqlSorPath { + vaultVersion: Int! + pools: [String]! #list of pool Ids + tokens: [Token]! + outputAmountRaw: String! + inputAmountRaw: String! +} + +type Token { + address: String! + decimals: Int! +} + enum GqlSorSwapType { EXACT_IN EXACT_OUT @@ -119,6 +132,7 @@ type GqlSorGetSwapsResponse { priceImpact: AmountHumanReadable! } +#used by cowswap type GqlSorSwap { poolId: String! assetInIndex: Int! diff --git a/modules/sor/sor.resolvers.ts b/modules/sor/sor.resolvers.ts index 5d78b973c..b3e18bbe2 100644 --- a/modules/sor/sor.resolvers.ts +++ b/modules/sor/sor.resolvers.ts @@ -16,8 +16,8 @@ const balancerSdkResolvers: Resolvers = { return sorService.getSorSwaps(args); }, - sorV2GetSwaps: async (parent, args, context) => { - return sorService.getSorV2Swaps(args); + sorGetSwapPaths: async (parent, args, context) => { + return sorService.getSorSwapPaths(args); }, }, }; diff --git a/modules/sor/sor.service.ts b/modules/sor/sor.service.ts index 55ce556d9..46adb6397 100644 --- a/modules/sor/sor.service.ts +++ b/modules/sor/sor.service.ts @@ -2,8 +2,8 @@ import { GqlSorSwapType, GqlSorGetSwapsResponse, QuerySorGetSwapsArgs, - GqlSorGetSwaps, - QuerySorV2GetSwapsArgs, + QuerySorGetSwapPathsArgs, + GqlSorGetSwapPaths, } from '../../schema'; import { sorV1BeetsService } from './sorV1Beets/sorV1Beets.service'; import { sorV2Service } from './sorV2/sorV2.service'; @@ -12,15 +12,15 @@ import * as Sentry from '@sentry/node'; import { Chain } from '@prisma/client'; import { parseUnits, formatUnits } from '@ethersproject/units'; import { tokenService } from '../token/token.service'; -import { getToken, getTokenAmountHuman, zeroResponse, zeroResponseV2 } from './utils'; +import { getToken, getTokenAmountHuman, zeroResponse, swapPathsZeroResponse } from './utils'; export class SorService { - async getSorV2Swaps(args: QuerySorV2GetSwapsArgs): Promise { + async getSorSwapPaths(args: QuerySorGetSwapPathsArgs): 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; - const emptyResponse = zeroResponseV2(args.swapType, args.tokenIn, args.tokenOut); + const emptyResponse = swapPathsZeroResponse(args.tokenIn, args.tokenOut); // check if tokens addresses exist try { @@ -44,7 +44,7 @@ export class SorService { // args.swapAmount is HumanScale const amount = await getTokenAmountHuman(amountToken, args.swapAmount, args.chain!); - return sorV2Service.getSorSwaps({ + return sorV2Service.getSorSwapPaths({ chain: args.chain!, swapAmount: amount, swapType: args.swapType, diff --git a/modules/sor/sorV2/beetsHelpers.ts b/modules/sor/sorV2/beetsHelpers.ts index 6a7226742..e0e9d24ed 100644 --- a/modules/sor/sorV2/beetsHelpers.ts +++ b/modules/sor/sorV2/beetsHelpers.ts @@ -1,6 +1,7 @@ -import { BatchSwapStep, NATIVE_ADDRESS, SingleSwap, SwapKind, ZERO_ADDRESS } from '@balancer/sdk'; -import { GqlPoolMinimal, GqlSorSwapRoute, GqlSorSwapRouteHop } from '../../../schema'; +import { BatchSwapStep, NATIVE_ADDRESS, SingleSwap, Swap, SwapKind, ZERO_ADDRESS } from '@balancer/sdk'; +import { GqlPoolMinimal, GqlSorPath, GqlSorSwapRoute, GqlSorSwapRouteHop } from '../../../schema'; import { formatFixed } from '@ethersproject/bignumber'; +import path from 'path'; export function mapRoutes( swaps: BatchSwapStep[] | SingleSwap, @@ -22,6 +23,25 @@ export function mapRoutes( return paths.map((p) => mapBatchSwap(p, amountIn, amountOut, kind, assets, pools)); } +export function mapPaths(swap: Swap): GqlSorPath[] { + const paths: GqlSorPath[] = []; + + for (const path of swap.paths) { + paths.push({ + vaultVersion: 2, + inputAmountRaw: path.inputAmount.amount.toString(), + outputAmountRaw: path.outputAmount.amount.toString(), + tokens: path.tokens.map((token) => ({ + address: token.address, + decimals: token.decimals, + })), + pools: path.pools.map((pool) => pool.id), + }); + } + + return paths; +} + export function mapBatchSwap( swaps: BatchSwapStep[], amountIn: string, diff --git a/modules/sor/sorV2/sorV2.service.ts b/modules/sor/sorV2/sorV2.service.ts index d4a27edfd..fdc8f1a8d 100644 --- a/modules/sor/sorV2/sorV2.service.ts +++ b/modules/sor/sorV2/sorV2.service.ts @@ -1,4 +1,4 @@ -import { GqlSorGetSwaps, GqlSorSwap, GqlSorSwapType } from '../../../schema'; +import { GqlSorGetSwapPaths, GqlSorSwap, GqlSorSwapType } from '../../../schema'; import { Chain } from '@prisma/client'; import { PrismaPoolWithDynamic, prismaPoolWithDynamic } from '../../../prisma/prisma-types'; import { prisma } from '../../../prisma/prisma-client'; @@ -12,9 +12,9 @@ import { Address, formatUnits, parseUnits } from 'viem'; import { sorGetSwapsWithPools } from './lib/static'; import { SwapResultV2 } from './swapResultV2'; import { poolService } from '../../pool/pool.service'; -import { mapRoutes } from './beetsHelpers'; +import { mapPaths, mapRoutes } from './beetsHelpers'; import { replaceZeroAddressWithEth } from '../../web3/addresses'; -import { getToken, zeroResponseV2 } from '../utils'; +import { getToken, swapPathsZeroResponse } from '../utils'; import { BatchSwapStep, SingleSwap, Swap, SwapKind, TokenAmount } from '@balancer/sdk'; import { Token } from 'graphql'; @@ -66,16 +66,16 @@ export class SorV2Service implements SwapService { } } - public async getSorSwaps(input: GetSwapsV2Input, maxNonBoostedPathDepth = 4): Promise { + public async getSorSwapPaths(input: GetSwapsV2Input, maxNonBoostedPathDepth = 4): Promise { const swap = await this.getSwap(input, maxNonBoostedPathDepth); - const emptyResponse = zeroResponseV2(input.swapType, input.tokenIn, input.tokenOut); + const emptyResponse = swapPathsZeroResponse(input.tokenIn, input.tokenOut); if (!swap) { return emptyResponse; } try { - return this.mapToSorSwaps(swap!, input.chain, input.queryBatchSwap ? input.queryBatchSwap : true); + return this.mapToSorSwapPaths(swap!, input.chain, input.queryBatchSwap ? input.queryBatchSwap : true); } catch (err: any) { console.log(`Error Retrieving QuerySwap`, err); Sentry.captureException(err.message, { @@ -136,7 +136,7 @@ export class SorV2Service implements SwapService { } } - public async mapToSorSwaps(swap: Swap, chain: Chain, queryFirst = false): Promise { + public async mapToSorSwapPaths(swap: Swap, chain: Chain, queryFirst = false): Promise { if (!queryFirst) return this.mapSwapToSorGetSwaps(swap, swap.inputAmount, swap.outputAmount); else { const rpcUrl = AllNetworkConfigsKeyedOnChain[chain].data.rpcUrl; @@ -153,7 +153,7 @@ export class SorV2Service implements SwapService { swap: Swap, inputAmount: TokenAmount, outputAmount: TokenAmount, - ): Promise { + ): Promise { const priceImpact = swap.priceImpact.decimal.toFixed(4); let poolIds: string[]; if (swap.isBatchSwap) { @@ -187,6 +187,8 @@ export class SorV2Service implements SwapService { swap.swapKind, ); + const paths = mapPaths(swap); + for (const route of routes) { route.tokenInAmount = ((inputAmount.amount * BigInt(parseUnits(`${0.5}`, 6))) / 1000000n).toString(); route.tokenOutAmount = ( @@ -196,11 +198,11 @@ export class SorV2Service implements SwapService { } return { + vaultVersion: 2, + paths: paths, swaps: this.mapSwaps(swap.swaps, swap.assets), - tokenAddresses: swap.assets, tokenIn: replaceZeroAddressWithEth(inputAmount.token.address), tokenOut: replaceZeroAddressWithEth(outputAmount.token.address), - swapType: this.mapSwapKindToSwapType(swap.swapKind), tokenInAmount: inputAmount.amount.toString(), tokenOutAmount: outputAmount.amount.toString(), swapAmount: formatUnits(swapAmount.amount, swapAmount.token.decimals), @@ -224,10 +226,6 @@ export class SorV2Service implements SwapService { return swapType === 'EXACT_IN' ? SwapKind.GivenIn : SwapKind.GivenOut; } - private mapSwapKindToSwapType(kind: SwapKind): GqlSorSwapType { - return kind === SwapKind.GivenIn ? 'EXACT_IN' : 'EXACT_OUT'; - } - private mapSwaps(swaps: BatchSwapStep[] | SingleSwap, assets: string[]): GqlSorSwap[] { if (Array.isArray(swaps)) { return swaps.map((swap) => { diff --git a/modules/sor/utils.ts b/modules/sor/utils.ts index bfc42cd91..40bbeb455 100644 --- a/modules/sor/utils.ts +++ b/modules/sor/utils.ts @@ -1,7 +1,7 @@ import { tokenService } from '../token/token.service'; import { Chain } from '@prisma/client'; import { AllNetworkConfigsKeyedOnChain, chainToIdMap } from '../network/network-config'; -import { GqlSorGetSwaps, GqlSorGetSwapsResponse, GqlSorSwapType } from '../../schema'; +import { GqlSorGetSwapPaths, GqlSorGetSwapsResponse, GqlSorSwapType } from '../../schema'; import { replaceZeroAddressWithEth } from '../web3/addresses'; import { Address } from 'viem'; import { NATIVE_ADDRESS, Token, TokenAmount } from '@balancer/sdk'; @@ -37,13 +37,13 @@ export const getToken = async (tokenAddr: string, chain: Chain): Promise } }; -export const zeroResponseV2 = (swapType: GqlSorSwapType, tokenIn: string, tokenOut: string): GqlSorGetSwaps => { +export const swapPathsZeroResponse = (tokenIn: string, tokenOut: string): GqlSorGetSwapPaths => { return { - tokenAddresses: [], swaps: [], + paths: [], + vaultVersion: 2, tokenIn: replaceZeroAddressWithEth(tokenIn), tokenOut: replaceZeroAddressWithEth(tokenOut), - swapType, tokenInAmount: '0', tokenOutAmount: '0', swapAmount: '0',