diff --git a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx index 140a5b038e..4d1b9989e5 100644 --- a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx +++ b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx @@ -1,4 +1,4 @@ -import { normalize, valueToBigNumber } from '@aave/math-utils'; +import { normalize } from '@aave/math-utils'; import { getOrderToSign, LimitTradeParameters, OrderKind, OrderStatus } from '@cowprotocol/cow-sdk'; import { AaveFlashLoanType, HASH_ZERO } from '@cowprotocol/sdk-flash-loans'; import { Trans } from '@lingui/macro'; @@ -14,18 +14,18 @@ import { zeroAddress } from 'viem'; import { useShallow } from 'zustand/react/shallow'; import { TrackAnalyticsHandlers } from '../../analytics/useTrackAnalytics'; -import { - COW_PARTNER_FEE, - DUST_PROTECTION_MULTIPLIER, - FLASH_LOAN_FEE_BPS, -} from '../../constants/cow.constants'; +import { COW_PARTNER_FEE, FLASH_LOAN_FEE_BPS } from '../../constants/cow.constants'; import { APP_CODE_PER_SWAP_TYPE } from '../../constants/shared.constants'; import { addOrderTypeToAppData, getCowFlashLoanSdk, getCowTradingSdkByChainIdAndAppCode, } from '../../helpers/cow'; -import { calculateInstanceAddress, getHooksGasLimit } from '../../helpers/cow/adapters.helpers'; +import { + accountForDustProtection, + calculateInstanceAddress, + getHooksGasLimit, +} from '../../helpers/cow/adapters.helpers'; import { useCollateralsAmount } from '../../hooks/useCollateralsAmount'; import { useSwapGasEstimation } from '../../hooks/useSwapGasEstimation'; import { @@ -181,11 +181,16 @@ export const DebtSwapActionsViaCoW = ({ ); const flashLoanSdk = await getCowFlashLoanSdk(state.chainId); - const buyAmountWithMarginForDustProtection = valueToBigNumber( - state.buyAmountBigInt.toString() - ) - .multipliedBy(DUST_PROTECTION_MULTIPLIER) - .toFixed(0); + const sellAmountWithMarginForDustProtection = accountForDustProtection( + state.sellAmountBigInt.toString(), + state.swapType, + state.orderType + ); + const buyAmountWithMarginForDustProtection = accountForDustProtection( + state.buyAmountBigInt.toString(), + state.swapType, + state.orderType + ); const delegationPermit = signatureParams ? { @@ -199,7 +204,7 @@ export const DebtSwapActionsViaCoW = ({ const { flashLoanFeeAmount, sellAmountToSign } = flashLoanSdk.calculateFlashLoanAmounts({ flashLoanFeeBps: FLASH_LOAN_FEE_BPS, - sellAmount: state.sellAmountBigInt, + sellAmount: BigInt(sellAmountWithMarginForDustProtection), }); // On Debt Swap, the side is inverted for the swap @@ -239,7 +244,7 @@ export const DebtSwapActionsViaCoW = ({ hooksGasLimit: getHooksGasLimit(debtAmount), }, { - sellAmount: state.sellAmountBigInt, + sellAmount: BigInt(sellAmountWithMarginForDustProtection), buyAmount: BigInt(buyAmountWithMarginForDustProtection), orderToSign, collateralPermit: delegationPermit, diff --git a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx index 3be65c3c45..1fd6597f45 100644 --- a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx +++ b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx @@ -1,4 +1,4 @@ -import { normalize, valueToBigNumber } from '@aave/math-utils'; +import { normalize } from '@aave/math-utils'; import { getOrderToSign, LimitTradeParameters, OrderKind, OrderStatus } from '@cowprotocol/cow-sdk'; import { AaveFlashLoanType, HASH_ZERO } from '@cowprotocol/sdk-flash-loans'; import { Trans } from '@lingui/macro'; @@ -13,18 +13,18 @@ import { saveCowOrderToUserHistory } from 'src/utils/swapAdapterHistory'; import { useShallow } from 'zustand/react/shallow'; import { TrackAnalyticsHandlers } from '../../analytics/useTrackAnalytics'; -import { - COW_PARTNER_FEE, - DUST_PROTECTION_MULTIPLIER, - FLASH_LOAN_FEE_BPS, -} from '../../constants/cow.constants'; +import { COW_PARTNER_FEE, FLASH_LOAN_FEE_BPS } from '../../constants/cow.constants'; import { APP_CODE_PER_SWAP_TYPE } from '../../constants/shared.constants'; import { addOrderTypeToAppData, getCowFlashLoanSdk, getCowTradingSdkByChainIdAndAppCode, } from '../../helpers/cow'; -import { calculateInstanceAddress, getHooksGasLimit } from '../../helpers/cow/adapters.helpers'; +import { + accountForDustProtection, + calculateInstanceAddress, + getHooksGasLimit, +} from '../../helpers/cow/adapters.helpers'; import { useCollateralsAmount } from '../../hooks/useCollateralsAmount'; import { useSwapGasEstimation } from '../../hooks/useSwapGasEstimation'; import { @@ -179,11 +179,16 @@ export const RepayWithCollateralActionsViaCoW = ({ ); const flashLoanSdk = await getCowFlashLoanSdk(state.chainId); - const buyAmountWithMarginForDustProtection = valueToBigNumber( - state.buyAmountBigInt.toString() - ) - .multipliedBy(DUST_PROTECTION_MULTIPLIER) - .toFixed(0); + const sellAmountWithMarginForDustProtection = accountForDustProtection( + state.sellAmountBigInt.toString(), + state.swapType, + state.orderType + ); + const buyAmountWithMarginForDustProtection = accountForDustProtection( + state.buyAmountBigInt.toString(), + state.swapType, + state.orderType + ); const collateralPermit = signatureParams ? { @@ -197,7 +202,7 @@ export const RepayWithCollateralActionsViaCoW = ({ const { flashLoanFeeAmount, sellAmountToSign } = flashLoanSdk.calculateFlashLoanAmounts({ flashLoanFeeBps: FLASH_LOAN_FEE_BPS, - sellAmount: state.sellAmountBigInt, + sellAmount: BigInt(sellAmountWithMarginForDustProtection), }); // In Repay With Collateral, the order is inverted, we need to sell the collateral to repay with and do a BUY order to the repay amount @@ -237,7 +242,7 @@ export const RepayWithCollateralActionsViaCoW = ({ hooksGasLimit: getHooksGasLimit(collateralsAmount), }, { - sellAmount: state.sellAmountBigInt, + sellAmount: BigInt(sellAmountWithMarginForDustProtection), buyAmount: BigInt(buyAmountWithMarginForDustProtection), orderToSign, collateralPermit, diff --git a/src/components/transactions/Swap/constants/cow.constants.ts b/src/components/transactions/Swap/constants/cow.constants.ts index 2dcf044eb0..0ea41ff57c 100644 --- a/src/components/transactions/Swap/constants/cow.constants.ts +++ b/src/components/transactions/Swap/constants/cow.constants.ts @@ -60,7 +60,7 @@ export const ADAPTER_FACTORY: Record = { [SupportedChainId.SEPOLIA]: '', }; -export const DUST_PROTECTION_MULTIPLIER = 1.001; +export const DUST_PROTECTION_MULTIPLIER = 1.0003; // 3 BPS export const COW_UNSUPPORTED_ASSETS: Partial< Record>> @@ -151,7 +151,6 @@ export const COW_PARTNER_FEE = (tokenFromSymbol: string, tokenToSymbol: string) }); export const FLASH_LOAN_FEE_BPS = 5; -export const VALID_TO_HALF_HOUR = Math.floor(Date.now() / 1000) + 60 * 30; // 30 minutes export const COW_APP_DATA = ( tokenFromSymbol: string, diff --git a/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts b/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts index ae44766ec4..3b0cf9e519 100644 --- a/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts +++ b/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts @@ -23,6 +23,17 @@ import { import { isCowProtocolRates, OrderType, SwapProvider, SwapState, SwapType } from '../../types'; import { getCowFlashLoanSdk } from './env.helpers'; +export const accountForDustProtection = ( + amount: string, + swapType: SwapType, + orderType: OrderType +) => { + return (swapType == SwapType.DebtSwap || swapType == SwapType.RepayWithCollateral) && + orderType == OrderType.MARKET + ? valueToBigNumber(amount).multipliedBy(DUST_PROTECTION_MULTIPLIER).toFixed(0) + : amount; +}; + export const calculateInstanceAddress = async ({ user, validTo, @@ -45,7 +56,7 @@ export const calculateInstanceAddress = async ({ const flashLoanSdk = await getCowFlashLoanSdk(state.chainId); const { - sellAmount, + sellAmountWithMarginForDustProtection, buyAmountWithMarginForDustProtection, buyAmount, sellToken, @@ -55,14 +66,16 @@ export const calculateInstanceAddress = async ({ slippageBps, partnerFee, } = { - sellAmount: state.sellAmountBigInt, - // @note: We wont have dust for borrow side, but we may have dust in collateral swaps - buyAmountWithMarginForDustProtection: - state.swapType !== SwapType.CollateralSwap - ? valueToBigNumber(state.buyAmountBigInt.toString()) - .multipliedBy(DUST_PROTECTION_MULTIPLIER) - .toFixed(0) - : state.buyAmountBigInt, + sellAmountWithMarginForDustProtection: accountForDustProtection( + state.sellAmountBigInt.toString(), + state.swapType, + state.orderType + ), + buyAmountWithMarginForDustProtection: accountForDustProtection( + state.buyAmountBigInt.toString(), + state.swapType, + state.orderType + ), sellToken: state.sellAmountToken, buyAmount: state.buyAmountBigInt, buyToken: state.buyAmountToken, @@ -74,7 +87,7 @@ export const calculateInstanceAddress = async ({ const { flashLoanFeeAmount, sellAmountToSign } = flashLoanSdk.calculateFlashLoanAmounts({ flashLoanFeeBps: FLASH_LOAN_FEE_BPS, - sellAmount: sellAmount, + sellAmount: BigInt(sellAmountWithMarginForDustProtection), }); const limitOrder: LimitTradeParameters = { @@ -110,9 +123,9 @@ export const calculateInstanceAddress = async ({ }; const hookAmounts: FlashLoanHookAmounts = { - flashLoanAmount: sellAmount.toString(), + flashLoanAmount: sellAmountWithMarginForDustProtection.toString(), flashLoanFeeAmount: flashLoanFeeAmount.toString(), - sellAssetAmount: sellAmount.toString(), + sellAssetAmount: sellAmountWithMarginForDustProtection.toString(), buyAssetAmount: buyAmountWithMarginForDustProtection.toString(), }; diff --git a/src/components/transactions/Swap/hooks/useSwapOrderAmounts.ts b/src/components/transactions/Swap/hooks/useSwapOrderAmounts.ts index e35f0777b2..78b5196041 100644 --- a/src/components/transactions/Swap/hooks/useSwapOrderAmounts.ts +++ b/src/components/transactions/Swap/hooks/useSwapOrderAmounts.ts @@ -357,6 +357,6 @@ export const useSwapOrderAmounts = ({ state.side, state.swapType, state.orderType, - state.useFlashloan + state.useFlashloan, ]); };