Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: li.fi unstable quotes use original rate #8350

Merged
merged 34 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
50a689f
feat: improve quote or rate discrimination
gomesalexandre Dec 9, 2024
0058933
fix: types
gomesalexandre Dec 9, 2024
a468c64
fix: tests
gomesalexandre Dec 9, 2024
7fea22b
fix: lifi
gomesalexandre Dec 9, 2024
46cc515
Merge remote-tracking branch 'origin/develop' into feat_quoteOrRate_d…
gomesalexandre Dec 9, 2024
bf4eef4
Merge remote-tracking branch 'origin/develop' into feat_quoteOrRate_d…
gomesalexandre Dec 11, 2024
74e3613
Merge remote-tracking branch 'origin/develop' into feat_quoteOrRate_d…
gomesalexandre Dec 11, 2024
18a28dd
fix: merge
gomesalexandre Dec 11, 2024
a90ebb7
Merge branch 'develop' into feat_quoteOrRate_discriminator
gomesalexandre Dec 11, 2024
44e0301
feat: rm Li.Fi specific case
gomesalexandre Dec 11, 2024
e52c6f7
feat: better casting
gomesalexandre Dec 11, 2024
214784c
feat: no casting better than casting
gomesalexandre Dec 11, 2024
fa3e167
feat: improve isThorTradeQuote / isThorTradeRate heuristics with one
gomesalexandre Dec 11, 2024
f13a9dc
Merge branch 'develop' into feat_quoteOrRate_discriminator
gomesalexandre Dec 11, 2024
fe5de5b
Merge remote-tracking branch 'origin/develop' into feat_quoteOrRate_d…
gomesalexandre Dec 11, 2024
049ecaf
Merge branch 'develop' into feat_quoteOrRate_discriminator
gomesalexandre Dec 11, 2024
c6de9b3
Merge branch 'develop' into feat_quoteOrRate_discriminator
gomesalexandre Dec 12, 2024
077b487
Merge remote-tracking branch 'origin/develop' into feat_quoteOrRate_d…
gomesalexandre Dec 12, 2024
558a016
feat: remove TradeQuoteOrRate type
gomesalexandre Dec 12, 2024
bcd1151
fix: trade quotes cannot return undefined accountNumber
gomesalexandre Dec 12, 2024
f6aa615
feat: monkey patch
gomesalexandre Dec 12, 2024
3dc0c95
feat: pass down originalRate
gomesalexandre Dec 12, 2024
4f32b89
feat: make it work
gomesalexandre Dec 12, 2024
070f3d1
feat: fuarkin TS mang...
gomesalexandre Dec 12, 2024
cf81273
fix: derp
gomesalexandre Dec 12, 2024
ca4af48
fix: absolute derp
gomesalexandre Dec 12, 2024
e78c258
feat: here we fuarkin go
gomesalexandre Dec 12, 2024
d908eed
feat: revert "feat: monkey patch"
gomesalexandre Dec 12, 2024
5aa17cc
fix: jupiter undefined receiveAddy
gomesalexandre Dec 12, 2024
3ac3a4e
Revert "feat: revert "feat: monkey patch""
gomesalexandre Dec 12, 2024
730d867
Merge remote-tracking branch 'origin/develop' into fix_lifi_final_quotes
gomesalexandre Dec 13, 2024
4f90e8c
Revert "Revert "feat: revert "feat: monkey patch"""
gomesalexandre Dec 13, 2024
58d2115
feat: cleanup
gomesalexandre Dec 13, 2024
d0fecda
fix: typo
gomesalexandre Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
COW_SWAP_NATIVE_ASSET_MARKER_ADDRESS,
DEFAULT_ADDRESS,
} from '../../../cowswap-utils/constants'
import type { GetTradeQuoteInput, SwapperConfig, TradeQuote } from '../../../types'
import type { GetTradeQuoteInput, SwapperConfig, TradeQuote, TradeRate } from '../../../types'
import { SwapperName, TradeQuoteError } from '../../../types'
import {
ETH,
Expand Down Expand Up @@ -382,6 +382,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
}

const maybeTradeQuote = await getCowSwapTradeQuote(input, MOCK_COWSWAP_CONFIG)
Expand Down Expand Up @@ -409,6 +410,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

