Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -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';
Expand All @@ -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 {
Expand Down Expand Up @@ -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
? {
Expand All @@ -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
Expand Down Expand Up @@ -239,7 +244,7 @@ export const DebtSwapActionsViaCoW = ({
hooksGasLimit: getHooksGasLimit(debtAmount),
},
{
sellAmount: state.sellAmountBigInt,
sellAmount: BigInt(sellAmountWithMarginForDustProtection),
buyAmount: BigInt(buyAmountWithMarginForDustProtection),
orderToSign,
collateralPermit: delegationPermit,
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 {
Expand Down Expand Up @@ -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
? {
Expand All @@ -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
Expand Down Expand Up @@ -237,7 +242,7 @@ export const RepayWithCollateralActionsViaCoW = ({
hooksGasLimit: getHooksGasLimit(collateralsAmount),
},
{
sellAmount: state.sellAmountBigInt,
sellAmount: BigInt(sellAmountWithMarginForDustProtection),
buyAmount: BigInt(buyAmountWithMarginForDustProtection),
orderToSign,
collateralPermit,
Expand Down
3 changes: 1 addition & 2 deletions src/components/transactions/Swap/constants/cow.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const ADAPTER_FACTORY: Record<SupportedChainId, string> = {
[SupportedChainId.SEPOLIA]: '',
};

export const DUST_PROTECTION_MULTIPLIER = 1.001;
Copy link
Contributor Author

@mgrabina mgrabina Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👉 Conservative market
Max APR ≈ 80%
Max per hour: 0.91 bps

👉 Aggressive / volatile market
Max APR ≈ 300%
Max per hour:≈3.4 bps

👉 Extreme custom strategy (rare but allowed)
Max APR ≈ 1000%
Max per hour:≈11.4 bps

We have 10 min max now.

export const DUST_PROTECTION_MULTIPLIER = 1.0003; // 3 BPS

export const COW_UNSUPPORTED_ASSETS: Partial<
Record<SwapType | 'ALL', Partial<Record<SupportedChainId, string[] | 'ALL'>>>
Expand Down Expand Up @@ -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,
Expand Down
37 changes: 25 additions & 12 deletions src/components/transactions/Swap/helpers/cow/adapters.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -45,7 +56,7 @@ export const calculateInstanceAddress = async ({

const flashLoanSdk = await getCowFlashLoanSdk(state.chainId);
const {
sellAmount,
sellAmountWithMarginForDustProtection,
buyAmountWithMarginForDustProtection,
buyAmount,
sellToken,
Expand All @@ -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,
Expand All @@ -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 = {
Expand Down Expand Up @@ -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(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,6 @@ export const useSwapOrderAmounts = ({
state.side,
state.swapType,
state.orderType,
state.useFlashloan
state.useFlashloan,
]);
};
Loading