diff --git a/packages/canonical-bridge-sdk/src/debridge/index.ts b/packages/canonical-bridge-sdk/src/debridge/index.ts index 08491b70..b643bd58 100644 --- a/packages/canonical-bridge-sdk/src/debridge/index.ts +++ b/packages/canonical-bridge-sdk/src/debridge/index.ts @@ -83,7 +83,7 @@ export class DeBridge { try { const deBridgeParams = { srcChainId: fromChainId, - srcChainTokenIn: '0xd5da8318cE7ca005E8F5285Db0e750CA9256586e', + srcChainTokenIn: fromTokenAddress, srcChainTokenInAmount: amount, dstChainId: toChainId, dstChainTokenOut: toTokenAddress, diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx index 88cca6a1..2099f170 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx @@ -84,8 +84,13 @@ export function TransferButton({ const { isConnected: isEvmConnected } = useAccount(); const { isConnected: isTronConnected } = useTronAccount(); const { waitForTxReceipt } = useWaitForTxReceipt(); - const { validateCBridgeToken, validateDeBridgeToken, validateMesonToken, validateStargateToken } = - useValidateSendToken(); + const { + validateCBridgeToken, + validateDeBridgeToken, + validateMesonToken, + validateStargateToken, + validateLayerZeroToken, + } = useValidateSendToken(); const isApproveNeeded = (fromChain?.chainType === 'evm' && @@ -257,7 +262,8 @@ export function TransferButton({ deBridgeHash = await bridgeSDK.deBridge.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, - bridgeAddress: transferActionInfo.bridgeAddress as string, + // bridgeAddress: transferActionInfo.bridgeAddress as string, + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', data: transferActionInfo.data as `0x${string}`, amount: BigInt(transferActionInfo.value), address, @@ -350,6 +356,24 @@ export function TransferButton({ onOpenSubmittedModal(); } } else if (transferActionInfo.bridgeType === 'layerZero' && address) { + // check layerZero token address + const isValidToken = await validateLayerZeroToken({ + publicClient, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + fromTokenAddress: selectedToken.layerZero?.raw?.address as `0x${string}`, + toTokenAddress: toToken?.layerZero?.raw?.address as `0x${string}`, + dstEndpoint: toToken?.layerZero?.raw?.endpointID as number, + }); + if (!isValidToken) { + handleFailure({ + messages: '(Token Validation Failed) - Invalid LayerZero token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.layerZero?.raw?.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + return; + } const layerZeroHash = await bridgeSDK.layerZero.sendToken({ bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, dstEndpoint: toToken?.layerZero?.raw?.endpointID as number, @@ -412,7 +436,7 @@ export function TransferButton({ // get unsigned message const unsignedMessage = await bridgeSDK.meson.getUnsignedMessage({ - fromToken: 'bsc:okse', + fromToken: 'bsc:usdc', // fromToken: `${fromChain?.meson?.raw?.id}:${selectedToken?.meson?.raw?.id}`, toToken: `${toChain?.meson?.raw?.id}:${toToken?.meson?.raw?.id}`, amount: sendValue, diff --git a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts index 7c56ab24..656397fd 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts +++ b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import axios from 'axios'; +import { type PublicClient } from 'viem'; import { CBRIDGE_ENDPOINT, @@ -10,6 +11,8 @@ import { import { ICBridgeTransferConfig, IDeBridgeToken, IStargateTokenList } from '@/modules/aggregator'; import { IMesonTokenList } from '@/modules/aggregator/adapters/meson/types'; import { stargateChainKey } from '@/modules/aggregator/adapters/stargate/const'; +import { isEvmAddress } from '@/core/utils/address'; +import { CAKE_PROXY_OFT_ABI } from '@/modules/aggregator/adapters/layerZero/abi/cakeProxyOFT'; interface ICBridgeTokenValidateParams { isPegged: boolean; @@ -25,6 +28,7 @@ interface IDeBridgeTokenValidateParams { tokenAddress: `0x${string}`; tokenSymbol: string; fromChainId?: number; + toChainId?: number; } interface IStargateTokenValidateParams { @@ -59,6 +63,7 @@ export const useValidateSendToken = () => { `${CBRIDGE_ENDPOINT}/getTransferConfigsForAll`, ); if (!cBridgeConfig) return false; + if (!isEvmAddress(tokenAddress) || !isEvmAddress(bridgeAddress)) return false; if (isPegged === true) { // pegged token const peggedToken = cBridgeConfig.pegged_pair_configs.filter((pair) => { @@ -119,11 +124,13 @@ export const useValidateSendToken = () => { // deBridge const validateDeBridgeToken = async ({ fromChainId, + toChainId, tokenSymbol, tokenAddress, }: IDeBridgeTokenValidateParams) => { try { - if (!fromChainId || !tokenAddress || !tokenSymbol) return false; + if (!fromChainId || !tokenAddress || !tokenSymbol || !toChainId) return false; + if (!isEvmAddress(tokenAddress)) return false; const { data: deBridgeConfig } = await axios.get<{ tokens: { [key: string]: IDeBridgeToken }; }>(`${DEBRIDGE_ENDPOINT}/token-list?chainId=${fromChainId}`); @@ -159,6 +166,7 @@ export const useValidateSendToken = () => { }: IStargateTokenValidateParams) => { try { if (!fromChainId || !tokenAddress || !bridgeAddress || !tokenSymbol) return false; + if (!isEvmAddress(tokenAddress) || !isEvmAddress(bridgeAddress)) return false; const { data: stargateConfig } = await axios.get<{ data: IStargateTokenList }>( `${STARGATE_ENDPOINT}`, ); @@ -195,6 +203,36 @@ export const useValidateSendToken = () => { } }; + // layerZero + const validateLayerZeroToken = async ({ + publicClient, + bridgeAddress, + fromTokenAddress, + toTokenAddress, + dstEndpoint, + }: { + publicClient: PublicClient; + bridgeAddress: `0x${string}`; + fromTokenAddress: `0x${string}`; + toTokenAddress: `0x${string}`; + dstEndpoint?: number; + }) => { + if (!publicClient || !bridgeAddress || !fromTokenAddress || !dstEndpoint || !toTokenAddress) { + return false; + } + const supportedToken = await publicClient.readContract({ + address: bridgeAddress as `0x${string}`, + abi: CAKE_PROXY_OFT_ABI, + functionName: 'token', + }); + + console.log('supportedToken', supportedToken); + if (supportedToken.toLowerCase() === fromTokenAddress.toLowerCase()) { + return true; + } + return false; + }; + // Meson const validateMesonToken = async ({ fromChainId, @@ -204,6 +242,7 @@ export const useValidateSendToken = () => { }: IMesonTokenValidateParams) => { try { if (!fromChainId || !tokenAddress || !tokenSymbol || !bridgeAddress) return false; + if (!isEvmAddress(tokenAddress) || !isEvmAddress(bridgeAddress)) return false; const { data: mesonConfig } = await axios.get<{ result: IMesonTokenList[] }>( `${MESON_ENDPOINT}/limits`, ); @@ -244,5 +283,11 @@ export const useValidateSendToken = () => { } }; - return { validateCBridgeToken, validateDeBridgeToken, validateStargateToken, validateMesonToken }; + return { + validateCBridgeToken, + validateDeBridgeToken, + validateStargateToken, + validateMesonToken, + validateLayerZeroToken, + }; };