diff --git a/apps/bridge/public/icons/bridges/axelar.webp b/apps/bridge/public/icons/bridges/axelar.webp new file mode 100644 index 0000000000..6866d01029 Binary files /dev/null and b/apps/bridge/public/icons/bridges/axelar.webp differ diff --git a/apps/bridge/public/icons/bridges/hop_protocol.webp b/apps/bridge/public/icons/bridges/hop_protocol.webp new file mode 100644 index 0000000000..fb75edc986 Binary files /dev/null and b/apps/bridge/public/icons/bridges/hop_protocol.webp differ diff --git a/apps/bridge/public/icons/bridges/socket.webp b/apps/bridge/public/icons/bridges/socket.webp new file mode 100644 index 0000000000..61d874a8c0 Binary files /dev/null and b/apps/bridge/public/icons/bridges/socket.webp differ diff --git a/apps/bridge/public/icons/bridges/synapse.webp b/apps/bridge/public/icons/bridges/synapse.webp new file mode 100644 index 0000000000..c5f2d1d087 Binary files /dev/null and b/apps/bridge/public/icons/bridges/synapse.webp differ diff --git a/apps/bridge/public/icons/bridges/wormhole.webp b/apps/bridge/public/icons/bridges/wormhole.webp new file mode 100644 index 0000000000..88cd2016e0 Binary files /dev/null and b/apps/bridge/public/icons/bridges/wormhole.webp differ diff --git a/apps/bridge/src/components/WithdrawContainer/BridgeProviderDropdown.tsx b/apps/bridge/src/components/WithdrawContainer/BridgeProviderDropdown.tsx new file mode 100644 index 0000000000..952b93ad6a --- /dev/null +++ b/apps/bridge/src/components/WithdrawContainer/BridgeProviderDropdown.tsx @@ -0,0 +1,91 @@ +import { useChainEnv } from 'apps/bridge/src/utils/hooks/useChainEnv'; +import { useCallback, useState } from 'react'; + +const chainEnvToBridgeTime = { + mainnet: 'Takes about 7 days', + testnet: 'Takes about 20 minutes', +}; + +type BridgeProviderDropdownProps = { + bridgeProvider: 'native' | 'thirdParty'; + setBridgeProvider: (bridgeProvider: 'native' | 'thirdParty') => void; +}; + +export function BridgeProviderDropdown({ + bridgeProvider, + setBridgeProvider, +}: BridgeProviderDropdownProps) { + const [isOpen, setIsOpen] = useState(false); + const chainEnv = useChainEnv(); + + const handleToggleDropdown = useCallback(() => { + setIsOpen(!isOpen); + }, [isOpen]); + + const handleSelectNative = useCallback(() => { + setBridgeProvider('native'); + setIsOpen(false); + }, [setBridgeProvider]); + + const handleSelectThirdParty = useCallback(() => { + setBridgeProvider('thirdParty'); + setIsOpen(false); + }, [setBridgeProvider]); + + return ( +
+ Method +
+
+ +
+ {isOpen && ( +
+
+ + +
+
+ )} +
+ + {bridgeProvider === 'native' ? chainEnvToBridgeTime[chainEnv] : 'Takes about 20 minutes'} + +
+ ); +} diff --git a/apps/bridge/src/components/WithdrawContainer/ThirdPartyBridges.tsx b/apps/bridge/src/components/WithdrawContainer/ThirdPartyBridges.tsx new file mode 100644 index 0000000000..f6f9bfbb50 --- /dev/null +++ b/apps/bridge/src/components/WithdrawContainer/ThirdPartyBridges.tsx @@ -0,0 +1,57 @@ +import Image from 'next/image'; + +const THIRD_PARTY_BRIDGES = [ + { name: 'Hop Exchange', logo: '/icons/bridges/hop_protocol.webp', url: 'https://hop.exchange/' }, + { name: 'Synapse', logo: '/icons/bridges/synapse.webp', url: 'https://www.synapseprotocol.com' }, + { name: 'Socket Tech', logo: '/icons/bridges/socket.webp', url: 'https://socket.tech/' }, +]; + +type ThirdPartyBridgeProps = { + name: string; + logo: string; + url: string; +}; + +function ThirdPartyBridge({ name, logo, url }: ThirdPartyBridgeProps) { + return ( + + {name} + {name} + + ); +} + +export function ThirdPartyBridges() { + return ( +
+ Choose Third-Party Bridge +
+ {THIRD_PARTY_BRIDGES.map((bridge) => ( + + ))} +
+ + Show More + + + These are independent service providers that Base is linking to for your convenience. Base + has no responsibility for their operation. + +
+ ); +} diff --git a/apps/bridge/src/components/WithdrawContainer/WithdrawContainer.tsx b/apps/bridge/src/components/WithdrawContainer/WithdrawContainer.tsx index 9462a8a068..ce54c2e97f 100644 --- a/apps/bridge/src/components/WithdrawContainer/WithdrawContainer.tsx +++ b/apps/bridge/src/components/WithdrawContainer/WithdrawContainer.tsx @@ -31,6 +31,8 @@ import { useIsContractApproved } from 'apps/bridge/src/utils/hooks/useIsContract import { useApproveContract } from 'apps/bridge/src/utils/hooks/useApproveContract'; import { BridgeButton } from 'apps/bridge/src/components/BridgeButton/BridgeButton'; import { parseUnits } from 'viem'; +import { BridgeProviderDropdown } from 'apps/bridge/src/components/WithdrawContainer/BridgeProviderDropdown'; +import { ThirdPartyBridges } from 'apps/bridge/src/components/WithdrawContainer/ThirdPartyBridges'; const activeAssets = getWithdrawalAssetsForChainEnv(); @@ -47,6 +49,7 @@ export function WithdrawContainer() { const [selectedAsset, setSelectedAsset] = useState(activeAssets[0]); const publicClient = usePublicClient({ chainId }); const { switchNetwork } = useSwitchNetwork(); + const [bridgeProvider, setBridgeProvider] = useState<'native' | 'thirdParty'>('thirdParty'); useEffect(() => { switchNetwork?.(chainId); @@ -294,44 +297,57 @@ export function WithdrawContainer() { return (
-
- + - - {button} - - - {isSmartContractWallet && ( - + {bridgeProvider === 'thirdParty' && ( +
+ +
)} + {bridgeProvider === 'native' && ( +
+ + + {button} + + + {isSmartContractWallet && ( + + )} -
- -
{button}
-
+
+ +
{button}
+
+
+ )}