From bcf65ef741515025101681afa1c45bc1fdd59da7 Mon Sep 17 00:00:00 2001 From: wenty22 Date: Thu, 28 Nov 2024 16:27:44 +0800 Subject: [PATCH 1/4] fix: Fix colorMode does not follow the parameter --- .release/.changeset/itchy-flies-fail.md | 5 ++++ .release/.changeset/pre.json | 1 + packages/canonical-bridge-widget/CHANGELOG.md | 6 ++++ packages/canonical-bridge-widget/package.json | 2 +- .../src/CanonicalBridgeProvider.tsx | 18 +++++++----- .../src/core/theme/ThemeProvider.tsx | 29 ++++++++----------- 6 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 .release/.changeset/itchy-flies-fail.md diff --git a/.release/.changeset/itchy-flies-fail.md b/.release/.changeset/itchy-flies-fail.md new file mode 100644 index 00000000..ea88d707 --- /dev/null +++ b/.release/.changeset/itchy-flies-fail.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Fix colorMode does not follow the parameter diff --git a/.release/.changeset/pre.json b/.release/.changeset/pre.json index 61f7478b..140ca611 100644 --- a/.release/.changeset/pre.json +++ b/.release/.changeset/pre.json @@ -10,6 +10,7 @@ "gorgeous-maps-fly", "grumpy-squids-collect", "honest-lies-cheer", + "itchy-flies-fail", "late-swans-sparkle", "lovely-maps-study", "quick-pots-tease", diff --git a/packages/canonical-bridge-widget/CHANGELOG.md b/packages/canonical-bridge-widget/CHANGELOG.md index ec483cf0..7d178fef 100644 --- a/packages/canonical-bridge-widget/CHANGELOG.md +++ b/packages/canonical-bridge-widget/CHANGELOG.md @@ -1,5 +1,11 @@ # @bnb-chain/canonical-bridge-widget +## 0.5.4-alpha.4 + +### Patch Changes + +- Fix colorMode does not follow the parameter + ## 0.5.4-alpha.3 ### Patch Changes diff --git a/packages/canonical-bridge-widget/package.json b/packages/canonical-bridge-widget/package.json index b465b330..2db430a1 100644 --- a/packages/canonical-bridge-widget/package.json +++ b/packages/canonical-bridge-widget/package.json @@ -1,6 +1,6 @@ { "name": "@bnb-chain/canonical-bridge-widget", - "version": "0.5.4-alpha.3", + "version": "0.5.4-alpha.4", "description": "canonical bridge widget", "author": "bnb-chain", "private": false, diff --git a/packages/canonical-bridge-widget/src/CanonicalBridgeProvider.tsx b/packages/canonical-bridge-widget/src/CanonicalBridgeProvider.tsx index ff25475a..79554080 100644 --- a/packages/canonical-bridge-widget/src/CanonicalBridgeProvider.tsx +++ b/packages/canonical-bridge-widget/src/CanonicalBridgeProvider.tsx @@ -1,9 +1,9 @@ import React, { useContext, useMemo } from 'react'; -import { ColorMode, IntlProvider } from '@bnb-chain/space'; +import { ColorMode, IntlProvider, theme } from '@bnb-chain/space'; import { ChainType, IChainConfig, ITransferConfig } from '@/modules/aggregator/types'; import { StoreProvider } from '@/modules/store/StoreProvider'; -import { ThemeProvider, ThemeProviderProps } from '@/core/theme/ThemeProvider'; +import { ThemeProvider } from '@/core/theme/ThemeProvider'; import { AggregatorProvider } from '@/modules/aggregator/components/AggregatorProvider'; import { TokenBalancesProvider } from '@/modules/aggregator/components/TokenBalancesProvider'; import { TokenPricesProvider } from '@/modules/aggregator/components/TokenPricesProvider'; @@ -17,7 +17,12 @@ export interface ICanonicalBridgeConfig { appearance: { colorMode?: ColorMode; - theme?: ThemeProviderProps['themeConfig']; + theme?: { + dark?: any; + light?: any; + fontFamily?: string; + breakpoints?: Partial; + }; locale?: string; messages?: Record; bridgeTitle?: string; @@ -75,7 +80,7 @@ export function CanonicalBridgeProvider(props: CanonicalBridgeProviderProps) { appearance: { bridgeTitle: 'BNB Chain Cross-Chain Bridge', - mode: 'dark', + colorMode: 'dark', locale: 'en', messages: locales.en, ...config.appearance, @@ -100,10 +105,7 @@ export function CanonicalBridgeProvider(props: CanonicalBridgeProviderProps) { - + diff --git a/packages/canonical-bridge-widget/src/core/theme/ThemeProvider.tsx b/packages/canonical-bridge-widget/src/core/theme/ThemeProvider.tsx index 95b70912..9de3dfa3 100644 --- a/packages/canonical-bridge-widget/src/core/theme/ThemeProvider.tsx +++ b/packages/canonical-bridge-widget/src/core/theme/ThemeProvider.tsx @@ -1,4 +1,4 @@ -import { ChakraProvider, theme, createLocalStorageManager, ColorMode } from '@bnb-chain/space'; +import { ChakraProvider, ColorMode, theme } from '@bnb-chain/space'; import { useMemo } from 'react'; import { merge } from 'lodash'; @@ -8,24 +8,13 @@ import { walletStyles } from '@/core/theme/walletStyles'; import { useBridgeConfig } from '@/CanonicalBridgeProvider'; export interface ThemeProviderProps { - colorMode?: ColorMode; children: React.ReactNode; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - themeConfig?: { - dark?: any; - light?: any; - fontFamily?: string; - breakpoints?: Partial; - }; } -export const ThemeProvider = ({ - children, - colorMode = 'dark', - themeConfig, -}: ThemeProviderProps) => { - const { appName: APP_NAME } = useBridgeConfig(); - const colorModeManager = createLocalStorageManager(`${APP_NAME}-color-mode`); +export const ThemeProvider = ({ children }: ThemeProviderProps) => { + const { appearance } = useBridgeConfig(); + const { theme: themeConfig, colorMode } = appearance; + const customTheme = useMemo(() => { return { ...theme, @@ -57,7 +46,13 @@ export const ThemeProvider = ({ return ( Date: Thu, 28 Nov 2024 16:43:19 +0800 Subject: [PATCH 2/4] fix: Extract the part of the svg icon that contains the id as the common component --- .../core/components/icons/SvgDefs.tsx | 69 +++++++++++++++++++ .../components/icons/wallets/PhantomIcon.tsx | 5 -- .../components/icons/wallets/TronLinkIcon.tsx | 22 ------ .../icons/wallets/TrustWalletIcon.tsx | 28 -------- apps/canonical-bridge-ui/pages/_app.tsx | 2 + 5 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 apps/canonical-bridge-ui/core/components/icons/SvgDefs.tsx diff --git a/apps/canonical-bridge-ui/core/components/icons/SvgDefs.tsx b/apps/canonical-bridge-ui/core/components/icons/SvgDefs.tsx new file mode 100644 index 00000000..f14ee92d --- /dev/null +++ b/apps/canonical-bridge-ui/core/components/icons/SvgDefs.tsx @@ -0,0 +1,69 @@ +import { Icon } from '@bnb-chain/space'; + +export function SvgDefs() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/canonical-bridge-ui/core/components/icons/wallets/PhantomIcon.tsx b/apps/canonical-bridge-ui/core/components/icons/wallets/PhantomIcon.tsx index 39aef1c8..1c042d97 100644 --- a/apps/canonical-bridge-ui/core/components/icons/wallets/PhantomIcon.tsx +++ b/apps/canonical-bridge-ui/core/components/icons/wallets/PhantomIcon.tsx @@ -10,11 +10,6 @@ export function PhantomIcon(props: IconProps) { fill="#AB9FF2" /> - - - - - ); } diff --git a/apps/canonical-bridge-ui/core/components/icons/wallets/TronLinkIcon.tsx b/apps/canonical-bridge-ui/core/components/icons/wallets/TronLinkIcon.tsx index 74e219b9..d522dd44 100644 --- a/apps/canonical-bridge-ui/core/components/icons/wallets/TronLinkIcon.tsx +++ b/apps/canonical-bridge-ui/core/components/icons/wallets/TronLinkIcon.tsx @@ -8,12 +8,6 @@ export function TronLinkIcon(props: IconProps) { d="M7.30721 0C3.27132 0 0 3.59886 0 8.03839V56.9616C0 61.4011 3.27132 65 7.30721 65H57.6928C61.7283 65 65 61.4011 65 56.9616V8.03839C65 3.59886 61.7283 0 57.6928 0H7.30721Z" fill="url(#paint0_linear_18_3)" /> - - - - - - - - - - - - ); } diff --git a/apps/canonical-bridge-ui/core/components/icons/wallets/TrustWalletIcon.tsx b/apps/canonical-bridge-ui/core/components/icons/wallets/TrustWalletIcon.tsx index bcc92ccd..f10d3e2f 100644 --- a/apps/canonical-bridge-ui/core/components/icons/wallets/TrustWalletIcon.tsx +++ b/apps/canonical-bridge-ui/core/components/icons/wallets/TrustWalletIcon.tsx @@ -16,34 +16,6 @@ export function TrustWalletIcon(props: IconProps) { d="M18.6662 6.66673L12.0003 4.5V19.5C16.7622 17.4998 18.6662 13.6665 18.6662 11.5001V6.66673Z" fill="url(#paint1_linear_7476_132116)" /> - - - - - - - - - - - - - - ); } diff --git a/apps/canonical-bridge-ui/pages/_app.tsx b/apps/canonical-bridge-ui/pages/_app.tsx index 011805d1..8f21c5c4 100644 --- a/apps/canonical-bridge-ui/pages/_app.tsx +++ b/apps/canonical-bridge-ui/pages/_app.tsx @@ -4,6 +4,7 @@ import Head from 'next/head'; import { AppProps } from 'next/app'; import { ThemeProvider } from '@/core/components/ThemeProvider'; +import { SvgDefs } from '@/core/components/icons/SvgDefs'; const queryClient = new QueryClient({ defaultOptions: { @@ -23,6 +24,7 @@ export default function App({ Component, ...restProps }: AppProps) { + From ee00ad3e1e3e7dde8eefbfa8fa124ac07f9694b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 28 Nov 2024 08:56:38 +0000 Subject: [PATCH 3/4] chore: Update versions --- .release/.changeset/few-cherries-smile.md | 5 ----- .release/.changeset/gorgeous-maps-fly.md | 5 ----- .release/.changeset/grumpy-squids-collect.md | 5 ----- .release/.changeset/honest-lies-cheer.md | 5 ----- .release/.changeset/itchy-flies-fail.md | 5 ----- .release/.changeset/late-swans-sparkle.md | 5 ----- .release/.changeset/lovely-maps-study.md | 5 ----- .release/.changeset/pre.json | 20 ------------------- .release/.changeset/quick-pots-tease.md | 5 ----- .release/.changeset/tall-spiders-love.md | 5 ----- .release/.changeset/twelve-moose-sit.md | 5 ----- packages/canonical-bridge-widget/CHANGELOG.md | 15 ++++++++++++++ packages/canonical-bridge-widget/package.json | 2 +- 13 files changed, 16 insertions(+), 71 deletions(-) delete mode 100644 .release/.changeset/few-cherries-smile.md delete mode 100644 .release/.changeset/gorgeous-maps-fly.md delete mode 100644 .release/.changeset/grumpy-squids-collect.md delete mode 100644 .release/.changeset/honest-lies-cheer.md delete mode 100644 .release/.changeset/itchy-flies-fail.md delete mode 100644 .release/.changeset/late-swans-sparkle.md delete mode 100644 .release/.changeset/lovely-maps-study.md delete mode 100644 .release/.changeset/pre.json delete mode 100644 .release/.changeset/quick-pots-tease.md delete mode 100644 .release/.changeset/tall-spiders-love.md delete mode 100644 .release/.changeset/twelve-moose-sit.md diff --git a/.release/.changeset/few-cherries-smile.md b/.release/.changeset/few-cherries-smile.md deleted file mode 100644 index 14575efd..00000000 --- a/.release/.changeset/few-cherries-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Support custom breakpoints diff --git a/.release/.changeset/gorgeous-maps-fly.md b/.release/.changeset/gorgeous-maps-fly.md deleted file mode 100644 index 4eb23f4e..00000000 --- a/.release/.changeset/gorgeous-maps-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Fix wallet issues diff --git a/.release/.changeset/grumpy-squids-collect.md b/.release/.changeset/grumpy-squids-collect.md deleted file mode 100644 index 4eb23f4e..00000000 --- a/.release/.changeset/grumpy-squids-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Fix wallet issues diff --git a/.release/.changeset/honest-lies-cheer.md b/.release/.changeset/honest-lies-cheer.md deleted file mode 100644 index 22d8e410..00000000 --- a/.release/.changeset/honest-lies-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Remove delayTime for wallet diff --git a/.release/.changeset/itchy-flies-fail.md b/.release/.changeset/itchy-flies-fail.md deleted file mode 100644 index ea88d707..00000000 --- a/.release/.changeset/itchy-flies-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Fix colorMode does not follow the parameter diff --git a/.release/.changeset/late-swans-sparkle.md b/.release/.changeset/late-swans-sparkle.md deleted file mode 100644 index 4eb23f4e..00000000 --- a/.release/.changeset/late-swans-sparkle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Fix wallet issues diff --git a/.release/.changeset/lovely-maps-study.md b/.release/.changeset/lovely-maps-study.md deleted file mode 100644 index e782ac60..00000000 --- a/.release/.changeset/lovely-maps-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Support custom connect wallet button diff --git a/.release/.changeset/pre.json b/.release/.changeset/pre.json deleted file mode 100644 index 140ca611..00000000 --- a/.release/.changeset/pre.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "mode": "pre", - "tag": "alpha", - "initialVersions": { - "@bnb-chain/canonical-bridge-sdk": "0.4.1", - "@bnb-chain/canonical-bridge-widget": "0.5.1" - }, - "changesets": [ - "few-cherries-smile", - "gorgeous-maps-fly", - "grumpy-squids-collect", - "honest-lies-cheer", - "itchy-flies-fail", - "late-swans-sparkle", - "lovely-maps-study", - "quick-pots-tease", - "tall-spiders-love", - "twelve-moose-sit" - ] -} diff --git a/.release/.changeset/quick-pots-tease.md b/.release/.changeset/quick-pots-tease.md deleted file mode 100644 index 76aa1823..00000000 --- a/.release/.changeset/quick-pots-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Show all tokens in token list with different token address diff --git a/.release/.changeset/tall-spiders-love.md b/.release/.changeset/tall-spiders-love.md deleted file mode 100644 index f8453a4c..00000000 --- a/.release/.changeset/tall-spiders-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Separate wallet component diff --git a/.release/.changeset/twelve-moose-sit.md b/.release/.changeset/twelve-moose-sit.md deleted file mode 100644 index 79edb826..00000000 --- a/.release/.changeset/twelve-moose-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bnb-chain/canonical-bridge-widget": patch ---- - -Add log for solana diff --git a/packages/canonical-bridge-widget/CHANGELOG.md b/packages/canonical-bridge-widget/CHANGELOG.md index 7d178fef..f9ed6d81 100644 --- a/packages/canonical-bridge-widget/CHANGELOG.md +++ b/packages/canonical-bridge-widget/CHANGELOG.md @@ -1,5 +1,20 @@ # @bnb-chain/canonical-bridge-widget +## 0.5.4 + +### Patch Changes + +- 8d3b6d1: Support custom breakpoints +- b95b3ab: Fix wallet issues +- fb73ca4: Fix wallet issues +- da03355: Remove delayTime for wallet +- bcf65ef: Fix colorMode does not follow the parameter +- 6d78c07: Fix wallet issues +- 3146b01: Support custom connect wallet button +- dc0fcac: Show all tokens in token list with different token address +- cdf450d: Separate wallet component +- 0f6c74c: Add log for solana + ## 0.5.4-alpha.4 ### Patch Changes diff --git a/packages/canonical-bridge-widget/package.json b/packages/canonical-bridge-widget/package.json index 2db430a1..52df5051 100644 --- a/packages/canonical-bridge-widget/package.json +++ b/packages/canonical-bridge-widget/package.json @@ -1,6 +1,6 @@ { "name": "@bnb-chain/canonical-bridge-widget", - "version": "0.5.4-alpha.4", + "version": "0.5.4", "description": "canonical bridge widget", "author": "bnb-chain", "private": false, From 9026cb5b894a8c79b6241bb5b6f6a9a29590d88a Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 2 Dec 2024 16:42:44 +1000 Subject: [PATCH 4/4] feat: Bridge and token address validation --- .../src/core/constants/index.ts | 5 + .../aggregator/adapters/meson/types.ts | 16 ++ .../adapters/stargate/const/index.ts | 24 ++ .../aggregator/adapters/stargate/types.ts | 43 ++++ .../components/Button/TransferButton.tsx | 71 +++++- .../transfer/hooks/useSendTokenValidation.ts | 239 ++++++++++++++++++ 6 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts create mode 100644 packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts diff --git a/packages/canonical-bridge-widget/src/core/constants/index.ts b/packages/canonical-bridge-widget/src/core/constants/index.ts index e5189218..6604baee 100644 --- a/packages/canonical-bridge-widget/src/core/constants/index.ts +++ b/packages/canonical-bridge-widget/src/core/constants/index.ts @@ -15,6 +15,11 @@ export const DEFAULT_ADDRESS = '0x6836CbaCbBd1E798cC56802AC7d8BDf6Da0d0980'; export const DEFAULT_TRON_ADDRESS = 'TTb3A6ASFejJuGcM1UVcRCJA23WGiJKSiY'; export const DEFAULT_SOLANA_ADDRESS = 'J7JYXS8PMMBgfFKP1bqUu7mGgWyWUDL9xqfYujznc61r'; +export const CBRIDGE_ENDPOINT = 'https://cbridge-prod2.celer.app/v2'; +export const DEBRIDGE_ENDPOINT = 'https://deswap.debridge.finance/v1.0'; +export const STARGATE_ENDPOINT = 'https://mainnet.stargate-api.com/v1/metadata?version=v2'; +export const MESON_ENDPOINT = 'https://relayer.meson.fi/api/v1'; + export const nativeTokenMap = { 1: 'ETH', 10: 'ETH', diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts index eaa25eb3..fc107639 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts @@ -13,3 +13,19 @@ export interface IMesonChain { address: string; // bridge address tokens: IMesonToken[]; } + +interface IMesonTokenLimits { + id: string; + decimals: number; + addr?: `0x${string}`; + min: string; + max: string; +} + +export interface IMesonTokenList { + id: string; + name: string; + chainId: `0x${string}`; + address: `0x${string}`; + tokens: IMesonTokenLimits[]; +} diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts new file mode 100644 index 00000000..d1ae31e5 --- /dev/null +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts @@ -0,0 +1,24 @@ +export const stargateChainKey: { [key: number]: string } = { + 1: 'ethereum', + 10: 'optimism', + 14: 'flare', + 56: 'bsc', + 137: 'polygon', + 250: 'fantom', + 1088: 'metis', + 1116: 'coredao', + 1329: 'sei', + 1625: 'gravity', + 2222: 'kava', + 5000: 'mantle', + 8217: 'klaytn', + 8453: 'base', + 8822: 'iota', + 42161: 'arbitrum', + 43114: 'avalanche', + 59144: 'linea', + 167000: 'taiko', + 534352: 'scroll', + 1313161554: 'aurora', + 1380012617: 'rarible', +}; diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts index 95ca11c2..5e90f9de 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts @@ -39,3 +39,46 @@ export interface IStargateBusDriveSettings { maxWaitTime: number; passengersToDrive: number; } + +export interface IStargateBridgeTokenInfo { + stargateType: string; + address: `0x${string}`; + token: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + lpToken: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + farm: { + stargateStaking: { + address: `0x${string}`; + rewardTokens: [ + { + address: `0x${string}`; + decimals: number; + symbol: string; + }, + { + address: `0x${string}`; + decimals: number; + symbol: string; + }, + ]; + }; + }; + id: string; + assetId: string; + chainKey: string; + chainName: string; + tokenMessaging: `0x${string}`; + sharedDecimals: number; +} + +export interface IStargateTokenList { + v1: IStargateBridgeTokenInfo[]; + v2: IStargateBridgeTokenInfo[]; +} 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 91876e9f..1c97469d 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 @@ -20,6 +20,7 @@ import { useTronContract } from '@/modules/aggregator/adapters/meson/hooks/useTr import { useSolanaTransferInfo } from '@/modules/transfer/hooks/solana/useSolanaTransferInfo'; import { useTronAccount } from '@/modules/wallet/hooks/useTronAccount'; import { useWaitForTxReceipt } from '@/core/hooks/useWaitForTxReceipt'; +import { useValidateSendToken } from '@/modules/transfer/hooks/useSendTokenValidation'; export function TransferButton({ onOpenSubmittedModal, @@ -83,6 +84,8 @@ export function TransferButton({ const { isConnected: isEvmConnected } = useAccount(); const { isConnected: isTronConnected } = useTronAccount(); const { waitForTxReceipt } = useWaitForTxReceipt(); + const { validateCBridgeToken, validateDeBridgeToken, validateMesonToken, validateStargateToken } = + useValidateSendToken(); const isApproveNeeded = (fromChain?.chainType === 'evm' && @@ -171,6 +174,26 @@ export function TransferButton({ if (transferActionInfo.bridgeType === 'cBridge' && cBridgeArgs && fromChain && address) { try { + const isValid = await validateCBridgeToken({ + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + fromChainId: fromChain.id, + isPegged: selectedToken.isPegged, + tokenSymbol: selectedToken.symbol, + toChainId: toChain?.id, + }); + if (!isValid) { + handleFailure({ + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + fromChainId: fromChain.id, + isPegged: selectedToken.isPegged, + tokenSymbol: selectedToken.symbol, + toChainId: toChain?.id, + message: `Invalid cBridge token!!`, + }); + return; + } const cBridgeHash = await bridgeSDK.cBridge.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, @@ -212,8 +235,21 @@ export function TransferButton({ } else if (transferActionInfo.bridgeType === 'deBridge') { try { let deBridgeHash: string | undefined; - if (fromChain?.chainType === 'evm' && transferActionInfo.value && address) { + const isValidToken = await validateDeBridgeToken({ + fromChainId: fromChain?.id, + tokenSymbol: selectedToken.symbol, + tokenAddress: selectedToken.address as `0x${string}`, + }); + if (!isValidToken) { + handleFailure({ + message: 'Invalid deBridge token!!', + fromChainId: fromChain?.id, + tokenSymbol: selectedToken.symbol, + tokenAddress: selectedToken.address as `0x${string}`, + }); + return; + } deBridgeHash = await bridgeSDK.deBridge.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, @@ -265,6 +301,23 @@ export function TransferButton({ handleFailure(e); } } else if (transferActionInfo.bridgeType === 'stargate' && address) { + const isValidToken = await validateStargateToken({ + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + if (!isValidToken) { + handleFailure({ + messages: 'Invalid Stargate token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + + return; + } const stargateHash = await bridgeSDK.stargate.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, @@ -318,6 +371,22 @@ export function TransferButton({ onOpenSubmittedModal(); } } else if (transferActionInfo.bridgeType === 'meson') { + const isValidToken = await validateMesonToken({ + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + if (!isValidToken) { + handleFailure({ + message: 'Invalid Meson token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + return; + } let fromAddress = ''; let toAddress = ''; let msg = ''; diff --git a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts new file mode 100644 index 00000000..4149adc5 --- /dev/null +++ b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useSendTokenValidation.ts @@ -0,0 +1,239 @@ +/* eslint-disable no-console */ +import axios from 'axios'; + +import { + CBRIDGE_ENDPOINT, + DEBRIDGE_ENDPOINT, + MESON_ENDPOINT, + STARGATE_ENDPOINT, +} from '@/core/constants'; +import { ICBridgeTransferConfig, IDeBridgeToken, IStargateTokenList } from '@/modules/aggregator'; +import { IMesonTokenList } from '@/modules/aggregator/adapters/meson/types'; +import { stargateChainKey } from '@/modules/aggregator/adapters/stargate/const'; + +interface ICBridgeTokenValidateParams { + isPegged: boolean; + tokenAddress: `0x${string}`; + bridgeAddress: `0x${string}`; + fromChainId?: number; + toChainId?: number; + tokenSymbol: string; +} + +// deBridge only needs to check token address +interface IDeBridgeTokenValidateParams { + tokenAddress: `0x${string}`; + tokenSymbol: string; + fromChainId?: number; +} + +interface IStargateTokenValidateParams { + tokenAddress: `0x${string}`; + bridgeAddress: `0x${string}`; + fromChainId?: number; + tokenSymbol: string; +} + +interface IMesonTokenValidateParams { + fromChainId?: number; + tokenSymbol: string; + tokenAddress: `0x${string}`; + bridgeAddress: `0x${string}`; +} + +export const useValidateSendToken = () => { + // cBridge + const validateCBridgeToken = async ({ + isPegged, + fromChainId, + toChainId, + tokenAddress, + bridgeAddress, + tokenSymbol, + }: ICBridgeTokenValidateParams) => { + try { + if (!fromChainId || !toChainId || !tokenAddress || !bridgeAddress || !tokenSymbol) { + return false; + } + const { data: cBridgeConfig } = await axios.get( + `${CBRIDGE_ENDPOINT}/getTransferConfigsForAll`, + ); + if (!cBridgeConfig) return false; + if (isPegged === true) { + // pegged token + const peggedToken = cBridgeConfig.pegged_pair_configs.filter((pair) => { + return ( + (pair.pegged_deposit_contract_addr === bridgeAddress && + pair?.org_chain_id === fromChainId && + pair?.org_token.token.address === tokenAddress && + pair?.org_token.token.symbol === tokenSymbol && + pair?.pegged_chain_id === toChainId) || + (pair?.pegged_chain_id === fromChainId && + pair.pegged_burn_contract_addr === bridgeAddress && + pair.pegged_token.token.address === tokenAddress && + pair.pegged_token.token.symbol === tokenSymbol && + pair?.org_chain_id === toChainId) + ); + }); + if (!!peggedToken && peggedToken.length > 0) { + console.log('cBridge pegged token info matched', peggedToken); + return true; + } + console.log('Can not find cBridge pegged info'); + console.log('-- isPegged', isPegged); + console.log('-- fromChainId', fromChainId); + console.log('-- tokenAddress', tokenAddress); + console.log('-- bridgeAddress', bridgeAddress); + return false; + } else { + // bridge address + const addressInfo = cBridgeConfig.chains.filter((chain) => { + return chain.id === fromChainId && chain.contract_addr === bridgeAddress; + }); + // token address + const tokenInfo = cBridgeConfig.chain_token[fromChainId].token.filter((t) => { + return ( + t.token.address.toLowerCase() === tokenAddress.toLowerCase() && + t.token.symbol === tokenSymbol + ); + }); + if (addressInfo?.length > 0 && tokenInfo?.length > 0) { + console.log('cBridge pool info matched', addressInfo, tokenInfo); + return true; + } else { + console.log('Can not find cBridge pool info'); + console.log('-- isPegged', isPegged); + console.log('-- fromChainId', fromChainId); + console.log('-- tokenAddress', tokenAddress); + console.log('-- bridgeAddress', bridgeAddress); + return false; + } + } + } catch (error) { + // eslint-disable-next-line no-console + console.log('cBridge token address validation error', error); + return false; + } + }; + + // deBridge + const validateDeBridgeToken = async ({ + fromChainId, + tokenSymbol, + tokenAddress, + }: IDeBridgeTokenValidateParams) => { + try { + if (!fromChainId || !tokenAddress || !tokenSymbol) return false; + const { data: deBridgeConfig } = await axios.get<{ + tokens: { [key: string]: IDeBridgeToken }; + }>(`${DEBRIDGE_ENDPOINT}/token-list?chainId=${fromChainId}`); + + if (!deBridgeConfig?.tokens) return false; + const tokenInfo = deBridgeConfig.tokens[tokenAddress.toLowerCase()]; + if (!!tokenInfo && tokenInfo?.address === tokenAddress && tokenInfo?.symbol === tokenSymbol) { + console.log('deBridge token info matched', tokenInfo); + return true; + } + console.log('Could not find deBridge token info'); + console.log('-- fromChainId', fromChainId); + console.log('-- tokenSymbol', tokenSymbol); + console.log('-- tokenAddress', tokenAddress); + return false; + } catch (error: any) { + // eslint-disable-next-line no-console + console.log('deBridge token validation error', error); + return false; + } + }; + + // Stargate + const validateStargateToken = async ({ + fromChainId, + tokenAddress, + bridgeAddress, + tokenSymbol, + }: IStargateTokenValidateParams) => { + try { + if (!fromChainId || !tokenAddress || !bridgeAddress || !tokenSymbol) return false; + const { data: stargateConfig } = await axios.get<{ data: IStargateTokenList }>( + `${STARGATE_ENDPOINT}`, + ); + + // Get chain name by chain id + const chainKey = stargateChainKey[fromChainId] ?? ''; + + if (!chainKey) return false; + if (!stargateConfig) return false; + + const tokenInfo = stargateConfig.data?.v2?.filter((token) => { + return ( + token.chainKey === chainKey && + token.address.toLowerCase() === bridgeAddress.toLowerCase() && + token.token.symbol === tokenSymbol && + token.token.address.toLowerCase() === tokenAddress.toLowerCase() + ); + }); + + console.log('tokenInfo', tokenInfo, stargateConfig.data?.v2); + if (!!tokenInfo && tokenInfo.length > 0) { + console.log('Stargate token info matched', tokenInfo); + return true; + } + console.log('Could not find Stargate token info'); + console.log('-- fromChainId', fromChainId); + console.log('-- tokenAddress', tokenAddress); + console.log('-- bridgeAddress', bridgeAddress); + console.log('-- tokenSymbol', tokenSymbol); + return false; + } catch (error: any) { + console.log('Stargate token validation error', error); + return false; + } + }; + + // Meson + const validateMesonToken = async ({ + fromChainId, + tokenSymbol, + bridgeAddress, + tokenAddress, + }: IMesonTokenValidateParams) => { + try { + if (!fromChainId || !tokenAddress || !tokenSymbol || !bridgeAddress) return false; + const { data: mesonConfig } = await axios.get<{ result: IMesonTokenList[] }>( + `${MESON_ENDPOINT}/limits`, + ); + + const hexNum = fromChainId?.toString(16); + const chainInfo = mesonConfig.result.filter((chainInfo) => { + const tokenInfo = chainInfo.tokens.filter( + (token) => token?.addr === tokenAddress && token.id === tokenSymbol.toLowerCase(), + ); + if (!!tokenInfo && tokenInfo.length > 0) { + console.log('Meson token info', tokenInfo); + } + return ( + chainInfo.chainId === `0x${hexNum}` && + chainInfo.address === bridgeAddress && + tokenInfo?.length > 0 && + !!tokenInfo + ); + }); + if (!!chainInfo && chainInfo.length > 0) { + console.log('Meson chain info matched', chainInfo); + return true; + } + console.log('Could not find Meson token'); + console.log('-- fromChainId', fromChainId); + console.log('-- bridgeAddress', bridgeAddress); + console.log('-- tokenAddress', tokenAddress); + console.log('-- tokenSymbol', tokenSymbol); + return false; + } catch (error: any) { + console.log('Meson token validation error', error); + return false; + } + }; + + return { validateCBridgeToken, validateDeBridgeToken, validateStargateToken, validateMesonToken }; +};