From 9d156a08f4d3a7f5362e1fd7ff5863cb9169c2f5 Mon Sep 17 00:00:00 2001 From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:15:21 +0200 Subject: [PATCH 1/2] fix: remove addSlippageToMemo in favor of addLimitToMemo --- .../utils/addSlippageToMemo.test.ts | 32 ---------- .../utils/addSlippageToMemo.ts | 45 -------------- .../ThorchainSwapper/utils/getL1quote.ts | 62 ++++++++++++++----- .../utils/getLimitWithManualSlippage.test.ts | 19 ++++++ .../utils/getLimitWithManualSlippage.ts | 19 ++++++ 5 files changed, 84 insertions(+), 93 deletions(-) delete mode 100644 src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.test.ts delete mode 100644 src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.ts create mode 100644 src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.test.ts create mode 100644 src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.ts diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.test.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.test.ts deleted file mode 100644 index fd7a8870a0c..00000000000 --- a/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import { addSlippageToMemo } from './addSlippageToMemo' -import { MEMO_PART_DELIMITER } from './constants' - -const RECEIVE_ADDRESS = '0x32DBc9Cf9E8FbCebE1e0a2ecF05Ed86Ca3096Cb6' - -describe('addSlippageToMemo', () => { - it('should add slippage to memo correctly', () => { - const affiliateBps = '100' - const quotedMemo = `=:ETH.ETH:${RECEIVE_ADDRESS}::ss:${affiliateBps}` - const expectedL1AmountOut = '42' // we don't care about this for the purpose of tests - const expectedL1AmountOutMinusSlippage = '41' - - const slippageBps = 100 // 1% - const chainId = 'eip155:1' - const isStreaming = false - - const modifiedMemo = addSlippageToMemo({ - expectedAmountOutThorBaseUnit: expectedL1AmountOut, - quotedMemo, - slippageBps, - isStreaming, - chainId, - affiliateBps, - }) - - expect(modifiedMemo).toBe( - `=${MEMO_PART_DELIMITER}ETH.ETH${MEMO_PART_DELIMITER}${RECEIVE_ADDRESS}${MEMO_PART_DELIMITER}${expectedL1AmountOutMinusSlippage}${MEMO_PART_DELIMITER}ss${MEMO_PART_DELIMITER}${affiliateBps}`, - ) - }) -}) diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.ts deleted file mode 100644 index bb919df803f..00000000000 --- a/src/lib/swapper/swappers/ThorchainSwapper/utils/addSlippageToMemo.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { ChainId } from '@shapeshiftoss/caip' -import { BigNumber, bn } from 'lib/bignumber/bignumber' -import { subtractBasisPointAmount } from 'state/slices/tradeQuoteSlice/utils' - -import { MEMO_PART_DELIMITER } from './constants' -import { assertIsValidMemo } from './makeSwapMemo/assertIsValidMemo' - -export const addSlippageToMemo = ({ - expectedAmountOutThorBaseUnit, - quotedMemo, - slippageBps, - isStreaming, - chainId, - affiliateBps, -}: { - expectedAmountOutThorBaseUnit: string - quotedMemo: string | undefined - slippageBps: BigNumber.Value - chainId: ChainId - affiliateBps: string - isStreaming: boolean -}) => { - if (!quotedMemo) throw new Error('no memo provided') - - // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) - // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 - if (isStreaming) return quotedMemo - - // the missing element is the original limit with (optional, missing) streaming parameters - const [prefix, pool, address, , affiliate, memoAffiliateBps] = - quotedMemo.split(MEMO_PART_DELIMITER) - - const limitWithManualSlippage = subtractBasisPointAmount( - bn(expectedAmountOutThorBaseUnit).toFixed(0, BigNumber.ROUND_DOWN), - slippageBps, - BigNumber.ROUND_DOWN, - ) - - const memo = [prefix, pool, address, limitWithManualSlippage, affiliate, memoAffiliateBps].join( - MEMO_PART_DELIMITER, - ) - - assertIsValidMemo(memo, chainId, affiliateBps) - return memo -} diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts index cc2f531163e..5c6658da1c1 100644 --- a/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts +++ b/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts @@ -25,6 +25,7 @@ import { assertUnreachable, isFulfilled, isRejected } from 'lib/utils' import { assertGetCosmosSdkChainAdapter } from 'lib/utils/cosmosSdk' import { assertGetEvmChainAdapter } from 'lib/utils/evm' import { THOR_PRECISION } from 'lib/utils/thorchain/constants' +import { addLimitToMemo } from 'lib/utils/thorchain/memo/addLimitToMemo' import { assertGetUtxoChainAdapter } from 'lib/utils/utxo' import { convertDecimalPercentageToBasisPoints } from 'state/slices/tradeQuoteSlice/utils' @@ -39,8 +40,8 @@ import type { ThorTradeUtxoOrCosmosQuote, } from '../getThorTradeQuote/getTradeQuote' import type { ThornodeQuoteResponseSuccess } from '../types' -import { addSlippageToMemo } from './addSlippageToMemo' import { THORCHAIN_FIXED_PRECISION } from './constants' +import { getLimitWithManualSlippage } from './getLimitWithManualSlippage' import { getQuote } from './getQuote/getQuote' import { TradeType } from './longTailHelpers' import { getEvmTxFees } from './txFeeHelpers/evmTxFees/getEvmTxFees' @@ -221,14 +222,24 @@ export const getL1quote = async ( const buyAmountBeforeFeesCryptoBaseUnit = getRouteBuyAmountBeforeFeesCryptoBaseUnit(quote) - const updatedMemo = addSlippageToMemo({ + const limitWithManualSlippage = getLimitWithManualSlippage({ expectedAmountOutThorBaseUnit, - quotedMemo: quote.memo, slippageBps, - chainId: sellAsset.chainId, - affiliateBps, - isStreaming, }) + + if (!quote.memo) throw new Error('no memo provided') + + let updatedMemo = quote.memo + + // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) + // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 + if (!isStreaming) { + updatedMemo = addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) + } + const { data, router, vault } = await getEvmThorTxInfo({ sellAsset, sellAmountCryptoBaseUnit, @@ -314,14 +325,24 @@ export const getL1quote = async ( const buyAmountBeforeFeesCryptoBaseUnit = getRouteBuyAmountBeforeFeesCryptoBaseUnit(quote) - const updatedMemo = addSlippageToMemo({ + const limitWithManualSlippage = getLimitWithManualSlippage({ expectedAmountOutThorBaseUnit, - quotedMemo: quote.memo, slippageBps, - isStreaming, - chainId: sellAsset.chainId, - affiliateBps, }) + + if (!quote.memo) throw new Error('no memo provided') + + let updatedMemo = quote.memo + + // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) + // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 + if (!isStreaming) { + updatedMemo = addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) + } + const { vault, opReturnData, pubkey } = await getUtxoThorTxInfo({ sellAsset, xpub: (input as GetUtxoTradeQuoteInput).xpub, @@ -419,15 +440,24 @@ export const getL1quote = async ( outputExponent: buyAsset.precision, }).toFixed() - const updatedMemo = addSlippageToMemo({ + const limitWithManualSlippage = getLimitWithManualSlippage({ expectedAmountOutThorBaseUnit, - quotedMemo: quote.memo, slippageBps, - isStreaming, - chainId: sellAsset.chainId, - affiliateBps, }) + if (!quote.memo) throw new Error('no memo provided') + + let updatedMemo = quote.memo + + // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) + // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 + if (!isStreaming) { + updatedMemo = addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) + } + return { id: uuid(), memo: updatedMemo, diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.test.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.test.ts new file mode 100644 index 00000000000..4668b366d6f --- /dev/null +++ b/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from 'vitest' + +import { getLimitWithManualSlippage } from './getLimitWithManualSlippage' + +describe('getLimitWithManualSlippage', () => { + it('should remove slippage from expected amount out', () => { + const amountOut = '100' + const expectedLimitWithManualSlippage = '50' + + const slippageBps = 5000 // 50% + + const limitWithManualSlippage = getLimitWithManualSlippage({ + expectedAmountOutThorBaseUnit: amountOut, + slippageBps, + }) + + expect(limitWithManualSlippage).toBe(expectedLimitWithManualSlippage) + }) +}) diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.ts new file mode 100644 index 00000000000..28d05ce0379 --- /dev/null +++ b/src/lib/swapper/swappers/ThorchainSwapper/utils/getLimitWithManualSlippage.ts @@ -0,0 +1,19 @@ +import { bn } from '@shapeshiftoss/chain-adapters' +import BigNumber from 'bignumber.js' +import { subtractBasisPointAmount } from 'state/slices/tradeQuoteSlice/utils' + +export const getLimitWithManualSlippage = ({ + expectedAmountOutThorBaseUnit, + slippageBps, +}: { + expectedAmountOutThorBaseUnit: string + slippageBps: BigNumber.Value +}) => { + const limitWithManualSlippage = subtractBasisPointAmount( + bn(expectedAmountOutThorBaseUnit).toFixed(0, BigNumber.ROUND_DOWN), + slippageBps, + BigNumber.ROUND_DOWN, + ) + + return limitWithManualSlippage +} From ad907d8b9e045937eefbd18632d551a76a6b7819 Mon Sep 17 00:00:00 2001 From: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com> Date: Mon, 17 Jun 2024 09:56:38 +0200 Subject: [PATCH 2/2] fix: review feedbacks --- .../ThorchainSwapper/utils/getL1quote.ts | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts b/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts index 5c6658da1c1..07820d6b986 100644 --- a/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts +++ b/src/lib/swapper/swappers/ThorchainSwapper/utils/getL1quote.ts @@ -218,6 +218,8 @@ export const getL1quote = async ( affiliateBps, slippageBps, }): Promise => { + if (!quote.memo) throw new Error('no memo provided') + const rate = getRouteRate(expectedAmountOutThorBaseUnit) const buyAmountBeforeFeesCryptoBaseUnit = getRouteBuyAmountBeforeFeesCryptoBaseUnit(quote) @@ -227,23 +229,19 @@ export const getL1quote = async ( slippageBps, }) - if (!quote.memo) throw new Error('no memo provided') - - let updatedMemo = quote.memo - // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 - if (!isStreaming) { - updatedMemo = addLimitToMemo({ - memo: quote.memo, - limit: limitWithManualSlippage, - }) - } + const memo = isStreaming + ? quote.memo + : addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) const { data, router, vault } = await getEvmThorTxInfo({ sellAsset, sellAmountCryptoBaseUnit, - memo: updatedMemo, + memo, expiry: quote.expiry, }) @@ -255,7 +253,7 @@ export const getL1quote = async ( return { id: uuid(), - memo: updatedMemo, + memo, receiveAddress, affiliateBps, potentialAffiliateBps, @@ -321,6 +319,8 @@ export const getL1quote = async ( affiliateBps, slippageBps, }): Promise => { + if (!quote.memo) throw new Error('no memo provided') + const rate = getRouteRate(expectedAmountOutThorBaseUnit) const buyAmountBeforeFeesCryptoBaseUnit = getRouteBuyAmountBeforeFeesCryptoBaseUnit(quote) @@ -330,23 +330,19 @@ export const getL1quote = async ( slippageBps, }) - if (!quote.memo) throw new Error('no memo provided') - - let updatedMemo = quote.memo - // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 - if (!isStreaming) { - updatedMemo = addLimitToMemo({ - memo: quote.memo, - limit: limitWithManualSlippage, - }) - } + const memo = isStreaming + ? quote.memo + : addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) const { vault, opReturnData, pubkey } = await getUtxoThorTxInfo({ sellAsset, xpub: (input as GetUtxoTradeQuoteInput).xpub, - memo: updatedMemo, + memo, }) const sellAdapter = assertGetUtxoChainAdapter(sellAsset.chainId) @@ -367,7 +363,7 @@ export const getL1quote = async ( return { id: uuid(), - memo: updatedMemo, + memo, receiveAddress, affiliateBps, potentialAffiliateBps, @@ -430,6 +426,8 @@ export const getL1quote = async ( affiliateBps, slippageBps, }): ThorTradeUtxoOrCosmosQuote => { + if (!quote.memo) throw new Error('no memo provided') + const rate = getRouteRate(expectedAmountOutThorBaseUnit) const buyAmountBeforeFeesCryptoBaseUnit = getRouteBuyAmountBeforeFeesCryptoBaseUnit(quote) @@ -445,22 +443,18 @@ export const getL1quote = async ( slippageBps, }) - if (!quote.memo) throw new Error('no memo provided') - - let updatedMemo = quote.memo - // always use TC auto stream quote (0 limit = 5bps - 50bps, sometimes up to 100bps) // see: https://discord.com/channels/838986635756044328/1166265575941619742/1166500062101250100 - if (!isStreaming) { - updatedMemo = addLimitToMemo({ - memo: quote.memo, - limit: limitWithManualSlippage, - }) - } + const memo = isStreaming + ? quote.memo + : addLimitToMemo({ + memo: quote.memo, + limit: limitWithManualSlippage, + }) return { id: uuid(), - memo: updatedMemo, + memo, receiveAddress, affiliateBps, potentialAffiliateBps,