|
| 1 | +import { |
| 2 | + AaveV3Arbitrum, |
| 3 | + AaveV3Avalanche, |
| 4 | + AaveV3Base, |
| 5 | + AaveV3BNB, |
| 6 | + AaveV3Ethereum, |
| 7 | + AaveV3EthereumEtherFi, |
| 8 | + AaveV3EthereumLido, |
| 9 | + AaveV3Gnosis, |
| 10 | + AaveV3Optimism, |
| 11 | + AaveV3Polygon, |
| 12 | + AaveV3Sonic, |
| 13 | +} from '@aave-dao/aave-address-book'; |
| 14 | +import { SupportedChainId } from '@cowprotocol/cow-sdk'; |
| 15 | +import { useQuery } from '@tanstack/react-query'; |
| 16 | +import { Contract } from 'ethers'; |
| 17 | +import { CustomMarket, MarketDataType } from 'src/ui-config/marketsConfig'; |
| 18 | +import { getProvider } from 'src/utils/marketsAndNetworksConfig'; |
| 19 | + |
| 20 | +import { ADAPTER_FACTORY, FLASH_LOAN_FEE_BPS } from '../constants/cow.constants'; |
| 21 | +import { PARASWAP_FLASH_LOAN_FEE_BPS } from '../constants/paraswap.constants'; |
| 22 | +import { SwapProvider, SwapType } from '../types'; |
| 23 | + |
| 24 | +const ACL_MANAGER_ABI = ['function isFlashBorrower(address) view returns (bool)']; |
| 25 | + |
| 26 | +const ACL_MANAGER_BY_MARKET: Partial<Record<CustomMarket, string>> = { |
| 27 | + [CustomMarket.proto_mainnet_v3]: AaveV3Ethereum.ACL_MANAGER, |
| 28 | + [CustomMarket.proto_lido_v3]: AaveV3EthereumLido.ACL_MANAGER, |
| 29 | + [CustomMarket.proto_etherfi_v3]: AaveV3EthereumEtherFi.ACL_MANAGER, |
| 30 | + [CustomMarket.proto_arbitrum_v3]: AaveV3Arbitrum.ACL_MANAGER, |
| 31 | + [CustomMarket.proto_base_v3]: AaveV3Base.ACL_MANAGER, |
| 32 | + [CustomMarket.proto_polygon_v3]: AaveV3Polygon.ACL_MANAGER, |
| 33 | + [CustomMarket.proto_optimism_v3]: AaveV3Optimism.ACL_MANAGER, |
| 34 | + [CustomMarket.proto_avalanche_v3]: AaveV3Avalanche.ACL_MANAGER, |
| 35 | + [CustomMarket.proto_sonic_v3]: AaveV3Sonic.ACL_MANAGER, |
| 36 | + [CustomMarket.proto_gnosis_v3]: AaveV3Gnosis.ACL_MANAGER, |
| 37 | + [CustomMarket.proto_bnb_v3]: AaveV3BNB.ACL_MANAGER, |
| 38 | +}; |
| 39 | + |
| 40 | +const fallbackBps = (provider: SwapProvider): number => |
| 41 | + provider === SwapProvider.COW_PROTOCOL ? FLASH_LOAN_FEE_BPS : PARASWAP_FLASH_LOAN_FEE_BPS; |
| 42 | + |
| 43 | +const resolveTarget = ( |
| 44 | + provider: SwapProvider, |
| 45 | + swapType: SwapType, |
| 46 | + marketData: MarketDataType |
| 47 | +): string | undefined => { |
| 48 | + if (provider === SwapProvider.COW_PROTOCOL) { |
| 49 | + return ADAPTER_FACTORY[marketData.chainId as unknown as SupportedChainId] || undefined; |
| 50 | + } |
| 51 | + if (provider === SwapProvider.PARASWAP) { |
| 52 | + switch (swapType) { |
| 53 | + case SwapType.CollateralSwap: |
| 54 | + return marketData.addresses.SWAP_COLLATERAL_ADAPTER; |
| 55 | + case SwapType.RepayWithCollateral: |
| 56 | + return marketData.addresses.REPAY_WITH_COLLATERAL_ADAPTER; |
| 57 | + case SwapType.DebtSwap: |
| 58 | + return marketData.addresses.DEBT_SWITCH_ADAPTER; |
| 59 | + case SwapType.WithdrawAndSwap: |
| 60 | + return marketData.addresses.WITHDRAW_SWITCH_ADAPTER; |
| 61 | + default: |
| 62 | + return undefined; |
| 63 | + } |
| 64 | + } |
| 65 | + return undefined; |
| 66 | +}; |
| 67 | + |
| 68 | +/** |
| 69 | + * Resolve the flashloan fee bps for the active swap, defaulting to the |
| 70 | + * provider's hardcoded bps when the on-chain ACLManager check is unavailable |
| 71 | + * or pending. Returns 0 only when the target adapter (Paraswap per-flow) / |
| 72 | + * factory (CoW) is registered as a FLASH_BORROWER on the market's ACLManager. |
| 73 | + */ |
| 74 | +export const useFlashLoanFeeBps = ({ |
| 75 | + provider, |
| 76 | + swapType, |
| 77 | + marketData, |
| 78 | +}: { |
| 79 | + provider: SwapProvider; |
| 80 | + swapType: SwapType; |
| 81 | + marketData: MarketDataType; |
| 82 | +}): number => { |
| 83 | + const aclManager = ACL_MANAGER_BY_MARKET[marketData.market]; |
| 84 | + const target = resolveTarget(provider, swapType, marketData); |
| 85 | + const fallback = fallbackBps(provider); |
| 86 | + |
| 87 | + const enabled = Boolean(aclManager && target); |
| 88 | + |
| 89 | + const { data: isWhitelisted } = useQuery({ |
| 90 | + queryFn: async (): Promise<boolean> => { |
| 91 | + const contract = new Contract( |
| 92 | + aclManager as string, |
| 93 | + ACL_MANAGER_ABI, |
| 94 | + getProvider(marketData.chainId) |
| 95 | + ); |
| 96 | + return contract.isFlashBorrower(target); |
| 97 | + }, |
| 98 | + queryKey: ['flashBorrowerCheck', marketData.chainId, aclManager, target], |
| 99 | + enabled, |
| 100 | + staleTime: 5 * 60 * 1000, |
| 101 | + }); |
| 102 | + |
| 103 | + return isWhitelisted === true ? 0 : fallback; |
| 104 | +}; |
0 commit comments