mockedCowService.post.mockReturnValue(
Expand Down Expand Up @@ -454,6 +456,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

mockedCowService.post.mockReturnValue(
Expand Down Expand Up @@ -499,6 +502,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

mockedCowService.post.mockReturnValue(
Expand Down Expand Up @@ -544,6 +548,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

mockedCowService.post.mockReturnValue(
Expand Down Expand Up @@ -589,6 +594,7 @@ describe('getCowSwapTradeQuote', () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: '0.005', // 0.5%
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

mockedCowService.post.mockReturnValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export const getTradeRate = async (
id: uuid(),
quoteOrRate: 'rate',
rate: inputOutputRate,
receiveAddress: undefined,
receiveAddress,
potentialAffiliateBps: affiliateBps,
affiliateBps,
slippageTolerancePercentageDecimal,
Expand Down
8 changes: 6 additions & 2 deletions packages/swapper/src/swappers/LifiSwapper/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export const lifiApi: SwapperApi = {
)

return tradeQuoteResult.map(quote =>
quote.map(({ selectedLifiRoute, ...tradeQuote }) => {
quote.map(tradeQuote => {
const { selectedLifiRoute } = tradeQuote

gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
// TODO: quotes below the minimum aren't valid and should not be processed as such
// selectedLifiRoute will be missing for quotes below the minimum
if (!selectedLifiRoute) throw Error('missing selectedLifiRoute')
Expand Down Expand Up @@ -98,7 +100,9 @@ export const lifiApi: SwapperApi = {
const tradeRateResult = await getTradeRate(input as GetEvmTradeRateInput, deps, lifiChainMap)

return tradeRateResult.map(quote =>
quote.map(({ selectedLifiRoute, ...tradeQuote }) => {
quote.map(tradeQuote => {
const { selectedLifiRoute } = tradeQuote

gomesalexandre marked this conversation as resolved.
Show resolved Hide resolved
// TODO: quotes below the minimum aren't valid and should not be processed as such
// selectedLifiRoute will be missing for quotes below the minimum
if (!selectedLifiRoute) throw Error('missing selectedLifiRoute')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constant
import type {
GetEvmTradeQuoteInput,
GetEvmTradeQuoteInputBase,
GetEvmTradeRateInput,
MultiHopTradeQuoteSteps,
SingleHopTradeQuoteSteps,
SwapErrorRight,
Expand All @@ -40,7 +41,7 @@ export async function getTrade({
deps,
lifiChainMap,
}: {
input: GetEvmTradeQuoteInput & { lifiAllowedTools?: string[] | undefined }
input: GetEvmTradeQuoteInput | GetEvmTradeRateInput
deps: SwapperDeps
lifiChainMap: Map<ChainId, ChainKey>
}): Promise<Result<LifiTradeQuote[] | LifiTradeRate[], SwapErrorRight>> {
Expand All @@ -54,7 +55,6 @@ export async function getTrade({
supportsEIP1559,
affiliateBps,
potentialAffiliateBps,
lifiAllowedTools,
quoteOrRate,
} = input

Expand Down Expand Up @@ -104,9 +104,10 @@ export async function getTrade({
// reverts, partial swaps, wrong received tokens (due to out-of-gas mid-trade), etc. For now,
// these bridges are disabled.
bridges: { deny: ['stargate', 'stargateV2', 'stargateV2Bus', 'amarok', 'arbitrum'] },
...(lifiAllowedTools && {
exchanges: { allow: lifiAllowedTools },
}),
...(quoteOrRate === 'quote' &&
(input.originalRate as LifiTradeRate).lifiTools && {
exchanges: { allow: (input.originalRate as LifiTradeRate).lifiTools },
}),
allowSwitchChain: true,
fee: affiliateBpsDecimalPercentage.isZero()
? undefined
Expand Down Expand Up @@ -147,6 +148,13 @@ export async function getTrade({
const { routes } = routesResponse.unwrap()

if (routes.length === 0) {
if (quoteOrRate === 'quote')
return Ok([
{
...input.originalRate,
quoteOrRate: 'quote',
} as LifiTradeQuote,
])
return Err(
makeSwapErrorRight({
message: 'no route found',
Expand Down Expand Up @@ -302,7 +310,7 @@ export async function getTrade({
}

export const getTradeQuote = async (
input: GetEvmTradeQuoteInputBase & { lifiAllowedTools?: string[] | undefined },
input: GetEvmTradeQuoteInputBase,
deps: SwapperDeps,
lifiChainMap: Map<ChainId, ChainKey>,
): Promise<Result<LifiTradeQuote[], SwapErrorRight>> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import { v4 as uuid } from 'uuid'

import { getDefaultSlippageDecimalPercentageForSwapper } from '../../..'
import type {
GetEvmTradeQuoteInput,
GetEvmTradeRateInput,
GetTradeRateInput,
GetUtxoTradeQuoteInput,
GetUtxoTradeRateInput,
ProtocolFee,
SwapErrorRight,
SwapperDeps,
Expand Down Expand Up @@ -216,7 +217,7 @@ export const getL1Rate = async (
const sellAdapter = deps.assertGetEvmChainAdapter(sellAsset.chainId)
const { networkFeeCryptoBaseUnit } = await getEvmTxFees({
adapter: sellAdapter,
supportsEIP1559: Boolean((input as GetEvmTradeQuoteInput).supportsEIP1559),
supportsEIP1559: Boolean((input as GetEvmTradeRateInput).supportsEIP1559),
})

const maybeRoutes = await Promise.allSettled(
Expand Down Expand Up @@ -327,7 +328,7 @@ export const getL1Rate = async (

const feeData = await (async () => {
// This is a rate without a wallet connected, so we can't get fees
if (!(input as GetUtxoTradeQuoteInput).xpub)
if (!(input as GetUtxoTradeRateInput).xpub)
return {
networkFeeCryptoBaseUnit: undefined,
protocolFees: getProtocolFees(quote),
Expand All @@ -340,7 +341,7 @@ export const getL1Rate = async (

const { vault, opReturnData, pubkey } = await getUtxoThorTxInfo({
sellAsset,
xpub: (input as GetUtxoTradeQuoteInput).xpub!,
xpub: (input as unknown as GetUtxoTradeQuoteInput).xpub!,
memo,
config: deps.config,
})
Expand Down
4 changes: 2 additions & 2 deletions packages/swapper/src/swappers/ZrxSwapper/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
EvmTransactionRequest,
GetEvmTradeQuoteInputBase,
GetEvmTradeRateInput,
GetTradeQuoteInput,
GetTradeRateInput,
GetUnsignedEvmTransactionArgs,
SwapErrorRight,
SwapperApi,
Expand All @@ -37,7 +37,7 @@ export const zrxApi: SwapperApi = {
return tradeQuoteResult.map(tradeQuote => [tradeQuote])
},
getTradeRate: async (
input: GetTradeQuoteInput,
input: GetTradeRateInput,
{ assetsById, config }: SwapperDeps,
): Promise<Result<TradeRate[], SwapErrorRight>> => {
const tradeRateResult = await getZrxTradeRate(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Asset } from '@shapeshiftoss/types'
import { KnownChainIds } from '@shapeshiftoss/types'

import type { GetTradeQuoteInput, TradeQuote } from '../../../types'
import type { GetTradeQuoteInput, TradeQuote, TradeRate } from '../../../types'
import { SwapperName } from '../../../types'
import { DEFAULT_SLIPPAGE } from '../constants'
import { FOX_MAINNET, WETH } from './assets'
Expand Down Expand Up @@ -51,6 +51,7 @@ export const setupQuote = () => {
allowMultiHop: false,
slippageTolerancePercentageDecimal: DEFAULT_SLIPPAGE,
quoteOrRate: 'quote',
originalRate: {} as TradeRate,
}

return { quoteInput, tradeQuote, buyAsset, sellAsset }
Expand Down
20 changes: 10 additions & 10 deletions packages/swapper/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ type CommonTradeInputBase = {
potentialAffiliateBps: string
affiliateBps: string
allowMultiHop: boolean
lifiAllowedTools?: string[] | undefined
slippageTolerancePercentageDecimal?: string
}

Expand All @@ -166,6 +165,7 @@ export type CommonTradeQuoteInput = CommonTradeInputBase & {
receiveAddress: string
accountNumber: number
quoteOrRate: 'quote'
originalRate: TradeRate
}

type CommonTradeRateInput = CommonTradeInputBase & {
Expand All @@ -175,7 +175,7 @@ type CommonTradeRateInput = CommonTradeInputBase & {
quoteOrRate: 'rate'
}

type CommonTradeInput = CommonTradeQuoteInput | CommonTradeRateInput
type CommonTradeInput = CommonTradeQuoteInput

export type GetEvmTradeQuoteInputBase = CommonTradeQuoteInput & {
chainId: EvmChainId
Expand All @@ -185,7 +185,7 @@ export type GetEvmTradeRateInput = CommonTradeRateInput & {
chainId: EvmChainId
supportsEIP1559: false
}
export type GetEvmTradeQuoteInput = GetEvmTradeQuoteInputBase | GetEvmTradeRateInput
export type GetEvmTradeQuoteInput = GetEvmTradeQuoteInputBase

export type GetCosmosSdkTradeQuoteInputBase = CommonTradeQuoteInput & {
chainId: CosmosSdkChainId
Expand All @@ -206,16 +206,16 @@ type GetUtxoTradeQuoteWithWallet = CommonTradeQuoteInput & {
xpub: string
}

type GetUtxoTradeRateInput = CommonTradeRateInput & {
export type GetUtxoTradeRateInput = CommonTradeRateInput & {
chainId: UtxoChainId
// We need a dummy script type when getting a quote without a wallet
// so we always use SegWit (which works across all UTXO chains)
accountType: UtxoAccountType.P2pkh
accountNumber: undefined
xpub: undefined
accountType: UtxoAccountType
// accountNumber and accountType may be undefined if no wallet is connected
// accountType will default to UtxoAccountType.P2pkh without a wallet connected
accountNumber: number | undefined
xpub: string | undefined
}

export type GetUtxoTradeQuoteInput = GetUtxoTradeQuoteWithWallet | GetUtxoTradeRateInput
export type GetUtxoTradeQuoteInput = GetUtxoTradeQuoteWithWallet

export type GetTradeQuoteInput =
| GetUtxoTradeQuoteInput
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { CHAIN_NAMESPACE, fromChainId } from '@shapeshiftoss/caip'
import type { HDWallet } from '@shapeshiftoss/hdwallet-core'
import { supportsETH } from '@shapeshiftoss/hdwallet-core'
import type { GetTradeQuoteInput } from '@shapeshiftoss/swapper'
import type { GetTradeQuoteInput, GetTradeRateInput, TradeRate } from '@shapeshiftoss/swapper'
import type { Asset, CosmosSdkChainId, EvmChainId, UtxoChainId } from '@shapeshiftoss/types'
import { UtxoAccountType } from '@shapeshiftoss/types'
import type { TradeQuoteInputCommonArgs } from 'components/MultiHopTrade/types'
import { toBaseUnit } from 'lib/math'
import { assertUnreachable } from 'lib/utils'
import { assertGetCosmosSdkChainAdapter } from 'lib/utils/cosmosSdk'
import { assertGetEvmChainAdapter } from 'lib/utils/evm'
import { assertGetSolanaChainAdapter } from 'lib/utils/solana'
import { assertGetUtxoChainAdapter } from 'lib/utils/utxo'

export type GetTradeQuoteInputArgs = {
export type GetTradeQuoteOrRateInputArgs = {
sellAsset: Asset
buyAsset: Asset
sellAccountType: UtxoAccountType | undefined
slippageTolerancePercentageDecimal?: string
sellAmountBeforeFeesCryptoPrecision: string
allowMultiHop: boolean
lifiAllowedTools?: string[]
originalRate?: TradeRate
// Potential affiliate bps - may be waved out either entirely or partially with FOX discounts
potentialAffiliateBps: string
// Actual affiliate bps - if the FOX discounts is off, this will be the same as *affiliateBps*
Expand All @@ -33,7 +32,7 @@ export type GetTradeQuoteInputArgs = {
wallet: HDWallet | undefined
}

export const getTradeQuoteInput = async ({
export const getTradeQuoteOrRateInput = async ({
sellAsset,
buyAsset,
sellAccountNumber,
Expand All @@ -43,28 +42,46 @@ export const getTradeQuoteInput = async ({
receiveAddress,
sellAmountBeforeFeesCryptoPrecision,
allowMultiHop,
lifiAllowedTools,
originalRate,
affiliateBps,
potentialAffiliateBps,
slippageTolerancePercentageDecimal,
pubKey,
}: GetTradeQuoteInputArgs): Promise<GetTradeQuoteInput> => {
const tradeQuoteInputCommonArgs: TradeQuoteInputCommonArgs = {
sellAmountIncludingProtocolFeesCryptoBaseUnit: toBaseUnit(
sellAmountBeforeFeesCryptoPrecision,
sellAsset.precision,
),
sellAsset,
buyAsset,
receiveAddress,
accountNumber: sellAccountNumber,
affiliateBps: affiliateBps ?? '0',
potentialAffiliateBps: potentialAffiliateBps ?? '0',
allowMultiHop,
lifiAllowedTools,
slippageTolerancePercentageDecimal,
quoteOrRate,
}
}: GetTradeQuoteOrRateInputArgs): Promise<GetTradeQuoteInput | GetTradeRateInput> => {
const tradeQuoteInputCommonArgs =
quoteOrRate === 'quote' && receiveAddress && sellAccountNumber !== undefined
? {
sellAmountIncludingProtocolFeesCryptoBaseUnit: toBaseUnit(
sellAmountBeforeFeesCryptoPrecision,
sellAsset.precision,
),
sellAsset,
buyAsset,
receiveAddress,
accountNumber: sellAccountNumber,
affiliateBps: affiliateBps ?? '0',
potentialAffiliateBps: potentialAffiliateBps ?? '0',
allowMultiHop,
slippageTolerancePercentageDecimal,
quoteOrRate: 'quote',
originalRate,
}
: {
sellAmountIncludingProtocolFeesCryptoBaseUnit: toBaseUnit(
sellAmountBeforeFeesCryptoPrecision,
sellAsset.precision,
),
sellAsset,
buyAsset,
receiveAddress,
originalRate,
accountNumber: sellAccountNumber,
affiliateBps: affiliateBps ?? '0',
potentialAffiliateBps: potentialAffiliateBps ?? '0',
allowMultiHop,
slippageTolerancePercentageDecimal,
quoteOrRate: 'rate',
}

const { chainNamespace } = fromChainId(sellAsset.chainId)

Expand Down
Loading