diff --git a/.release/.changeset/big-ligers-stare.md b/.release/.changeset/big-ligers-stare.md new file mode 100644 index 00000000..3de34771 --- /dev/null +++ b/.release/.changeset/big-ligers-stare.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Fix Cbridge send minmax multi call diff --git a/.release/.changeset/chilled-lizards-compare.md b/.release/.changeset/chilled-lizards-compare.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/chilled-lizards-compare.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/cyan-boxes-judge.md b/.release/.changeset/cyan-boxes-judge.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/cyan-boxes-judge.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/dirty-shoes-tap.md b/.release/.changeset/dirty-shoes-tap.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/dirty-shoes-tap.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/early-drinks-bathe.md b/.release/.changeset/early-drinks-bathe.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/early-drinks-bathe.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/fuzzy-houses-complain.md b/.release/.changeset/fuzzy-houses-complain.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/fuzzy-houses-complain.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/khaki-bears-rhyme.md b/.release/.changeset/khaki-bears-rhyme.md new file mode 100644 index 00000000..c3960b3b --- /dev/null +++ b/.release/.changeset/khaki-bears-rhyme.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Fix switch to ethereum token diff --git a/.release/.changeset/long-ears-press.md b/.release/.changeset/long-ears-press.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/long-ears-press.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/metal-steaks-drive.md b/.release/.changeset/metal-steaks-drive.md new file mode 100644 index 00000000..9fe5c3aa --- /dev/null +++ b/.release/.changeset/metal-steaks-drive.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Fix input and checkbox style diff --git a/.release/.changeset/nasty-candles-marry.md b/.release/.changeset/nasty-candles-marry.md new file mode 100644 index 00000000..b9260687 --- /dev/null +++ b/.release/.changeset/nasty-candles-marry.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget diff --git a/.release/.changeset/nice-boxes-taste.md b/.release/.changeset/nice-boxes-taste.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/nice-boxes-taste.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/ninety-buckets-cough.md b/.release/.changeset/ninety-buckets-cough.md new file mode 100644 index 00000000..c2ed9d6e --- /dev/null +++ b/.release/.changeset/ninety-buckets-cough.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Fix svg icon mask duplicate id diff --git a/.release/.changeset/polite-monkeys-share.md b/.release/.changeset/polite-monkeys-share.md new file mode 100644 index 00000000..65875796 --- /dev/null +++ b/.release/.changeset/polite-monkeys-share.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update unknown network title diff --git a/.release/.changeset/pre.json b/.release/.changeset/pre.json new file mode 100644 index 00000000..e7298e20 --- /dev/null +++ b/.release/.changeset/pre.json @@ -0,0 +1,38 @@ +{ + "mode": "pre", + "tag": "alpha", + "initialVersions": { + "@bnb-chain/canonical-bridge-sdk": "0.1.2", + "@bnb-chain/canonical-bridge-widget": "0.1.4" + }, + "changesets": [ + "big-ligers-stare", + "chilled-lizards-compare", + "cyan-boxes-judge", + "dirty-shoes-tap", + "early-drinks-bathe", + "fuzzy-houses-complain", + "khaki-bears-rhyme", + "long-ears-press", + "metal-steaks-drive", + "nasty-candles-marry", + "nice-boxes-taste", + "ninety-buckets-cough", + "polite-monkeys-share", + "rare-grapes-act", + "rotten-nails-drop", + "rude-tools-give", + "shy-lemons-grab", + "silly-lions-clap", + "six-turtles-prove", + "sixty-scissors-protect", + "slimy-clocks-rule", + "spotty-trainers-kick", + "swift-dolls-yawn", + "swift-rivers-accept", + "swift-suits-worry", + "tasty-pianos-raise", + "thin-snakes-cheat", + "tough-colts-compare" + ] +} diff --git a/.release/.changeset/rare-grapes-act.md b/.release/.changeset/rare-grapes-act.md new file mode 100644 index 00000000..ad2eb2a0 --- /dev/null +++ b/.release/.changeset/rare-grapes-act.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Some ui updates & Header chain switch update diff --git a/.release/.changeset/rotten-nails-drop.md b/.release/.changeset/rotten-nails-drop.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/rotten-nails-drop.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/rude-tools-give.md b/.release/.changeset/rude-tools-give.md new file mode 100644 index 00000000..c5a648be --- /dev/null +++ b/.release/.changeset/rude-tools-give.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Resolve multi loadingFee requst diff --git a/.release/.changeset/shy-lemons-grab.md b/.release/.changeset/shy-lemons-grab.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/shy-lemons-grab.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/silly-lions-clap.md b/.release/.changeset/silly-lions-clap.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/silly-lions-clap.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/six-turtles-prove.md b/.release/.changeset/six-turtles-prove.md new file mode 100644 index 00000000..3d749878 --- /dev/null +++ b/.release/.changeset/six-turtles-prove.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update icon element id diff --git a/.release/.changeset/sixty-scissors-protect.md b/.release/.changeset/sixty-scissors-protect.md new file mode 100644 index 00000000..d809e188 --- /dev/null +++ b/.release/.changeset/sixty-scissors-protect.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update ui diff --git a/.release/.changeset/slimy-clocks-rule.md b/.release/.changeset/slimy-clocks-rule.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/slimy-clocks-rule.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/spotty-trainers-kick.md b/.release/.changeset/spotty-trainers-kick.md new file mode 100644 index 00000000..5bf157e0 --- /dev/null +++ b/.release/.changeset/spotty-trainers-kick.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widge ui diff --git a/.release/.changeset/swift-dolls-yawn.md b/.release/.changeset/swift-dolls-yawn.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/swift-dolls-yawn.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/swift-rivers-accept.md b/.release/.changeset/swift-rivers-accept.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/swift-rivers-accept.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/swift-suits-worry.md b/.release/.changeset/swift-suits-worry.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/swift-suits-worry.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/tasty-pianos-raise.md b/.release/.changeset/tasty-pianos-raise.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/tasty-pianos-raise.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/thin-snakes-cheat.md b/.release/.changeset/thin-snakes-cheat.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/thin-snakes-cheat.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/.release/.changeset/tough-colts-compare.md b/.release/.changeset/tough-colts-compare.md new file mode 100644 index 00000000..f14199cb --- /dev/null +++ b/.release/.changeset/tough-colts-compare.md @@ -0,0 +1,5 @@ +--- +"@bnb-chain/canonical-bridge-widget": patch +--- + +Update widget ui diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index d992b5b8..07d93356 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -7444,7 +7444,7 @@ packages: resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} engines: {node: '>= 4.0'} os: [darwin] - deprecated: Upgrade to fsevents v2 to mitigate potential security issues + deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} diff --git a/packages/canonical-bridge-widget/CHANGELOG.md b/packages/canonical-bridge-widget/CHANGELOG.md index d67955a7..63bf16e3 100644 --- a/packages/canonical-bridge-widget/CHANGELOG.md +++ b/packages/canonical-bridge-widget/CHANGELOG.md @@ -1,5 +1,161 @@ # @bnb-chain/canonical-bridge-widget +## 0.3.2-alpha.25 + +### Patch Changes + +- Update icon element id + +## 0.3.2-alpha.24 + +### Patch Changes + +- Fix svg icon mask duplicate id + +## 0.3.2-alpha.23 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.22 + +### Patch Changes + +- Fix Cbridge send minmax multi call + +## 0.3.2-alpha.21 + +### Patch Changes + +- Resolve multi loadingFee requst + +## 0.3.2-alpha.20 + +### Patch Changes + +- Fix switch to ethereum token + +## 0.3.2-alpha.19 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.18 + +### Patch Changes + +- Update widget + +## 0.3.2-alpha.17 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.16 + +### Patch Changes + +- Update widge ui + +## 0.3.2-alpha.15 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.14 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.13 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.12 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.11 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.10 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.9 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.8 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.7 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.6 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.5 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.4 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.3 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.2 + +### Patch Changes + +- Update widget ui + +## 0.3.2-alpha.1 + +### Patch Changes + +- Fix input and checkbox style + +## 0.3.2-alpha.0 + +### Patch Changes + +- Update ui + ## 0.3.1 ### Patch Changes diff --git a/packages/canonical-bridge-widget/package.json b/packages/canonical-bridge-widget/package.json index f16871a6..d4ae2bd9 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.3.1", + "version": "0.3.2-alpha.25", "description": "canonical bridge widget", "author": "bnb-chain", "private": false, diff --git a/packages/canonical-bridge-widget/src/core/components/InfoTooltip/index.tsx b/packages/canonical-bridge-widget/src/core/components/InfoTooltip/index.tsx index fc20b9e2..8dd5a9c8 100644 --- a/packages/canonical-bridge-widget/src/core/components/InfoTooltip/index.tsx +++ b/packages/canonical-bridge-widget/src/core/components/InfoTooltip/index.tsx @@ -17,6 +17,7 @@ export const InfoTooltip = (props: InfoTooltipProps) => { const isBase = useBreakpointValue({ base: true, md: false }) ?? false; const { isOpen, onOpen, onToggle, onClose } = useDisclosure(); + if (!restProps.label) return null; return ( - + @@ -14,7 +17,7 @@ export function AvatarIcon(props: IconProps) { - + diff --git a/packages/canonical-bridge-widget/src/core/components/icons/ConfirmCheckIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/ConfirmCheckIcon.tsx new file mode 100644 index 00000000..83260879 --- /dev/null +++ b/packages/canonical-bridge-widget/src/core/components/icons/ConfirmCheckIcon.tsx @@ -0,0 +1,45 @@ +import { Box, Icon, IconProps, useColorMode, useTheme } from '@bnb-chain/space'; + +export const UncheckedIcon = (props: IconProps) => { + return ( + + + + ); +}; + +export const CheckedIcon = (props: IconProps) => { + return ( + + + + ); +}; + +export const ToAccountCheckBox = (props: { onClick: () => void; isChecked: boolean }) => { + const { onClick, isChecked } = props; + const theme = useTheme(); + const { colorMode } = useColorMode(); + + return ( + + {isChecked ? ( + + ) : ( + + )} + + ); +}; diff --git a/packages/canonical-bridge-widget/src/core/components/icons/ExLinkIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/ExLinkIcon.tsx index 9b25aee0..c34a1f3c 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/ExLinkIcon.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/ExLinkIcon.tsx @@ -10,23 +10,10 @@ export function ExLinkIcon(props: IconProps) { fill="none" {...props} > - - - - - - + ); } diff --git a/packages/canonical-bridge-widget/src/core/components/icons/ExchangeChainIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/ExchangeChainIcon.tsx index bf60fea6..cb6c82b2 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/ExchangeChainIcon.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/ExchangeChainIcon.tsx @@ -1,6 +1,9 @@ import { Icon, IconProps } from '@bnb-chain/space'; +import { useState } from 'react'; export function ExchangeChainIcon(props: IconProps) { + const [id1] = useState('mask0_2001_23666_exchangeIcon_' + Date.now()); + return ( - + { + const [id1] = useState('mask0_26135_32299_expand_details_' + Date.now()); + return ( { {...props} > { > - + { + const [id1] = useState('mask0_27981_20506_' + Date.now()); + return ( { {...props} > { > - + - + - + - + - + - + - + diff --git a/packages/canonical-bridge-widget/src/core/components/icons/NoResultIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/NoResultIcon.tsx index a9c01119..48fe2658 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/NoResultIcon.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/NoResultIcon.tsx @@ -1,14 +1,18 @@ import { Icon, IconProps } from '@bnb-chain/space'; +import { useState } from 'react'; export function NoResultIcon(props: IconProps) { + const [id1] = useState('mask0_26136_34623_' + Date.now()); + const [id2] = useState('clip0_26136_34623_' + Date.now()); + return ( - + - + - + - + diff --git a/packages/canonical-bridge-widget/src/core/components/icons/RouteNotFoundIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/RouteNotFoundIcon.tsx index 7ba747ea..91a48aef 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/RouteNotFoundIcon.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/RouteNotFoundIcon.tsx @@ -1,6 +1,10 @@ import { Icon, IconProps } from '@bnb-chain/space'; +import { useState } from 'react'; export const RouteNotFoundIcon = (props: IconProps) => { + const [id1] = useState('mask0_26136_34658_no_route_found_' + Date.now()); + const [id2] = useState('clip0_26136_34658_' + Date.now()); + return ( { xmlns="http://www.w3.org/2000/svg" {...props} > - + { > - + { - + diff --git a/packages/canonical-bridge-widget/src/core/components/icons/TransferToIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/TransferToIcon.tsx index c95e834c..96259aca 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/TransferToIcon.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/TransferToIcon.tsx @@ -1,6 +1,9 @@ import { Icon, IconProps } from '@bnb-chain/space'; +import { useState } from 'react'; export function TransferToIcon(props: IconProps) { + const [id1] = useState('paint0_linear_2473_21184_' + Date.now()); + return ( - + - + diff --git a/packages/canonical-bridge-widget/src/core/components/icons/WarningIcon.tsx b/packages/canonical-bridge-widget/src/core/components/icons/WarningIcon.tsx new file mode 100644 index 00000000..994a1df5 --- /dev/null +++ b/packages/canonical-bridge-widget/src/core/components/icons/WarningIcon.tsx @@ -0,0 +1,15 @@ +import { Icon, IconProps } from '@bnb-chain/space'; + +export function WarningIcon(props: IconProps) { + return ( + + + + + + ); +} diff --git a/packages/canonical-bridge-widget/src/core/components/icons/brand/CBridgeLogo.tsx b/packages/canonical-bridge-widget/src/core/components/icons/brand/CBridgeLogo.tsx index f1b083bc..533ca4b7 100644 --- a/packages/canonical-bridge-widget/src/core/components/icons/brand/CBridgeLogo.tsx +++ b/packages/canonical-bridge-widget/src/core/components/icons/brand/CBridgeLogo.tsx @@ -1,6 +1,10 @@ import { Icon, IconProps } from '@bnb-chain/space'; +import { useState } from 'react'; export function CBridgeIcon(props: IconProps) { + const [id1] = useState('mask0_1455_365_' + Date.now()); + const [id2] = useState('mask1_1455_365_' + Date.now()); + return ( - + - + - - + + - + - + diff --git a/packages/canonical-bridge-widget/src/core/hooks/useDebounce.ts b/packages/canonical-bridge-widget/src/core/hooks/useDebounce.ts index f57dec06..1bb9dcca 100644 --- a/packages/canonical-bridge-widget/src/core/hooks/useDebounce.ts +++ b/packages/canonical-bridge-widget/src/core/hooks/useDebounce.ts @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; export const useDebounce = (value: any, delay = 500) => { - const [debouncedValue, setDebouncedValue] = useState(''); + const [debouncedValue, setDebouncedValue] = useState(value); const timerRef = useRef(); useEffect(() => { diff --git a/packages/canonical-bridge-widget/src/core/locales/en.ts b/packages/canonical-bridge-widget/src/core/locales/en.ts index d5d4b72d..3fc37b62 100644 --- a/packages/canonical-bridge-widget/src/core/locales/en.ts +++ b/packages/canonical-bridge-widget/src/core/locales/en.ts @@ -57,7 +57,7 @@ export const en = { 'transfer.button.confirm': 'Send', 'transfer.button.approve': 'Approve', - 'transfer.button.switch-network': 'Switch Network', + 'transfer.button.switch-network': 'Switch Network in Wallet', 'transfer.button.wallet-connect': 'Connect Wallet', 'transfer.button.switch-wallet': 'Switch Wallet', @@ -96,6 +96,9 @@ export const en = { 'select-modal.destination.incompatible.tooltip': 'The token you’ve selected is incompatible with this network. Please select another token.', + 'wallet.network.switch-network': 'Please switch the network', + 'wallet.network.unknown-network': 'Unsupported Network', + 'wallet.network.unknown-network-mobile': 'Network', 'wallet.button.connect-wallet': 'Connect Wallet', 'wallet.network.wrong-network': 'Wrong network', 'wallet.error.switch-network': diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/action.ts b/packages/canonical-bridge-widget/src/modules/aggregator/action.ts index ecc15d0d..42698636 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/action.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/action.ts @@ -16,3 +16,7 @@ export const setIsLoadingTokenPrices = createAction( 'aggregator/setIsLoadingTokenBalances', ); + +export const setCBridgeMaxMinSendAmt = createAction( + 'aggregator/setCBridgeMaxMinSendAmt', +); diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeOption.tsx b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeOption.tsx index ae851bfd..05755e7b 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeOption.tsx +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeOption.tsx @@ -54,7 +54,7 @@ export const CBridgeOption = () => { }), ); } - }, [dispatch, estimatedAmount]); + }, [dispatch, estimatedAmount?.['cBridge']?.estimated_receive_amt]); const isError = useMemo( () => diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeSendMaxMin.tsx b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeSendMaxMin.tsx new file mode 100644 index 00000000..ab401fe9 --- /dev/null +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/components/CBridgeSendMaxMin.tsx @@ -0,0 +1,71 @@ +import { memo, useEffect } from 'react'; +import { usePublicClient } from 'wagmi'; +import { formatUnits } from 'viem'; + +import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; +import { setCBridgeMaxMinSendAmt } from '@/modules/aggregator/action'; +import { useCBridgeTransferParams } from '@/modules/aggregator/adapters/cBridge/hooks/useCBridgeTransferParams.ts'; +import { useBridgeSDK } from '@/core/hooks/useBridgeSDK.ts'; + +interface CBridgeSendMaxMinProps { + isDisabled?: boolean; +} + +export const CBridgeSendMaxMin = memo(function CBridgeSendMaxMin({ + isDisabled = false, +}) { + const { bridgeAddress } = useCBridgeTransferParams(); + const bridgeSDK = useBridgeSDK(); + const fromChain = useAppSelector((state) => state.transfer.fromChain); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const publicClient = usePublicClient({ chainId: fromChain?.id }) as any; + const selectedToken = useAppSelector((state) => state.transfer.selectedToken); + const dispatch = useAppDispatch(); + + useEffect(() => { + (async () => { + try { + if ( + selectedToken?.isPegged || + !publicClient || + !bridgeAddress || + !selectedToken?.address || + isDisabled || + !bridgeSDK?.cBridge + ) { + dispatch(setCBridgeMaxMinSendAmt({ min: '0', max: '0' })); + return; + } + + const { min, max } = await bridgeSDK.cBridge.getSendRange({ + bridgeAddress: bridgeAddress as `0x${string}`, + tokenAddress: selectedToken?.address as `0x${string}`, + client: publicClient, + }); + + dispatch( + setCBridgeMaxMinSendAmt({ + min: formatUnits(min, selectedToken?.decimals), + max: formatUnits(max, selectedToken?.decimals), + }), + ); + + // eslint-disable-next-line + } catch (error: any) { + // eslint-disable-next-line no-console + console.log('error', error); + } + })(); + }, [ + dispatch, + selectedToken?.address, + selectedToken?.isPegged, + selectedToken?.decimals, + publicClient, + bridgeAddress, + isDisabled, + bridgeSDK?.cBridge, + ]); + + return null; +}); diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin.ts index 1de1b9af..5439381a 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin.ts @@ -18,6 +18,7 @@ export const useCBridgeSendMaxMin = (isDisabled = false) => { min: '0', max: '0', }); + useEffect(() => { (async () => { try { @@ -29,8 +30,9 @@ export const useCBridgeSendMaxMin = (isDisabled = false) => { isDisabled || !bridgeSDK?.cBridge ) { - return; + return setMinMaxSendAmt({ min: '0', max: '0' }); } + const { min, max } = await bridgeSDK.cBridge.getSendRange({ bridgeAddress: bridgeAddress as `0x${string}`, tokenAddress: selectedToken?.address as `0x${string}`, @@ -47,7 +49,15 @@ export const useCBridgeSendMaxMin = (isDisabled = false) => { console.log('error', error); } })(); - }, [selectedToken, publicClient, bridgeAddress, isDisabled, bridgeSDK?.cBridge]); + }, [ + selectedToken?.address, + selectedToken?.isPegged, + selectedToken?.decimals, + publicClient, + bridgeAddress, + isDisabled, + bridgeSDK?.cBridge, + ]); return { minMaxSendAmt, diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useGetCBridgeFees.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useGetCBridgeFees.ts index 0b48a990..fb4a9981 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useGetCBridgeFees.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/cBridge/hooks/useGetCBridgeFees.ts @@ -1,11 +1,10 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useMemo } from 'react'; import { formatUnits, parseUnits } from 'viem'; import { useAccount, usePublicClient } from 'wagmi'; import { useIntl } from '@bnb-chain/space'; import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; import { useToTokenInfo } from '@/modules/transfer/hooks/useToTokenInfo'; -import { useCBridgeSendMaxMin } from '@/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin'; import { useCBridgeTransferParams } from '@/modules/aggregator/adapters/cBridge/hooks/useCBridgeTransferParams'; import { useGetTokenBalance } from '@/core/contract/hooks/useGetTokenBalance'; import { formatNumber } from '@/core/utils/number'; @@ -17,7 +16,7 @@ import { ERC20_TOKEN } from '@/core/contract/abi'; export const useGetCBridgeFees = () => { const { toTokenInfo } = useToTokenInfo(); const { args, bridgeAddress } = useCBridgeTransferParams(); - const { minMaxSendAmt: cBridgeAllowedAmt } = useCBridgeSendMaxMin(); + const cBridgeAllowedAmt = useAppSelector((state) => state.aggregator.bridgeMaxMin.cBridge); const nativeToken = useGetNativeToken(); const { formatMessage } = useIntl(); const dispatch = useAppDispatch(); @@ -29,27 +28,24 @@ export const useGetCBridgeFees = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const publicClient = usePublicClient({ chainId: fromChain?.id }) as any; - const [isAllowSendError, setIsAllowSendError] = useState(false); const { balance } = useGetTokenBalance({ tokenAddress: selectedToken?.address as `0x${string}`, }); - useEffect(() => { + const isAllowSendError = useMemo(() => { if (!Number(sendValue) || !selectedToken || !toTokenInfo) { - setIsAllowSendError(false); - return; + return false; } if (!!Number(cBridgeAllowedAmt?.min) && !!Number(cBridgeAllowedAmt?.max)) { - if (Number(sendValue) <= Number(cBridgeAllowedAmt.min)) { - setIsAllowSendError(true); - } else if (Number(sendValue) >= Number(cBridgeAllowedAmt.max)) { - setIsAllowSendError(true); + if ( + Number(sendValue) <= Number(cBridgeAllowedAmt.min) || + Number(sendValue) >= Number(cBridgeAllowedAmt.max) + ) { + return true; } } - return () => { - setIsAllowSendError(false); - }; + return false; }, [cBridgeAllowedAmt, sendValue, selectedToken, toTokenInfo]); const cBridgeFeeSorting = useCallback( diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/hooks/useGetStarGateFees.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/hooks/useGetStarGateFees.ts index 425aa7ce..f8d5ad9f 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/hooks/useGetStarGateFees.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/hooks/useGetStarGateFees.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useMemo } from 'react'; import { useAccount, useBalance, usePublicClient } from 'wagmi'; import { formatUnits, parseUnits } from 'viem'; import { useIntl } from '@bnb-chain/space'; @@ -32,35 +32,34 @@ export const useGetStargateFees = () => { const publicClient = usePublicClient({ chainId: fromChain?.id }) as any; const sendValue = useAppSelector((state) => state.transfer.sendValue); const estimatedAmount = useAppSelector((state) => state.transfer.estimatedAmount); - const [allowedSendAmount, setAllowedSendAmount] = useState<{ min: string; max: string } | null>( - null, - ); - const [isAllowSendError, setIsAllowSendError] = useState(false); const { balance } = useGetTokenBalance({ tokenAddress: selectedToken?.address as `0x${string}`, }); - useEffect(() => { + const allowedSendAmount = useMemo(() => { if (estimatedAmount?.stargate && estimatedAmount?.stargate?.[0]) { const fees = estimatedAmount?.stargate; const decimal = selectedToken?.stargate?.raw?.decimals ?? (18 as number); const allowedMin = Number(formatUnits(fees[0].minAmountLD, decimal)); const allowedMax = Number(formatUnits(fees[0].maxAmountLD, decimal)); - setAllowedSendAmount({ + return { min: formatNumber(allowedMin, 8), max: formatNumber(allowedMax, 8), - }); - if (Number(sendValue) < allowedMin || Number(sendValue) > allowedMax) { - setIsAllowSendError(true); - } else { - setIsAllowSendError(false); - } + }; + } + return null; + }, [estimatedAmount?.stargate, selectedToken?.stargate?.raw?.decimals]); + + const isAllowSendError = useMemo(() => { + if (estimatedAmount?.stargate && estimatedAmount?.stargate?.[0]) { + const fees = estimatedAmount?.stargate; + const decimal = selectedToken?.stargate?.raw?.decimals ?? (18 as number); + const allowedMin = Number(formatUnits(fees[0].minAmountLD, decimal)); + const allowedMax = Number(formatUnits(fees[0].maxAmountLD, decimal)); + return Number(sendValue) < allowedMin || Number(sendValue) > allowedMax; } - return () => { - setAllowedSendAmount(null); - setIsAllowSendError(false); - }; + return false; }, [estimatedAmount?.stargate, selectedToken?.stargate?.raw?.decimals, sendValue]); const stargateFeeSorting = useCallback( diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useDefaultSelectedInfo.ts b/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useDefaultSelectedInfo.ts index 4199d278..c61e0942 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useDefaultSelectedInfo.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useDefaultSelectedInfo.ts @@ -1,20 +1,23 @@ import { useEffect } from 'react'; -import { useAppDispatch } from '@/modules/store/StoreProvider'; +import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; import { setSendValue } from '@/modules/transfer/action'; import { useSelection } from '@/modules/aggregator/hooks/useSelection'; import { useAggregator } from '@/modules/aggregator/components/AggregatorProvider'; +import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider.tsx'; export function useDefaultSelectedInfo() { const { isReady, defaultSelectedInfo } = useAggregator(); const { selectDefault } = useSelection(); const dispatch = useAppDispatch(); + const { chainId } = useCurrentWallet(); + const sendValue = useAppSelector((state) => state.transfer.sendValue); useEffect(() => { if (isReady) { selectDefault(defaultSelectedInfo); - dispatch(setSendValue(defaultSelectedInfo.amount)); + dispatch(setSendValue(sendValue || defaultSelectedInfo.amount)); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isReady]); + }, [isReady, chainId]); } diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useSelection.ts b/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useSelection.ts index f3aadaa4..73e2e88c 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useSelection.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/hooks/useSelection.ts @@ -18,6 +18,7 @@ import { useTronWeb } from '@/core/hooks/useTronWeb'; import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider'; export function useSelection() { + const { chainId } = useCurrentWallet(); const { getFromChains, getToChains, getTokens, getToToken, adapters } = useAggregator(); const fromChain = useAppSelector((state) => state.transfer.fromChain); @@ -79,6 +80,38 @@ export function useSelection() { }); }; + const selectFromChain = async (tmpFromChain: IBridgeChain) => { + // After selecting fromChain, if toChain becomes incompatible, reselect the first compatible network in toChain list. + const toChains = getToChains({ + fromChainId: tmpFromChain.id, + }); + const tmpToChain = + toChains.find((c) => isChainOrTokenCompatible(c) && c.id === toChain?.id) ?? + toChains.find((c) => isChainOrTokenCompatible(c) && c.chainType !== 'link'); + + const tmpTokens = await getSortedTokens({ + chainType: tmpFromChain.chainType, + fromChainId: tmpFromChain.id, + tokens: getTokens({ + fromChainId: tmpFromChain.id, + toChainId: tmpToChain?.id, + }), + }); + + const newToken = + tmpTokens.find( + (t) => + isChainOrTokenCompatible(t) && + t.displaySymbol.toUpperCase() === selectedToken?.displaySymbol.toUpperCase(), + ) ?? tmpTokens.find((t) => isChainOrTokenCompatible(t)); + + updateSelectedInfo({ + tmpToken: newToken, + tmpFromChain, + tmpToChain, + }); + }; + return { async selectDefault({ fromChainId, @@ -94,6 +127,16 @@ export function useSelection() { bridgeTypes.map((item) => [item, { symbol: tokenSymbol }]), ) as any as IBridgeToken; + if (chainId) { + const fromChains = getFromChains({}); + const chain = fromChains.find((chain) => chain.id === chainId); + if (chain) { + selectFromChain(chain); + return; + } + if (fromChain?.id) return; + } + const fromChains = getFromChains({ toChainId, token, @@ -123,44 +166,11 @@ export function useSelection() { token: newToken, }); }, - - async selectFromChain(tmpFromChain: IBridgeChain) { - // After selecting fromChain, if toChain becomes incompatible, reselect the first compatible network in toChain list. - const toChains = getToChains({ - fromChainId: tmpFromChain.id, - }); - const tmpToChain = - toChains.find((c) => isChainOrTokenCompatible(c) && c.id === toChain?.id) ?? - toChains.find((c) => isChainOrTokenCompatible(c) && c.chainType !== 'link'); - - const tmpTokens = await getSortedTokens({ - chainType: tmpFromChain.chainType, - fromChainId: tmpFromChain.id, - tokens: getTokens({ - fromChainId: tmpFromChain.id, - toChainId: tmpToChain?.id, - }), - }); - - const newToken = - tmpTokens.find( - (t) => - isChainOrTokenCompatible(t) && - t.displaySymbol.toUpperCase() === selectedToken?.displaySymbol.toUpperCase(), - ) ?? tmpTokens.find((t) => isChainOrTokenCompatible(t)); - - updateSelectedInfo({ - tmpToken: newToken, - tmpFromChain, - tmpToChain, - }); - }, - + selectFromChain, async selectToChain(tmpToChain: IBridgeChain) { const fromChainId = fromChain!.id; const tmpTokens = await getSortedTokens({ - chainType: fromChain?.chainType, fromChainId, tokens: getTokens({ fromChainId, diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/reducer.ts b/packages/canonical-bridge-widget/src/modules/aggregator/reducer.ts index d9be0382..b267d1ea 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/reducer.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/reducer.ts @@ -1,5 +1,6 @@ import { createReducer } from '@/modules/store/createReducer'; import * as actions from '@/modules/aggregator/action'; +import { ICBridgeMaxMinSendAmt } from '@/modules/aggregator/adapters/cBridge/types'; export interface IAggregatorState { tokenPrices: { cmcPrices: Record; @@ -8,6 +9,9 @@ export interface IAggregatorState { tokenBalances: Record; isLoadingTokenPrices: boolean; isLoadingTokenBalances: boolean; + bridgeMaxMin: { + cBridge: ICBridgeMaxMinSendAmt; + }; } const initStates: IAggregatorState = { @@ -18,6 +22,9 @@ const initStates: IAggregatorState = { tokenBalances: {}, isLoadingTokenPrices: false, isLoadingTokenBalances: false, + bridgeMaxMin: { + cBridge: { max: '0', min: '0' }, + }, }; export default createReducer(initStates, (builder) => { @@ -43,4 +50,12 @@ export default createReducer(initStates, (builder) => { ...state, isLoadingTokenBalances: payload, })); + + builder.addCase(actions.setCBridgeMaxMinSendAmt, (state, { payload }) => ({ + ...state, + bridgeMaxMin: { + ...state.bridgeMaxMin, + cBridge: payload, + }, + })); }); diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchNetworkButton.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchNetworkButton.tsx index 258ccfb5..970ae716 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchNetworkButton.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchNetworkButton.tsx @@ -1,10 +1,10 @@ -import { Button, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; +import { Button, useColorMode, useIntl, useTheme, ButtonProps } from '@bnb-chain/space'; import { useAppSelector } from '@/modules/store/StoreProvider'; import { reportEvent } from '@/core/utils/gtm'; import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider'; -export const SwitchNetworkButton = () => { +export const SwitchNetworkButton = (props: ButtonProps) => { const { formatMessage } = useIntl(); const fromChain = useAppSelector((state) => state.transfer.fromChain); @@ -36,6 +36,7 @@ export const SwitchNetworkButton = () => { }, }); }} + {...props} > {formatMessage({ id: 'transfer.button.switch-network' })} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchWalletButton.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchWalletButton.tsx index bf7ab95b..f19ba1a3 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchWalletButton.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/SwitchWalletButton.tsx @@ -1,10 +1,10 @@ -import { Button, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; +import { Button, ButtonProps, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; import { reportEvent } from '@/core/utils/gtm'; import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider'; import { useAppSelector } from '@/modules/store/StoreProvider'; -export const SwitchWalletButton = () => { +export const SwitchWalletButton = (props: ButtonProps) => { const { formatMessage } = useIntl(); const { linkWallet } = useCurrentWallet(); @@ -36,6 +36,7 @@ export const SwitchWalletButton = () => { }, }); }} + {...props} > {formatMessage({ id: 'transfer.button.switch-wallet' })} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/WalletButtonWrapper.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/WalletButtonWrapper.tsx index a231a1d2..56e585fd 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/WalletButtonWrapper.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/WalletButtonWrapper.tsx @@ -1,22 +1,43 @@ -import { PropsWithChildren } from 'react'; +import { PropsWithChildren, useEffect, useMemo, useState } from 'react'; import { useAppSelector } from '@/modules/store/StoreProvider'; import { WalletConnectButton } from '@/modules/transfer/components/Button/WalletConnectButton'; import { SwitchNetworkButton } from '@/modules/transfer/components/Button/SwitchNetworkButton'; import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider'; import { SwitchWalletButton } from '@/modules/transfer/components/Button/SwitchWalletButton'; +import { useDebounce } from '@/core/hooks/useDebounce'; export function WalletButtonWrapper(props: PropsWithChildren) { const { children } = props; const fromChain = useAppSelector((state) => state.transfer.fromChain); const { isConnected, chainId, walletType } = useCurrentWallet(); + const [delay, setDelay] = useState(false); - if (isConnected) { - if (walletType !== fromChain?.chainType) { + useEffect(() => { + setTimeout(() => setDelay(true), 3000); + }, []); + + const payload = useMemo(() => { + return { + _chainId: chainId, + _fromChainId: fromChain?.id, + _isConnected: isConnected, + _walletType: walletType, + _fromChainType: fromChain?.chainType, + }; + }, [chainId, fromChain?.id, isConnected, walletType, fromChain?.chainType]); + + const { _chainId, _fromChainId, _isConnected, _walletType, _fromChainType } = useDebounce( + payload, + delay ? 1200 : 0, + ); + + if (_isConnected) { + if (_walletType !== _fromChainType && _fromChainType) { return ; } else { - if (chainId !== fromChain.id) { + if (_chainId !== _fromChainId && _fromChainId) { return ; } return <>{children}; diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/FromSection/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/FromSection/index.tsx index c80b11ec..3f143046 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/FromSection/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/FromSection/index.tsx @@ -1,12 +1,4 @@ -import { - Flex, - Typography, - useBreakpointValue, - useColorMode, - useDisclosure, - useIntl, - useTheme, -} from '@bnb-chain/space'; +import { Flex, Typography, useColorMode, useDisclosure, useIntl, useTheme } from '@bnb-chain/space'; import { SelectButton } from '@/modules/transfer/components/SelectButton'; import { useAppSelector } from '@/modules/store/StoreProvider'; @@ -16,7 +8,6 @@ import { SourceNetworkModal } from '@/modules/aggregator/components/SelectModal/ export function FromSection() { const { colorMode } = useColorMode(); const { isOpen, onClose, onOpen } = useDisclosure(); - const isBase = useBreakpointValue({ base: true, md: false }) ?? false; const { formatMessage } = useIntl(); const fromChain = useAppSelector((state) => state.transfer.fromChain); @@ -24,18 +15,20 @@ export function FromSection() { return ( - {isBase ? ( - - - {formatMessage({ id: 'from.section.title' })} - - - ) : null} + + + {formatMessage({ id: 'from.section.title' })} + + { const { formatMessage } = useIntl(); const { colorMode } = useColorMode(); const theme = useTheme(); - const isBase = useBreakpointValue({ base: true, md: false }) ?? false; return ( - {!isBase ? ( - <> - - - - {formatMessage({ id: 'from.section.title' })} - - - - - {formatMessage({ id: 'to.section.title' })} - - - {' '} - - ) : null} + + + + {formatMessage({ id: 'from.section.title' })} + + + + + {formatMessage({ id: 'to.section.title' })} + + + {' '} - + diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/ReceiveLoading.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/ReceiveLoading.tsx index f34820c6..3b2473f1 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/ReceiveLoading.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/ReceiveLoading.tsx @@ -1,41 +1,45 @@ -import { Flex, Skeleton, SkeletonCircle, useBreakpointValue } from '@bnb-chain/space'; +import { Flex, Skeleton, SkeletonCircle } from '@bnb-chain/space'; export const ReceiveLoading = () => { - const isBase = useBreakpointValue({ base: true, lg: false }) ?? false; - - return !isBase ? ( - - - - - - - - - ) : ( - - - - - - - - - + return ( + <> + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + - - - + ); }; diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/index.tsx index 11ff1cf3..a7249e30 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/ReceiveInfo/index.tsx @@ -1,4 +1,12 @@ -import { Box, Flex, useBreakpointValue, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; +import { + Box, + Flex, + useColorMode, + useIntl, + useTheme, + Collapse, + useBreakpointValue, +} from '@bnb-chain/space'; import { useEffect, useMemo } from 'react'; import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; @@ -38,7 +46,6 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { const { formatMessage } = useIntl(); const { loadingBridgeFees } = useLoadingBridgeFees(); const dispatch = useAppDispatch(); - const isBase = useBreakpointValue({ base: true, lg: false }) ?? false; const transferActionInfo = useAppSelector((state) => state.transfer.transferActionInfo); const isGlobalFeeLoading = useAppSelector((state) => state.transfer.isGlobalFeeLoading); @@ -46,6 +53,7 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { const selectedToken = useAppSelector((state) => state.transfer.selectedToken); const routeFees = useAppSelector((state) => state.transfer.routeFees); const estimatedAmount = useAppSelector((state) => state.transfer.estimatedAmount); + const isBase = useBreakpointValue({ base: true, lg: false }) ?? false; const receiveAmt = useMemo(() => { if (!Number(sendValue)) return null; @@ -98,8 +106,8 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { const debouncedSendValue = useDebounce(sendValue, DEBOUNCE_DELAY); useEffect(() => { - // On mobile if (!isBase) return; + // On mobile if (sendValue === debouncedSendValue) { dispatch(setTransferActionInfo(undefined)); if (!selectedToken || !Number(debouncedSendValue)) { @@ -119,6 +127,7 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { const isHideSection = useMemo(() => { // no receive amount and some routes are displayed + if (!Number(sendValue)) return true; if (isGlobalFeeLoading) return false; return ( !Number(sendValue) || @@ -127,7 +136,7 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { !Object.values(estimatedAmount).every((element) => element === undefined) && !receiveAmt) ); - }, [sendValue, estimatedAmount, isBase, receiveAmt, isGlobalFeeLoading]); + }, [sendValue, estimatedAmount, receiveAmt, isGlobalFeeLoading, isBase]); const isHideRouteButton = useMemo(() => { return ( @@ -135,61 +144,80 @@ export const ReceiveInfo = ({ onOpen }: ReceiveInfoProps) => { ); }, [estimatedAmount]); - return !isHideSection ? ( - - - - {formatMessage({ id: 'you.receive.title' })} - - {isBase && !isHideRouteButton ? : null} - - - {debouncedSendValue === sendValue ? ( - receiveAmt && !isGlobalFeeLoading ? ( - <> - {isBase && } - {isBase && } - {bridgeType && ( - - )} - - - - + + + + + {formatMessage({ id: 'you.receive.title' })} + + {!isHideRouteButton ? ( + + + + ) : null} + + + {debouncedSendValue === sendValue ? ( + receiveAmt && !isGlobalFeeLoading ? ( + <> + { + + + + } + { + + + } - /> - - - ) : !receiveAmt && !isGlobalFeeLoading ? ( - - ) : ( - - ) - ) : ( - - )} - - - ) : null; + {bridgeType && ( + + )} + + + + + + + ) : !receiveAmt && !isGlobalFeeLoading ? ( + + ) : ( + + ) + ) : ( + + )} + + + + + ); }; diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/TokenSelectButton.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/TokenSelectButton.tsx index a7333056..271da271 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/TokenSelectButton.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/TokenSelectButton.tsx @@ -31,9 +31,10 @@ export function TokenSelectButton(props: SelectButtonProps) { p={'4px 8px 4px 4px'} justifyContent={'space-between'} gap={'8px'} - background={theme.colors[colorMode].button.select.background.default} + transition={'all .15s'} + background={theme.colors[colorMode].layer[4].default} _hover={{ - background: theme.colors[colorMode].button.select.background.hover, + background: theme.colors[colorMode].layer[4].hover, }} color={theme.colors[colorMode].text.primary} {...restProps} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/index.tsx index b3643ba2..c62d4d1a 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/SelectButton/index.tsx @@ -56,7 +56,7 @@ export function SelectButton(props: SelectButtonProps) { }} > - {chain?.name ?? 'Select Network'} + {chain?.name ?? ''} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/InputValidationMessage.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/InputValidationMessage.tsx index 38ef41a5..065c1289 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/InputValidationMessage.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/InputValidationMessage.tsx @@ -5,7 +5,6 @@ import { useAccount } from 'wagmi'; import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; import { useInputValidation } from '@/modules/transfer/hooks/useInputValidation'; import { setError, setIsTransferable } from '@/modules/transfer/action'; -import { useCBridgeSendMaxMin } from '@/modules/aggregator/adapters/cBridge/hooks/useCBridgeSendMaxMin'; import { useTokenBalance } from '@/modules/aggregator/hooks/useTokenBalance'; export const InputValidationMessage = () => { @@ -20,11 +19,10 @@ export const InputValidationMessage = () => { const selectedToken = useAppSelector((state) => state.transfer.selectedToken); const sendValue = useAppSelector((state) => state.transfer.sendValue); const estimatedAmount = useAppSelector((state) => state.transfer.estimatedAmount); + const minMaxSendAmt = useAppSelector((state) => state.aggregator.bridgeMaxMin.cBridge); const { getTokenBalance } = useTokenBalance(); - const { minMaxSendAmt } = useCBridgeSendMaxMin(); - const [balanceInputError, setBalanceInputError] = useState(''); useEffect(() => { @@ -54,7 +52,8 @@ export const InputValidationMessage = () => { sendValue, dispatch, estimatedAmount, - minMaxSendAmt, + minMaxSendAmt?.min, + minMaxSendAmt?.max, selectedToken?.decimals, selectedToken?.isPegged, transferActionInfo, diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/MaxLink.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/MaxLink.tsx index 507f1681..256c86e1 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/MaxLink.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/MaxLink.tsx @@ -53,7 +53,7 @@ export const MaxLink: React.FC = () => { cursor={!!balance ? 'pointer' : 'auto'} fontSize={'12px'} fontWeight={500} - pb={`1px`} + lineHeight={'16px'} transitionDuration="normal" sx={{ '@media (hover:hover)': { diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/index.tsx index fcfa5c04..0510e973 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/SendInput/index.tsx @@ -1,5 +1,5 @@ import { Box, Flex, Input, useColorMode, useDisclosure, useIntl, useTheme } from '@bnb-chain/space'; -import { useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; import { setSendValue } from '@/modules/transfer/action'; @@ -85,10 +85,21 @@ export const SendInput: React.FC = () => { }, DEBOUNCE_DELAY); }; + useEffect(() => { + if (isGlobalFeeLoading && sendValue === debouncedSendValue) { + setIsFocused(false); + } + }, [isGlobalFeeLoading, debouncedSendValue, sendValue]); + return ( - + {formatMessage({ id: 'you.send.title' })} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/ToAccount/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/ToAccount/index.tsx index d35c00c5..29f1dabf 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/ToAccount/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/ToAccount/index.tsx @@ -7,7 +7,6 @@ import { FlexProps, useIntl, InputGroup, - InputRightElement, } from '@bnb-chain/space'; import { ChangeEvent, useRef, useState } from 'react'; import { useEffect } from 'react'; @@ -15,11 +14,9 @@ import { useBytecode } from 'wagmi'; import { setIsToAddressChecked, setToAccount } from '@/modules/transfer/action'; import { useTronTransferInfo } from '@/modules/transfer/hooks/tron/useTronTransferInfo'; -import { ErrorIcon } from '@/core/components/icons/ErrorIcon'; -import { CorrectIcon } from '@/core/components/icons/CorrectIcon'; import { useAppDispatch, useAppSelector } from '@/modules/store/StoreProvider'; -import { ConfirmCheckbox } from '@/core/components/ConfirmCheckbox'; import { useTronContract } from '@/modules/aggregator/adapters/meson/hooks/useTronContract'; +import { ToAccountCheckBox } from '@/core/components/icons/ConfirmCheckIcon'; export function ToAccount(props: FlexProps) { const { colorMode } = useColorMode(); @@ -67,13 +64,13 @@ export function ToAccount(props: FlexProps) { const isInvalid = (!isAvailableAccount && !!toAccount.address) || isTronContract === true || !!evmBytecode; - const onCheckboxChange = (e: React.ChangeEvent) => { - if (e.target.checked === true) { - setIsChecked(true); - dispatch(setIsToAddressChecked(true)); - } else { + const toggleChecked = () => { + if (isChecked) { setIsChecked(false); dispatch(setIsToAddressChecked(false)); + } else { + setIsChecked(true); + dispatch(setIsToAddressChecked(true)); } }; @@ -123,12 +120,6 @@ export function ToAccount(props: FlexProps) { borderColor: theme.colors[colorMode].text.danger, }} /> - {(isInvalid || isAvailableAccount) && ( - - {isInvalid && } - {isAvailableAccount && !isInvalid && } - - )} {isInvalid && ( @@ -137,16 +128,10 @@ export function ToAccount(props: FlexProps) { )} - - {formatMessage({ id: 'to.section.confirm.text' })} - + + + {formatMessage({ id: 'to.section.confirm.text' })} + ); } diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/ToSection/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/ToSection/index.tsx index d37568b3..ad33a7c6 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/ToSection/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/ToSection/index.tsx @@ -1,12 +1,4 @@ -import { - Flex, - Typography, - theme, - useBreakpointValue, - useColorMode, - useDisclosure, - useIntl, -} from '@bnb-chain/space'; +import { Flex, Typography, theme, useColorMode, useDisclosure, useIntl } from '@bnb-chain/space'; import { SelectButton } from '@/modules/transfer/components/SelectButton'; import { useAppSelector } from '@/modules/store/StoreProvider'; @@ -16,25 +8,26 @@ import { DestinationNetworkModal } from '@/modules/aggregator/components/SelectM export function ToSection() { const { isOpen, onClose, onOpen } = useDisclosure(); const { formatMessage } = useIntl(); - const isBase = useBreakpointValue({ base: true, md: false }) ?? false; const { colorMode } = useColorMode(); const toChain = useAppSelector((state) => state.transfer.toChain); return ( - {isBase ? ( - - - {formatMessage({ id: 'to.section.title' })} - - - ) : null} + + + {formatMessage({ id: 'to.section.title' })} + + { gap={'8px'} background={theme.colors[colorMode].receive.background} borderRadius={'8px'} - p={[0, 0, 0, '24px 16px']} + p={[0, 0, 0, '0 16px']} > @@ -56,8 +56,9 @@ export const NoRouteFound = ({ onOpen }: NoRouteFoundProps) => { ? formatMessage({ id: 'route.no-found.desc' }) : formatMessage({ id: !isNoRoute ? 'route.adjust.desc' : 'route.no-found.desc' })} - {isBase && !isNoRoute && ( + {!isNoRoute && ( svg': { + verticalAlign: '-3px', + }, + }} {...otherProps} > diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/FeesInfo.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/FeesInfo.tsx index 9af5c0b3..1145390b 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/FeesInfo.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/FeesInfo.tsx @@ -22,6 +22,11 @@ export const FeesInfo = ({ summary, breakdown, bridgeType, isError }: FeesInfoPr display={'inline-block'} lineHeight={'16px'} opacity={isError ? 0.5 : 1} + sx={{ + '>svg': { + verticalAlign: '-3px', + }, + }} > { const routeError = useAppSelector((state) => state.transfer.routeError); return routeError && routeError[bridgeType] ? ( - + svg': { + verticalAlign: '-3px', + }, + }} + > {routeError[bridgeType]} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/RouteName/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/RouteName/index.tsx index 5598d3d0..deba3e0b 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/RouteName/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/RouteInfo/RouteName/index.tsx @@ -25,8 +25,15 @@ export const RouteName = React.memo( const receiveValue = getSortedReceiveAmount(); const bestTimeRoute = useGetBestTime(); const bestReturnRoute = getMaxValueKey(receiveValue); + return ( - + {bridgeType === 'cBridge' ? ( ) : bridgeType === 'deBridge' ? ( diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/index.tsx index f3df1d3f..1ecca835 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/TransferOverview/index.tsx @@ -6,6 +6,7 @@ import { useColorMode, useIntl, useTheme, + Collapse, } from '@bnb-chain/space'; import { ReactNode, useEffect, useMemo } from 'react'; @@ -27,12 +28,15 @@ import { DeBridgeOption } from '@/modules/aggregator/adapters/deBridge/component import { StarGateOption } from '@/modules/aggregator/adapters/stargate/components/StarGateOption'; import { LayerZeroOption } from '@/modules/aggregator/adapters/layerZero/components/LayerZeroOption'; import { MesonOption } from '@/modules/aggregator/adapters/meson/components/MesonOption'; +import { useAggregator } from '@/modules/aggregator/components/AggregatorProvider'; +import { CBridgeSendMaxMin } from '@/modules/aggregator/adapters/cBridge/components/CBridgeSendMaxMin'; export function TransferOverview({ routeContentBottom }: { routeContentBottom?: ReactNode }) { const dispatch = useAppDispatch(); const { formatMessage } = useIntl(); const { colorMode } = useColorMode(); const theme = useTheme(); + const { transferConfig } = useAggregator(); const { loadingBridgeFees } = useLoadingBridgeFees(); const { getSortedReceiveAmount } = useGetReceiveAmount(); @@ -42,9 +46,7 @@ export function TransferOverview({ routeContentBottom }: { routeContentBottom?: const sendValue = useAppSelector((state) => state.transfer.sendValue); const estimatedAmount = useAppSelector((state) => state.transfer.estimatedAmount); const toTokenInfo = useAppSelector((state) => state.transfer.toToken); - const debouncedSendValue = useDebounce(sendValue, DEBOUNCE_DELAY); - const isBase = useBreakpointValue({ base: true, lg: false }) ?? false; useEffect(() => { @@ -102,72 +104,86 @@ export function TransferOverview({ routeContentBottom }: { routeContentBottom?: const showRoute = selectedToken && !!Number(sendValue) && toTokenInfo && options && !!options?.length; - return ( - - {showRoute && ( - - + const loading = !options || !options?.length || isGlobalFeeLoading; + const content = ( + + + + {formatMessage({ id: 'route.title' })} + {!options.length || isGlobalFeeLoading ? ( + + ) : !isBase ? ( + + ) : null} + + + {loading ? ( - {!isBase ? ( - - {formatMessage({ id: 'route.title' })} - {!options.length || isGlobalFeeLoading ? ( - - ) : !isBase ? ( - - ) : null} - - ) : null} - - {!options || !options?.length || isGlobalFeeLoading ? ( - - - - - - ) : ( - - {options?.map((bridge: ReactNode) => bridge)} - - )} - + + + - + ) : ( + + {options?.map((bridge: ReactNode) => bridge)} + + )} - )} - {routeContentBottom ? routeContentBottom : null} + + + ); + + const cBridgeSupport = 'cBridge' in transferConfig; + + return ( + + {cBridgeSupport && } + + {!routeContentBottom ? ( + content + ) : ( + + + {content} + + + )} + {routeContentBottom ? routeContentBottom : null} + ); } diff --git a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts index da2e892c..7fc828fe 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts +++ b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useCallback, useRef } from 'react'; import { formatUnits, parseUnits } from 'viem'; import { useAccount, useBalance, usePublicClient } from 'wagmi'; import { BridgeType, DeBridgeCreateQuoteResponse } from '@bnb-chain/canonical-bridge-sdk'; @@ -27,6 +27,8 @@ import { useGetNativeToken } from '@/modules/transfer/hooks/useGetNativeToken'; import { useGetMesonFees } from '@/modules/aggregator/adapters/meson/hooks/useGetMesonFees'; import { formatNumber } from '@/core/utils/number'; +let lastTime = Date.now(); + export const useLoadingBridgeFees = () => { const dispatch = useAppDispatch(); const { preSelectRoute } = usePreSelectRoute(); @@ -38,11 +40,31 @@ export const useLoadingBridgeFees = () => { http: { deBridgeAccessToken }, } = useBridgeConfig(); const nativeToken = useGetNativeToken(); - const { deBridgeFeeSorting } = useGetDeBridgeFees(); - const { cBridgeFeeSorting, isAllowSendError } = useGetCBridgeFees(); - const { stargateFeeSorting } = useGetStargateFees(); - const { layerZeroFeeSorting } = useGetLayerZeroFees(); - const { mesonFeeSorting } = useGetMesonFees(); + const { deBridgeFeeSorting: _deBridgeFeeSorting } = useGetDeBridgeFees(); + const deBridgeFeeSorting = useRef(_deBridgeFeeSorting); + deBridgeFeeSorting.current = _deBridgeFeeSorting; + + const { cBridgeFeeSorting: _cBridgeFeeSorting, isAllowSendError: _isAllowSendError } = + useGetCBridgeFees(); + const cBridgeFeeSorting = useRef(_cBridgeFeeSorting); + cBridgeFeeSorting.current = _cBridgeFeeSorting; + + // todo ensure cbridge minmax range updates before loadingBridgeFees + const isAllowSendError = useRef(_isAllowSendError); + isAllowSendError.current = _isAllowSendError; + + const { stargateFeeSorting: _stargateFeeSorting } = useGetStargateFees(); + const stargateFeeSorting = useRef(_stargateFeeSorting); + stargateFeeSorting.current = _stargateFeeSorting; + + const { layerZeroFeeSorting: _layerZeroFeeSorting } = useGetLayerZeroFees(); + const layerZeroFeeSorting = useRef(_layerZeroFeeSorting); + layerZeroFeeSorting.current = _layerZeroFeeSorting; + + const { mesonFeeSorting: _mesonFeeSorting } = useGetMesonFees(); + const mesonFeeSorting = useRef(_mesonFeeSorting); + mesonFeeSorting.current = _mesonFeeSorting; + const { formatMessage } = useIntl(); const toToken = useAppSelector((state) => state.transfer.toToken); @@ -52,11 +74,15 @@ export const useLoadingBridgeFees = () => { const toChain = useAppSelector((state) => state.transfer.toChain); const max_slippage = useAppSelector((state) => state.transfer.slippage); + // todo ensure nativeBalance updates before loadingBridgeFees const { data: nativeBalance } = useBalance({ address, chainId: fromChain?.id }); + const nativeBalanceRef = useRef(nativeBalance); + nativeBalanceRef.current = nativeBalance; // eslint-disable-next-line @typescript-eslint/no-explicit-any const publicClient = usePublicClient({ chainId: fromChain?.id }) as any; const debouncedSendValue = useDebounce(sendValue, DEBOUNCE_DELAY); + const loadingBridgeFees = useCallback(async () => { dispatch(setRouteFees(undefined)); if (!selectedToken || !fromChain || !toChain || !debouncedSendValue) { @@ -84,6 +110,8 @@ export const useLoadingBridgeFees = () => { }); try { const amount = parseUnits(debouncedSendValue, selectedToken.decimals); + const now = Date.now(); + lastTime = now; const response = await bridgeSDK.loadBridgeFees({ bridgeType: bridgeTypeList, fromChainId: fromChain.id, @@ -126,6 +154,9 @@ export const useLoadingBridgeFees = () => { 'API response deBridge[0], cBridge[1], stargate[2], layerZero[3], meson[4]', response, ); + if (lastTime > now) { + return; + } // eslint-disable-next-line @typescript-eslint/no-explicit-any const [debridgeEst, cbridgeEst, stargateEst, layerZeroEst, mesonEst] = response as any; @@ -167,7 +198,7 @@ export const useLoadingBridgeFees = () => { ); } } else { - const feeSortingRes = await mesonFeeSorting(mesonEst.value.result); + const feeSortingRes = await mesonFeeSorting.current(mesonEst.value.result); const decimals = selectedToken?.meson?.raw?.decimals || 6; const receiveMesonAmt = parseUnits(debouncedSendValue, decimals) - @@ -196,7 +227,7 @@ export const useLoadingBridgeFees = () => { // deBridge if (debridgeEst.status === 'fulfilled' && debridgeEst?.value) { - const feeSortingRes = await deBridgeFeeSorting( + const feeSortingRes = await deBridgeFeeSorting.current( debridgeEst.value as DeBridgeCreateQuoteResponse, ); if (!feeSortingRes?.isFailedToGetGas) { @@ -243,12 +274,12 @@ export const useLoadingBridgeFees = () => { } else { dispatch(setEstimatedAmount({ cBridge: cbridgeEst.value })); - const feeSortingRes = await cBridgeFeeSorting(cbridgeEst.value); + const feeSortingRes = await cBridgeFeeSorting.current(cbridgeEst.value); // Hide route on gas error if (feeSortingRes?.isFailedToGetGas) { dispatch(setEstimatedAmount({ cBridge: undefined })); } - if (!isAllowSendError && !feeSortingRes?.isFailedToGetGas) { + if (!isAllowSendError.current && !feeSortingRes?.isFailedToGetGas) { valueArr.push({ type: 'cBridge', value: formatUnits( @@ -271,7 +302,7 @@ export const useLoadingBridgeFees = () => { // stargate if (stargateEst.status === 'fulfilled' && stargateEst?.value) { - const feeSortingRes = await stargateFeeSorting(stargateEst.value); + const feeSortingRes = await stargateFeeSorting.current(stargateEst.value); // Hide route if we can not get gas fee. if (!feeSortingRes?.isFailedToGetGas) { dispatch(setEstimatedAmount({ stargate: toObject(stargateEst.value) })); @@ -300,11 +331,11 @@ export const useLoadingBridgeFees = () => { // layerZero if (layerZeroEst.status === 'fulfilled' && layerZeroEst?.value) { const nativeFee = layerZeroEst?.value[0]; - if (nativeBalance?.value && nativeBalance.value < Number(nativeFee)) { + if (nativeBalanceRef.current?.value && nativeBalanceRef.current.value < Number(nativeFee)) { dispatch(setRouteError({ layerZero: `Insufficient ${nativeToken} to cover native fee` })); dispatch(setEstimatedAmount({ layerZero: 'error' })); } else { - const feeSortingRes = await layerZeroFeeSorting(layerZeroEst.value); + const feeSortingRes = await layerZeroFeeSorting.current(layerZeroEst.value); if (!feeSortingRes?.isFailedToGetGas) { dispatch( setEstimatedAmount({ @@ -344,11 +375,11 @@ export const useLoadingBridgeFees = () => { preSelectRoute(response, highestValue.type as BridgeType); } } + dispatch(setIsGlobalFeeLoading(false)); // eslint-disable-next-line } catch (error: any) { // eslint-disable-next-line no-console console.log(error, error.message); - } finally { dispatch(setIsGlobalFeeLoading(false)); } }, [ @@ -366,15 +397,7 @@ export const useLoadingBridgeFees = () => { max_slippage, bridgeSDK, deBridgeAccessToken, - nativeBalance?.value, - deBridgeFeeSorting, - cBridgeFeeSorting, - stargateFeeSorting, - layerZeroFeeSorting, - mesonFeeSorting, - preSelectRoute, - isAllowSendError, nativeToken, ]); diff --git a/packages/canonical-bridge-widget/src/modules/transfer/index.tsx b/packages/canonical-bridge-widget/src/modules/transfer/index.tsx index c2f4f39d..a3513f21 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/index.tsx @@ -1,6 +1,7 @@ import { Box, Flex, + Typography, useBreakpointValue, useColorMode, useDisclosure, @@ -32,7 +33,6 @@ export function TransferWidget() { return ( {appearance.bridgeTitle && ( - {appearance.bridgeTitle} - + )} @@ -72,11 +72,12 @@ export function TransferWidget() { - {isBase ? routeContentBottom : null} + {routeContentBottom} - {!isBase ? ( + - ) : ( + + {isBase && ( state.transfer.fromChain); const { formatMessage } = useIntl(); + const thresholdRef = useRef(false); const theme = useTheme(); const { colorMode } = useColorMode(); - const { chain, chainId, linkWallet } = useCurrentWallet(); + const { chain, chainId, linkWallet, walletType } = useCurrentWallet(); const fromChains = useFromChains(); - const isWrongNetwork = !!fromChain && fromChain.id !== chainId; - const { chainConfigs } = useAggregator(); - const supportedChains = fromChains.filter( - (c) => chainConfigs.find((e) => c.id === e.id) && c.chainType !== 'link', + const supportedChains = fromChains.filter((c) => chainConfigs.find((e) => c.id === e.id)); + const bridgeChains = useFromChains(); + + useEffect(() => { + thresholdRef.current = true; + setTimeout(() => { + thresholdRef.current = false; + }, 1000); + }, [chainId]); + + const switchDropdown = (onClose: () => void) => ( + + + + + {formatMessage({ id: 'wallet.network.switch-network' })} + + + + + + + {fromChain!.name} + + + + + {walletType !== fromChain?.chainType ? ( + + ) : ( + + )} + + + ); - const iconUrl = supportedChains.find((e) => e.id === chainId)?.icon; if (!chain) { - return null; + if (!chainId || !fromChain) return null; + + return ( + + {({ isOpen, onClose }) => { + return ( + <> + + + + + {formatMessage({ id: 'wallet.network.unknown-network' })} + + + {formatMessage({ id: 'wallet.network.unknown-network-mobile' })} + + + + + {switchDropdown(onClose)} + + ); + }} + + ); } + const isWrongNetwork = !!fromChain && fromChain.id !== chain.id && !thresholdRef.current; + const iconUrl = bridgeChains.find((e) => e.id === chain.id)?.icon; + return ( - {({ isOpen }) => { + {({ isOpen, onClose }) => { return ( <> - - + + {isWrongNetwork ? ( + + ) : ( + + )} {chain.name} - {isWrongNetwork && ( - - {formatMessage({ id: 'wallet.network.wrong-network' })} - - )} - - {supportedChains.map((item) => { - const isSelected = chainId === item.id; - - return ( - { - linkWallet({ - targetChainType: item.chainType, - targetChainId: item.id, - }); - }} - > - - - {item.name} - - {isSelected && } - - ); - })} - + {isWrongNetwork ? ( + switchDropdown(onClose) + ) : ( + + {supportedChains.map((item) => { + const isSelected = chainId === item.id; + + return ( + { + if (item.chainType === 'link') { + openLink(item.externalBridgeUrl); + return; + } + linkWallet({ + targetChainType: item.chainType, + targetChainId: item.id, + }); + }} + > + + + {item.name} + + {item.chainType === 'link' && ( + + )} + {isSelected && } + + ); + })} + + )} ); }} diff --git a/packages/canonical-bridge-widget/src/modules/wallet/components/ProfileMenu/index.tsx b/packages/canonical-bridge-widget/src/modules/wallet/components/ProfileMenu/index.tsx index 33645d3c..ed5aabf9 100644 --- a/packages/canonical-bridge-widget/src/modules/wallet/components/ProfileMenu/index.tsx +++ b/packages/canonical-bridge-widget/src/modules/wallet/components/ProfileMenu/index.tsx @@ -1,4 +1,4 @@ -import { Box, Center, Flex, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; +import { Box, Center, Flex, Typography, useColorMode, useIntl, useTheme } from '@bnb-chain/space'; import { DisconnectIcon } from '@bnb-chain/icons'; import { useWalletKit } from '@node-real/walletkit'; import { useMemo } from 'react'; @@ -10,6 +10,7 @@ import { Dropdown } from '@/modules/wallet/components/Dropdown/Dropdown'; import { DropdownButton } from '@/modules/wallet/components/Dropdown/DropdownButton'; import { DropdownList } from '@/modules/wallet/components/Dropdown/DropdownList'; import { useCurrentWallet } from '@/modules/wallet/CurrentWalletProvider'; +import { WalletIcon } from '@/core/components/icons/WalletIcon'; export const ProfileMenu = () => { const { formatMessage } = useIntl(); @@ -23,6 +24,7 @@ export const ProfileMenu = () => { {({ isOpen, onClose }) => ( <> { {walletIcon} )} - {formatAppAddress({ address })} + + + {formatAppAddress({ address })} + + @@ -130,7 +136,7 @@ function useWalletIcon() { if (selectedWallet) { const { transparent: transparentLogos } = selectedWallet.logos ?? {}; const transparentLogo = (transparentLogos as any)?.[colorMode] ?? transparentLogos; - return transparentLogo; + return transparentLogo || ; } return null;