From f9b3eb59bd7076b528abcb4001858d193efbe04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 15:37:46 +0100 Subject: [PATCH 01/57] initial commit --- .../src/components/App/App.tsx | 13 +- .../components/MainContent/MainContent.tsx | 9 +- .../TransferPanel/TransferPanel.tsx | 138 ++++++++------- .../TransferPanel/TransferPanelMain.tsx | 165 +++++++++--------- .../arb-token-bridge-ui/src/pages/index.tsx | 13 +- 5 files changed, 171 insertions(+), 167 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 20707f7698..97674325a2 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -64,6 +64,7 @@ const rainbowkitTheme = merge(darkTheme(), { } as Theme) const AppContent = (): JSX.Element => { + const { isConnected } = useAccount() const [{ sourceChain }] = useNetworks() const { app: { connectionState } @@ -105,9 +106,7 @@ const AppContent = (): JSX.Element => { <> - - - + {isConnected && } @@ -425,11 +424,9 @@ export default function App() { > - - - {isTosAccepted && } - - + + {isTosAccepted && } + diff --git a/packages/arb-token-bridge-ui/src/components/MainContent/MainContent.tsx b/packages/arb-token-bridge-ui/src/components/MainContent/MainContent.tsx index 7fb30594c2..801faef812 100644 --- a/packages/arb-token-bridge-ui/src/components/MainContent/MainContent.tsx +++ b/packages/arb-token-bridge-ui/src/components/MainContent/MainContent.tsx @@ -16,16 +16,13 @@ import { TransactionStatusInfo } from '../TransactionHistory/TransactionStatusIn export const motionDivProps = { layout: true, initial: { - opacity: 0, - scale: 0.9 + opacity: 0 }, animate: { - opacity: 1, - scale: 1 + opacity: 1 }, exit: { - opacity: 0, - scale: 0.9 + opacity: 0 } } diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index 02b2ea6b8b..9554f8e0a5 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -70,6 +70,7 @@ import { getBridgeUiConfigForChain } from '../../util/bridgeUiConfig' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { CctpTransferStarter } from '@/token-bridge-sdk/CctpTransferStarter' +import { useConnectModal } from '@rainbow-me/rainbowkit' const isAllowedL2 = async ({ l1TokenAddress, @@ -175,6 +176,7 @@ export function TransferPanel() { [setQueryParams] ) + const { openConnectModal } = useConnectModal() const [tokenImportDialogProps] = useDialog() const [tokenCheckDialogProps, openTokenCheckDialog] = useDialog() const [tokenApprovalDialogProps, openTokenApprovalDialog] = useDialog() @@ -1202,72 +1204,84 @@ export function TransferPanel() { )} - {isDepositMode ? ( - + {isConnected ? ( + <> + {isDepositMode ? ( + + ) : ( + + )} + ) : ( )} diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx index 7b57bcd9f0..09ee11d62c 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx @@ -345,6 +345,7 @@ export function TransferPanelMain({ setAmount: (value: string) => void errorMessage?: TransferReadinessRichErrorMessage | string }) { + const { isConnected } = useAccount() const actions = useActions() const [networks, setNetworks] = useNetworks() const { @@ -985,39 +986,41 @@ export function TransferPanelMain({ - <> - - {nativeCurrency.isCustom ? ( - <> - + + {nativeCurrency.isCustom ? ( + <> + + {/* Only show ETH balance on L1 */} + {isDepositMode && } + + ) : ( + - {/* Only show ETH balance on L1 */} - {isDepositMode && } - - ) : ( - - )} - + )} + + )} @@ -1079,63 +1082,67 @@ export function TransferPanelMain({ > - - {destinationAddressOrWalletAddress && - utils.isAddress(destinationAddressOrWalletAddress) && ( - <> - - {/* In deposit mode, when user selected USDC on mainnet, - the UI shows the Arb One balance of both USDC.e and native USDC */} - {isDepositMode && showUSDCSpecificInfo && ( + {isConnected && ( + + {destinationAddressOrWalletAddress && + utils.isAddress(destinationAddressOrWalletAddress) && ( + <> - )} - {nativeCurrency.isCustom ? ( - <> + {/* In deposit mode, when user selected USDC on mainnet, + the UI shows the Arb One balance of both USDC.e and native USDC */} + {isDepositMode && showUSDCSpecificInfo && ( + )} + {nativeCurrency.isCustom ? ( + <> + + {!isDepositMode && ( + + )} + + ) : ( + - {!isDepositMode && } - - ) : ( - - )} - - )} - + )} + + )} + + )} diff --git a/packages/arb-token-bridge-ui/src/pages/index.tsx b/packages/arb-token-bridge-ui/src/pages/index.tsx index 53e3747dee..6d2fd7434c 100644 --- a/packages/arb-token-bridge-ui/src/pages/index.tsx +++ b/packages/arb-token-bridge-ui/src/pages/index.tsx @@ -2,8 +2,6 @@ import React, { useEffect } from 'react' import dynamic from 'next/dynamic' import { addCustomChain, addCustomNetwork } from '@arbitrum/sdk' -import { AppConnectionFallbackContainer } from '../components/App/AppConnectionFallbackContainer' -import { Loader } from '../components/common/atoms/Loader' import { getCustomChainsFromLocalStorage, xaiTestnet, @@ -11,16 +9,7 @@ import { } from '../util/networks' import { mapCustomChainToNetworkData } from '../util/networks' -const App = dynamic(() => import('../components/App/App'), { - ssr: false, - loading: () => ( - -
- -
-
- ) -}) +const App = dynamic(() => import('../components/App/App'), { ssr: false }) export default function Index() { useEffect(() => { From 5647bc7be6e7e7b63693d292dd93a3ba841bb7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 16:21:11 +0100 Subject: [PATCH 02/57] hide token balance while not connected --- .../src/components/TransferPanel/TokenRow.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx index fbe5ebec7b..8764646b74 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx @@ -87,6 +87,7 @@ export function TokenRow({ arbTokenBridge: { bridgeTokens } } } = useAppState() + const { isConnected } = useAccount() const { isLoading: isLoadingAccountType } = useAccountType() const [networks] = useNetworks() const { @@ -296,6 +297,10 @@ export function TokenRow({ }, [childChain.id, isDepositMode, parentChain.id]) const tokenBalanceContent = useMemo(() => { + if (!isConnected) { + return null + } + if (!tokenIsAddedToTheBridge) { return Import } @@ -327,6 +332,7 @@ export function TokenRow({ ) }, [ + isConnected, isLoadingAccountType, token?.decimals, tokenBalance, From ac2904cd0e9e7066c4db8c75a5834908198a2c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 16:41:19 +0100 Subject: [PATCH 03/57] move to separate file --- .../src/components/App/App.tsx | 53 ++----------------- .../App/ConnectedChainQueryParamSyncer.tsx | 46 ++++++++++++++++ 2 files changed, 51 insertions(+), 48 deletions(-) create mode 100644 packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 97674325a2..f77c52ee99 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react' import * as Sentry from '@sentry/react' -import { useAccount, useNetwork, WagmiConfig } from 'wagmi' +import { useAccount, WagmiConfig } from 'wagmi' import { darkTheme, RainbowKitProvider, @@ -33,20 +33,18 @@ import { import { HeaderAccountPopover } from '../common/HeaderAccountPopover' import { Notifications } from '../common/Notifications' import { isNetwork, rpcURLs } from '../../util/networks' -import { - ArbQueryParamProvider, - useArbQueryParams -} from '../../hooks/useArbQueryParams' +import { ArbQueryParamProvider } from '../../hooks/useArbQueryParams' import { GET_HELP_LINK, TOS_LOCALSTORAGE_KEY } from '../../constants' import { getProps } from '../../util/wagmi/setup' import { useAccountIsBlocked } from '../../hooks/useAccountIsBlocked' import { useCCTPIsBlocked } from '../../hooks/CCTP/useCCTPIsBlocked' import { useNativeCurrency } from '../../hooks/useNativeCurrency' -import { sanitizeQueryParams, useNetworks } from '../../hooks/useNetworks' +import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { HeaderConnectWalletButton } from '../common/HeaderConnectWalletButton' import { AppConnectionFallbackContainer } from './AppConnectionFallbackContainer' import { ProviderName, trackEvent } from '../../util/AnalyticsUtils' +import { ConnectedChainQueryParamSyncer } from './ConnectedChainQueryParamSyncer' declare global { interface Window { @@ -351,47 +349,6 @@ Object.keys(localStorage).forEach(key => { } }) -function ConnectedChainSyncer() { - const [shouldSync, setShouldSync] = useState(false) - const [didSync, setDidSync] = useState(false) - - const [{ sourceChain, destinationChain }, setQueryParams] = - useArbQueryParams() - const { chain } = useNetwork() - - useEffect(() => { - if (shouldSync) { - return - } - - // Only sync connected chain to query params if the query params were not initially provided - if ( - typeof sourceChain === 'undefined' && - typeof destinationChain === 'undefined' - ) { - setShouldSync(true) - } - }, [shouldSync, sourceChain, destinationChain]) - - useEffect(() => { - // When the chain is connected and we should sync, and we haven't synced yet, sync the connected chain to the query params - if (chain && shouldSync && !didSync) { - const { - sourceChainId: sourceChain, - destinationChainId: destinationChain - } = sanitizeQueryParams({ - sourceChainId: chain.id, - destinationChainId: undefined - }) - - setQueryParams({ sourceChain, destinationChain }) - setDidSync(true) - } - }, [chain, shouldSync, didSync, setQueryParams]) - - return null -} - export default function App() { const [overmind] = useState>(createOvermind(config)) const [tosAccepted, setTosAccepted] = @@ -422,7 +379,7 @@ export default function App() { theme={rainbowkitTheme} {...rainbowKitProviderProps} > - + {isTosAccepted && } diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx new file mode 100644 index 0000000000..d7018188ca --- /dev/null +++ b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx @@ -0,0 +1,46 @@ +import { useState, useEffect } from 'react' +import { useNetwork } from 'wagmi' + +import { useArbQueryParams } from '../../hooks/useArbQueryParams' +import { sanitizeQueryParams } from '../../hooks/useNetworks' + +export function ConnectedChainQueryParamSyncer() { + const [shouldSync, setShouldSync] = useState(false) + const [didSync, setDidSync] = useState(false) + + const { chain } = useNetwork() + const [{ sourceChain, destinationChain }, setQueryParams] = + useArbQueryParams() + + useEffect(() => { + if (shouldSync) { + return + } + + // Only sync connected chain to query params if the query params were not initially provided + if ( + typeof sourceChain === 'undefined' && + typeof destinationChain === 'undefined' + ) { + setShouldSync(true) + } + }, [shouldSync, sourceChain, destinationChain]) + + useEffect(() => { + // When the chain is connected and we should sync, and we haven't synced yet, sync the connected chain to the query params + if (chain && shouldSync && !didSync) { + const { + sourceChainId: sourceChain, + destinationChainId: destinationChain + } = sanitizeQueryParams({ + sourceChainId: chain.id, + destinationChainId: undefined + }) + + setQueryParams({ sourceChain, destinationChain }) + setDidSync(true) + } + }, [chain, shouldSync, didSync, setQueryParams]) + + return null +} From 761f76b0cde85a438acf916bfd2144bf38ffdc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 16:49:25 +0100 Subject: [PATCH 04/57] clean up --- .../src/components/App/App.tsx | 101 +----------------- .../App/AppConnectionFallbackContainer.tsx | 38 ------- .../App/ConnectedChainAnalyticsSyncer.tsx | 78 ++++++++++++++ yarn.lock | 5 + 4 files changed, 87 insertions(+), 135 deletions(-) delete mode 100644 packages/arb-token-bridge-ui/src/components/App/AppConnectionFallbackContainer.tsx create mode 100644 packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index f77c52ee99..76e84cbec2 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -1,13 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react' -import * as Sentry from '@sentry/react' import { useAccount, WagmiConfig } from 'wagmi' -import { - darkTheme, - RainbowKitProvider, - Theme, - useConnectModal -} from '@rainbow-me/rainbowkit' +import { darkTheme, RainbowKitProvider, Theme } from '@rainbow-me/rainbowkit' import merge from 'lodash-es/merge' import axios from 'axios' import { createOvermind, Overmind } from 'overmind' @@ -32,7 +26,7 @@ import { } from '../common/Header' import { HeaderAccountPopover } from '../common/HeaderAccountPopover' import { Notifications } from '../common/Notifications' -import { isNetwork, rpcURLs } from '../../util/networks' +import { isNetwork } from '../../util/networks' import { ArbQueryParamProvider } from '../../hooks/useArbQueryParams' import { GET_HELP_LINK, TOS_LOCALSTORAGE_KEY } from '../../constants' import { getProps } from '../../util/wagmi/setup' @@ -41,10 +35,8 @@ import { useCCTPIsBlocked } from '../../hooks/CCTP/useCCTPIsBlocked' import { useNativeCurrency } from '../../hooks/useNativeCurrency' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' -import { HeaderConnectWalletButton } from '../common/HeaderConnectWalletButton' -import { AppConnectionFallbackContainer } from './AppConnectionFallbackContainer' -import { ProviderName, trackEvent } from '../../util/AnalyticsUtils' import { ConnectedChainQueryParamSyncer } from './ConnectedChainQueryParamSyncer' +import { ConnectedChainAnalyticsSyncer } from './ConnectedChainAnalyticsSyncer' declare global { interface Window { @@ -245,92 +237,6 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { ) } -// connector names: https://github.com/wagmi-dev/wagmi/blob/b17c07443e407a695dfe9beced2148923b159315/docs/pages/core/connectors/_meta.en-US.json#L4 -function getWalletName(connectorName: string): ProviderName { - switch (connectorName) { - case 'MetaMask': - case 'Coinbase Wallet': - case 'Trust Wallet': - case 'Safe': - case 'Injected': - case 'Ledger': - return connectorName - - case 'WalletConnectLegacy': - case 'WalletConnect': - return 'WalletConnect' - - default: - return 'Other' - } -} - -/** given our RPC url, sanitize it before logging to Sentry, to only pass the url and not the keys */ -function getBaseUrl(url: string) { - try { - const urlObject = new URL(url) - return `${urlObject.protocol}//${urlObject.hostname}` - } catch { - // if invalid url passed - return '' - } -} - -function NetworkReady({ children }: { children: React.ReactNode }) { - const [networks] = useNetworks() - const { parentChain, childChain } = useNetworksRelationship(networks) - const { isConnected, connector } = useAccount() - const [tosAccepted] = useLocalStorage(TOS_LOCALSTORAGE_KEY) - const { openConnectModal } = useConnectModal() - - useEffect(() => { - if (tosAccepted !== undefined && !isConnected) { - openConnectModal?.() - } - }, [isConnected, tosAccepted, openConnectModal]) - - useEffect(() => { - if (isConnected && connector) { - const walletName = getWalletName(connector.name) - trackEvent('Connect Wallet Click', { walletName }) - } - - // set a custom tag in sentry to filter issues by connected wallet.name - Sentry.setTag('wallet.name', connector?.name ?? '') - }, [isConnected, connector]) - - useEffect(() => { - Sentry.setTag('network.parent_chain_id', parentChain.id) - Sentry.setTag( - 'network.parent_chain_rpc_url', - getBaseUrl(rpcURLs[parentChain.id] ?? '') - ) - Sentry.setTag('network.child_chain_id', childChain.id) - Sentry.setTag( - 'network.child_chain_rpc_url', - getBaseUrl(rpcURLs[childChain.id] ?? '') - ) - }, [childChain.id, parentChain.id]) - - if (!isConnected) { - return ( - <> - - - - - - - Please connect your wallet to use the bridge. - - - - ) - } - - return <>{children} -} - // We're doing this as a workaround so users can select their preferred chain on WalletConnect. // // https://github.com/orgs/WalletConnect/discussions/2733 @@ -379,6 +285,7 @@ export default function App() { theme={rainbowkitTheme} {...rainbowKitProviderProps} > + diff --git a/packages/arb-token-bridge-ui/src/components/App/AppConnectionFallbackContainer.tsx b/packages/arb-token-bridge-ui/src/components/App/AppConnectionFallbackContainer.tsx deleted file mode 100644 index 4405b8f801..0000000000 --- a/packages/arb-token-bridge-ui/src/components/App/AppConnectionFallbackContainer.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Image, { ImageProps } from 'next/image' -import ThreeArbinautsImg from '@/images/three-arbinauts.webp' -import { ExternalLink } from '../common/ExternalLink' -import { WalletConnectWarning } from '../common/WalletConnectWarning' - -export function AppConnectionFallbackContainer({ - layout = 'col', - imgProps = { - className: 'sm:w-[420px]', - src: ThreeArbinautsImg, - alt: 'Three Arbinauts', - priority: true - }, - children -}: { - layout?: 'row' | 'col' - imgProps?: ImageProps - children: React.ReactNode -}) { - return ( -
- - -
-
- {children} - - - -
-
-
- ) -} diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx new file mode 100644 index 0000000000..52f3e5af5e --- /dev/null +++ b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx @@ -0,0 +1,78 @@ +import { useEffect } from 'react' +import { useAccount } from 'wagmi' +import * as Sentry from '@sentry/react' + +import { useNetworks } from '../../hooks/useNetworks' +import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' +import { ProviderName, trackEvent } from '../../util/AnalyticsUtils' +import { rpcURLs } from '../../util/networks' + +// connector names: https://github.com/wagmi-dev/wagmi/blob/b17c07443e407a695dfe9beced2148923b159315/docs/pages/core/connectors/_meta.en-US.json#L4 +function getWalletName(connectorName: string): ProviderName { + switch (connectorName) { + case 'MetaMask': + case 'Coinbase Wallet': + case 'Trust Wallet': + case 'Safe': + case 'Injected': + case 'Ledger': + return connectorName + + case 'WalletConnectLegacy': + case 'WalletConnect': + return 'WalletConnect' + + default: + return 'Other' + } +} + +/** given our RPC url, sanitize it before logging to Sentry, to only pass the url and not the keys */ +function getBaseUrl(url: string | undefined): string | null { + if (typeof url === 'undefined') { + return null + } + + try { + const urlObject = new URL(url) + return `${urlObject.protocol}//${urlObject.hostname}` + } catch { + // if invalid url passed + return null + } +} + +export function ConnectedChainAnalyticsSyncer() { + const { isConnected, connector } = useAccount() + + const [networks] = useNetworks() + const { parentChain, childChain } = useNetworksRelationship(networks) + + useEffect(() => { + if (isConnected && connector) { + const walletName = getWalletName(connector.name) + trackEvent('Connect Wallet Click', { walletName }) + + // set a custom tag in sentry to filter issues by connected wallet.name + Sentry.setTag('wallet.name', walletName) + } + }, [isConnected, connector]) + + useEffect(() => { + Sentry.setTag('network.parent_chain_id', parentChain.id) + Sentry.setTag('network.child_chain_id', childChain.id) + + const parentChainRpcUrl = getBaseUrl(rpcURLs[parentChain.id]) + const childChainRpcUrl = getBaseUrl(rpcURLs[childChain.id]) + + if (parentChainRpcUrl) { + Sentry.setTag('network.parent_chain_rpc_url', parentChainRpcUrl) + } + + if (childChainRpcUrl) { + Sentry.setTag('network.child_chain_rpc_url', childChainRpcUrl) + } + }, [childChain.id, parentChain.id]) + + return null +} diff --git a/yarn.lock b/yarn.lock index 1a302bbaf2..60175a1c96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1296,6 +1296,11 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@ledgerhq/connect-kit-loader@^1.0.1": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@ledgerhq/connect-kit-loader/-/connect-kit-loader-1.1.8.tgz#6cc32191660dd9d6e8f89047af09b0f201e30190" + integrity sha512-mDJsOucVW8m3Lk2fdQst+P74SgiKebvq1iBk4sXLbADQOwhL9bWGaArvO+tW7jPJZwEfSPWBdHcHoYi11XAwZw== + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" From 8983c6cf31370d7fcefb4d656c53f74144f643ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 16:52:29 +0100 Subject: [PATCH 05/57] rename component --- packages/arb-token-bridge-ui/src/components/App/App.tsx | 4 ++-- .../src/components/App/ConnectedChainQueryParamSyncer.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 76e84cbec2..389e52a42d 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -35,8 +35,8 @@ import { useCCTPIsBlocked } from '../../hooks/CCTP/useCCTPIsBlocked' import { useNativeCurrency } from '../../hooks/useNativeCurrency' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' -import { ConnectedChainQueryParamSyncer } from './ConnectedChainQueryParamSyncer' import { ConnectedChainAnalyticsSyncer } from './ConnectedChainAnalyticsSyncer' +import { ConnectedChainQueryParamsSyncer } from './ConnectedChainQueryParamSyncer' declare global { interface Window { @@ -286,7 +286,7 @@ export default function App() { {...rainbowKitProviderProps} > - + {isTosAccepted && } diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx index d7018188ca..a385357d19 100644 --- a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx @@ -4,7 +4,7 @@ import { useNetwork } from 'wagmi' import { useArbQueryParams } from '../../hooks/useArbQueryParams' import { sanitizeQueryParams } from '../../hooks/useNetworks' -export function ConnectedChainQueryParamSyncer() { +export function ConnectedChainQueryParamsSyncer() { const [shouldSync, setShouldSync] = useState(false) const [didSync, setDidSync] = useState(false) From 7fc643a12061474fdef03850017bffa41d81f947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 17:02:32 +0100 Subject: [PATCH 06/57] christophe and fionna told me to make those hooks --- packages/arb-token-bridge-ui/src/components/App/App.tsx | 9 +++++---- .../src/components/App/ConnectedChainAnalyticsSyncer.tsx | 2 +- .../components/App/ConnectedChainQueryParamSyncer.tsx | 4 +--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 389e52a42d..219a84ea21 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -35,8 +35,8 @@ import { useCCTPIsBlocked } from '../../hooks/CCTP/useCCTPIsBlocked' import { useNativeCurrency } from '../../hooks/useNativeCurrency' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' -import { ConnectedChainAnalyticsSyncer } from './ConnectedChainAnalyticsSyncer' -import { ConnectedChainQueryParamsSyncer } from './ConnectedChainQueryParamSyncer' +import { useSyncConnectedChainToAnalytics } from './ConnectedChainAnalyticsSyncer' +import { useSyncConnectedChainToQueryParams } from './ConnectedChainQueryParamSyncer' declare global { interface Window { @@ -120,6 +120,9 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { // We want to be sure this fetch is completed by the time we open the USDC modals useCCTPIsBlocked() + useSyncConnectedChainToAnalytics() + useSyncConnectedChainToQueryParams() + const [tokenBridgeParams, setTokenBridgeParams] = useState(null) @@ -285,8 +288,6 @@ export default function App() { theme={rainbowkitTheme} {...rainbowKitProviderProps} > - - {isTosAccepted && } diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx index 52f3e5af5e..98cab09dcb 100644 --- a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx @@ -42,7 +42,7 @@ function getBaseUrl(url: string | undefined): string | null { } } -export function ConnectedChainAnalyticsSyncer() { +export function useSyncConnectedChainToAnalytics() { const { isConnected, connector } = useAccount() const [networks] = useNetworks() diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx index a385357d19..4afa7e7861 100644 --- a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx @@ -4,7 +4,7 @@ import { useNetwork } from 'wagmi' import { useArbQueryParams } from '../../hooks/useArbQueryParams' import { sanitizeQueryParams } from '../../hooks/useNetworks' -export function ConnectedChainQueryParamsSyncer() { +export function useSyncConnectedChainToQueryParams() { const [shouldSync, setShouldSync] = useState(false) const [didSync, setDidSync] = useState(false) @@ -41,6 +41,4 @@ export function ConnectedChainQueryParamsSyncer() { setDidSync(true) } }, [chain, shouldSync, didSync, setQueryParams]) - - return null } From 83ff1e083438351788ac704e724b85bb975b847c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 17:04:01 +0100 Subject: [PATCH 07/57] rename files --- packages/arb-token-bridge-ui/src/components/App/App.tsx | 4 ++-- ...nalyticsSyncer.tsx => useSyncConnectedChainToAnalytics.ts} | 0 ...yParamSyncer.tsx => useSyncConnectedChainToQueryParams.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/arb-token-bridge-ui/src/components/App/{ConnectedChainAnalyticsSyncer.tsx => useSyncConnectedChainToAnalytics.ts} (100%) rename packages/arb-token-bridge-ui/src/components/App/{ConnectedChainQueryParamSyncer.tsx => useSyncConnectedChainToQueryParams.ts} (100%) diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 219a84ea21..5fc4a1bd95 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -35,8 +35,8 @@ import { useCCTPIsBlocked } from '../../hooks/CCTP/useCCTPIsBlocked' import { useNativeCurrency } from '../../hooks/useNativeCurrency' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' -import { useSyncConnectedChainToAnalytics } from './ConnectedChainAnalyticsSyncer' -import { useSyncConnectedChainToQueryParams } from './ConnectedChainQueryParamSyncer' +import { useSyncConnectedChainToAnalytics } from './useSyncConnectedChainToAnalytics' +import { useSyncConnectedChainToQueryParams } from './useSyncConnectedChainToQueryParams' declare global { interface Window { diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts similarity index 100% rename from packages/arb-token-bridge-ui/src/components/App/ConnectedChainAnalyticsSyncer.tsx rename to packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts diff --git a/packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx b/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToQueryParams.ts similarity index 100% rename from packages/arb-token-bridge-ui/src/components/App/ConnectedChainQueryParamSyncer.tsx rename to packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToQueryParams.ts From fd27e6778242ec69e4c531fdd39e98c95b41bed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 17:05:09 +0100 Subject: [PATCH 08/57] remove return value --- .../src/components/App/useSyncConnectedChainToAnalytics.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts b/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts index 98cab09dcb..90e08ec2a1 100644 --- a/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts +++ b/packages/arb-token-bridge-ui/src/components/App/useSyncConnectedChainToAnalytics.ts @@ -73,6 +73,4 @@ export function useSyncConnectedChainToAnalytics() { Sentry.setTag('network.child_chain_rpc_url', childChainRpcUrl) } }, [childChain.id, parentChain.id]) - - return null } From 6c5f22f705740627985fd5704d9b58247094e14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dragi=C5=A1a=20Spasojevi=C4=87?= Date: Fri, 19 Jan 2024 17:07:05 +0100 Subject: [PATCH 09/57] blah --- yarn.lock | 5 ----- 1 file changed, 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 60175a1c96..1a302bbaf2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1296,11 +1296,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@ledgerhq/connect-kit-loader@^1.0.1": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@ledgerhq/connect-kit-loader/-/connect-kit-loader-1.1.8.tgz#6cc32191660dd9d6e8f89047af09b0f201e30190" - integrity sha512-mDJsOucVW8m3Lk2fdQst+P74SgiKebvq1iBk4sXLbADQOwhL9bWGaArvO+tW7jPJZwEfSPWBdHcHoYi11XAwZw== - "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" From ffdaa6452c171f83800d569f284bf35040a65085 Mon Sep 17 00:00:00 2001 From: Fionna Chan Date: Mon, 22 Jan 2024 18:39:38 +0000 Subject: [PATCH 10/57] add settings toggle --- .../src/components/App/App.tsx | 5 +- .../src/components/App/WelcomeDialog.tsx | 11 --- .../src/components/common/Header.tsx | 2 +- .../common/HeaderConnectWalletButton.tsx | 84 ------------------- .../common/atoms/SettingsToggle.tsx | 19 +++++ .../arb-token-bridge-ui/tailwind.config.js | 3 +- 6 files changed, 26 insertions(+), 98 deletions(-) delete mode 100644 packages/arb-token-bridge-ui/src/components/common/HeaderConnectWalletButton.tsx create mode 100644 packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 5fc4a1bd95..7e72aeec99 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -37,6 +37,7 @@ import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { useSyncConnectedChainToAnalytics } from './useSyncConnectedChainToAnalytics' import { useSyncConnectedChainToQueryParams } from './useSyncConnectedChainToQueryParams' +import { SettingsToggle } from '../common/atoms/SettingsToggle' declare global { interface Window { @@ -96,7 +97,9 @@ const AppContent = (): JSX.Element => { <> - {isConnected && } + + {isConnected ? : } + diff --git a/packages/arb-token-bridge-ui/src/components/App/WelcomeDialog.tsx b/packages/arb-token-bridge-ui/src/components/App/WelcomeDialog.tsx index 96acfa9895..528e168313 100644 --- a/packages/arb-token-bridge-ui/src/components/App/WelcomeDialog.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/WelcomeDialog.tsx @@ -1,27 +1,16 @@ import { useRef } from 'react' import { Dialog as HeadlessUIDialog } from '@headlessui/react' import Image from 'next/image' -import { useConnectModal } from '@rainbow-me/rainbowkit' -import * as Sentry from '@sentry/react' import { Button } from '../common/Button' import { ExternalLink } from '../common/ExternalLink' import { Dialog, UseDialogProps } from '../common/Dialog' -import { errorToast } from '../common/atoms/Toast' export function WelcomeDialog(props: UseDialogProps) { const confirmButtonRef = useRef(null) - const { openConnectModal } = useConnectModal() const closeHandler = () => { props.onClose(true) - - try { - openConnectModal?.() - } catch (error) { - errorToast('Failed to open up RainbowKit Connect Modal') - Sentry.captureException(error) - } } return ( diff --git a/packages/arb-token-bridge-ui/src/components/common/Header.tsx b/packages/arb-token-bridge-ui/src/components/common/Header.tsx index f672d82c38..d3008dc386 100644 --- a/packages/arb-token-bridge-ui/src/components/common/Header.tsx +++ b/packages/arb-token-bridge-ui/src/components/common/Header.tsx @@ -307,7 +307,7 @@ function MobileExternalLink({ const HeaderItemLogo = ({ src, alt }: { src: string; alt: string }) => { return ( - + {alt} ) diff --git a/packages/arb-token-bridge-ui/src/components/common/HeaderConnectWalletButton.tsx b/packages/arb-token-bridge-ui/src/components/common/HeaderConnectWalletButton.tsx deleted file mode 100644 index b72f55ceea..0000000000 --- a/packages/arb-token-bridge-ui/src/components/common/HeaderConnectWalletButton.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { PlusCircleIcon } from '@heroicons/react/24/outline' -import { ConnectButton } from '@rainbow-me/rainbowkit' -import { HeaderAccountPopover } from './HeaderAccountPopover' - -function NetworkButtonAndConnectButton({ - connected, - chainUnsupported, - openConnectModal, - openChainModal -}: { - connected: boolean - chainUnsupported?: boolean - openChainModal: () => void - openConnectModal: () => void -}) { - if (!connected) { - return ( - - ) - } - - if (chainUnsupported) { - return ( - - ) - } - - return ( -
- -
- ) -} - -function HeaderConnectWalletButtonWrapper({ - children, - ready -}: { - children: JSX.Element - ready: boolean -}) { - return ( -
- {children} -
- ) -} - -export function HeaderConnectWalletButton() { - return ( - - {({ account, chain, openChainModal, openConnectModal, mounted }) => { - const connected = !!(mounted && account && chain) - - return ( - - - - ) - }} - - ) -} diff --git a/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx b/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx new file mode 100644 index 0000000000..c45ec23cfc --- /dev/null +++ b/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx @@ -0,0 +1,19 @@ +import { Cog6ToothIcon } from '@heroicons/react/24/outline' + +import { useArbQueryParams } from '../../../hooks/useArbQueryParams' + +export function SettingsToggle() { + const [, setQueryParams] = useArbQueryParams() + + return ( + + ) +} diff --git a/packages/arb-token-bridge-ui/tailwind.config.js b/packages/arb-token-bridge-ui/tailwind.config.js index 4b307d3a8d..078a65ddd5 100644 --- a/packages/arb-token-bridge-ui/tailwind.config.js +++ b/packages/arb-token-bridge-ui/tailwind.config.js @@ -30,8 +30,9 @@ module.exports = { 'gray-1': '#F4F4F4', 'gray-2': '#E5E5E5', 'gray-3': '#DADADA', - 'gray-5': '#AEAEAE', 'gray-4': '#CCCCCC', + 'gray-5': '#AEAEAE', + 'gray-header-menu': '#8d8e8e', 'gray-6': '#999999', 'gray-dark': '#6D6D6D', dark: '#1A1C1D', // (or default-black) From 7afe65c8aaa8c75c51cf3df4406666bc14be50b4 Mon Sep 17 00:00:00 2001 From: Fionna Chan Date: Mon, 22 Jan 2024 18:56:22 +0000 Subject: [PATCH 11/57] remove address requirement for select token --- .../src/components/App/App.tsx | 15 +++++---------- .../TransferPanel/TokenImportDialog.tsx | 5 ++--- .../src/components/TransferPanel/TokenSearch.tsx | 4 ---- .../components/TransferPanel/TransferPanel.tsx | 3 --- .../components/common/atoms/SettingsToggle.tsx | 4 ++-- .../src/components/syncers/TokenListSyncer.tsx | 7 +------ packages/arb-token-bridge-ui/tailwind.config.js | 2 +- 7 files changed, 11 insertions(+), 29 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/App/App.tsx b/packages/arb-token-bridge-ui/src/components/App/App.tsx index 7e72aeec99..fef311eb80 100644 --- a/packages/arb-token-bridge-ui/src/components/App/App.tsx +++ b/packages/arb-token-bridge-ui/src/components/App/App.tsx @@ -113,7 +113,7 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { const actions = useActions() const { app } = useAppState() const { selectedToken } = app - const { address, isConnected } = useAccount() + const { address } = useAccount() const { isBlocked } = useAccountIsBlocked() const [networks] = useNetworks() const { childChain, childChainProvider, parentChain, parentChainProvider } = @@ -155,13 +155,9 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { setTokenBridgeParams(null) actions.app.setConnectionState(ConnectionState.LOADING) - if (!isConnected) { - return - } - const { - isArbitrum: isConnectedToArbitrum, - isOrbitChain: isConnectedToOrbitChain + isArbitrum: isSourceChainArbitrum, + isOrbitChain: isSourceChainOrbitChain } = isNetwork(networks.sourceChain.id) const isParentChainEthereum = isNetwork( parentChain.id @@ -174,8 +170,8 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { }) if ( - (isParentChainEthereum && isConnectedToArbitrum) || - isConnectedToOrbitChain + (isParentChainEthereum && isSourceChainArbitrum) || + isSourceChainOrbitChain ) { console.info('Withdrawal mode detected:') actions.app.setConnectionState(ConnectionState.L2_CONNECTED) @@ -195,7 +191,6 @@ const Injector = ({ children }: { children: React.ReactNode }): JSX.Element => { } }) }, [ - isConnected, address, networks.sourceChain.id, parentChain.id, diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenImportDialog.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenImportDialog.tsx index 87a7a7c18e..31cd9e91d1 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenImportDialog.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenImportDialog.tsx @@ -70,7 +70,6 @@ export function TokenImportDialog({ onClose, tokenAddress }: TokenImportDialogProps): JSX.Element { - const { address: walletAddress } = useAccount() const { app: { arbTokenBridge: { bridgeTokens, token }, @@ -125,7 +124,7 @@ export function TokenImportDialog({ }, [status]) const getL1TokenDataFromL1Address = useCallback(async () => { - if (!l1Address || !walletAddress) { + if (!l1Address) { return } @@ -136,7 +135,7 @@ export function TokenImportDialog({ } return fetchErc20Data(erc20Params) - }, [parentChainProvider, walletAddress, l1Address]) + }, [parentChainProvider, l1Address]) const searchForTokenInLists = useCallback( (erc20L1Address: string): TokenListSearchResult => { diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx index bc5b0d5431..31e5187fc0 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx @@ -538,10 +538,6 @@ export function TokenSearch({ close }: { close: () => void }) { return } - if (!walletAddress) { - return - } - const data = await fetchErc20Data({ address: _token.address, provider: parentChainProvider diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index af961f3d22..d88fa86dfb 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -702,9 +702,6 @@ export function TransferPanel() { setTransferring(false) } - if (!isConnected) { - return - } if (!walletAddress) { return } diff --git a/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx b/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx index c45ec23cfc..c1d0c7f2ba 100644 --- a/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx +++ b/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx @@ -7,11 +7,11 @@ export function SettingsToggle() { return ( diff --git a/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx b/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx index d2bdb11462..656e8f0b60 100644 --- a/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx +++ b/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx @@ -15,7 +15,6 @@ const TokenListSyncer = (): JSX.Element => { const { app: { arbTokenBridge, arbTokenBridgeLoaded } } = useAppState() - const { address: walletAddress } = useAccount() const [networks] = useNetworks() const { childChain } = useNetworksRelationship(networks) @@ -24,10 +23,6 @@ const TokenListSyncer = (): JSX.Element => { return } - if (!walletAddress) { - return - } - const tokenListsToSet = BRIDGE_TOKEN_LISTS.filter(bridgeTokenList => { // Always load the Arbitrum Token token list if (bridgeTokenList.isArbitrumTokenTokenList) { @@ -43,7 +38,7 @@ const TokenListSyncer = (): JSX.Element => { tokenListsToSet.forEach(bridgeTokenList => { addBridgeTokenListToBridge(bridgeTokenList, arbTokenBridge) }) - }, [walletAddress, childChain.id, arbTokenBridgeLoaded]) + }, [childChain.id, arbTokenBridgeLoaded]) return <> } diff --git a/packages/arb-token-bridge-ui/tailwind.config.js b/packages/arb-token-bridge-ui/tailwind.config.js index 078a65ddd5..62cd6081d1 100644 --- a/packages/arb-token-bridge-ui/tailwind.config.js +++ b/packages/arb-token-bridge-ui/tailwind.config.js @@ -32,8 +32,8 @@ module.exports = { 'gray-3': '#DADADA', 'gray-4': '#CCCCCC', 'gray-5': '#AEAEAE', - 'gray-header-menu': '#8d8e8e', 'gray-6': '#999999', + 'gray-header-menu': '#8d8e8e', 'gray-dark': '#6D6D6D', dark: '#1A1C1D', // (or default-black) From a4b42b9875b320ad8aa2439b6bf9c5d26ac74205 Mon Sep 17 00:00:00 2001 From: Fionna Chan Date: Fri, 9 Feb 2024 17:01:57 +0000 Subject: [PATCH 12/57] clean up after merging --- .../TransferPanel/TransferPanelMain.tsx | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx index 06dbad8250..fc73bee278 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx @@ -277,7 +277,15 @@ function TokenBalance({ ) } -function BalancesContainer({ children }: { children: React.ReactNode }) { +function BalancesContainer({ + children +}: { + children: JSX.Element[] | React.ReactNode +}) { + const { address: walletAddress, isConnected } = useAccount() + if (!walletAddress || !isConnected) { + return null + } return (
{children} @@ -826,39 +834,37 @@ export function TransferPanelMain({ - <> - - {nativeCurrency.isCustom ? ( - <> - - {/* Only show ETH balance on L1 */} - {isDepositMode && } - - ) : ( - + {nativeCurrency.isCustom ? ( + <> + - )} - + {/* Only show ETH balance on L1 */} + {isDepositMode && } + + ) : ( + + )} From 4d41c70d8b6ce08e60f35d82ba7b70704b1003a0 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 12 Feb 2024 15:55:14 +0100 Subject: [PATCH 13/57] Fix gas loading when user is not connected --- .../src/hooks/TransferPanel/useGasSummary.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts index ed883eb3d6..a76d650347 100644 --- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts +++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts @@ -61,7 +61,7 @@ export function useGasSummary(): UseGasSummaryResult { const [networks] = useNetworks() const { childChainProvider, parentChainProvider, isDepositMode } = useNetworksRelationship(networks) - const { address: walletAddress } = useAccount() + const { address: walletAddress, isConnected } = useAccount() const [{ amount }] = useArbQueryParams() const nativeCurrency = useNativeCurrency({ provider: childChainProvider }) const [gasSummary, setGasSummary] = useState( @@ -172,14 +172,18 @@ export function useGasSummary(): UseGasSummaryResult { } } - estimateGas() + if (!isConnected) { + setGasSummaryStatus('unavailable') + return + } }, [ // Re-run gas estimation when: estimateGas, isDepositMode, // when user switches deposit/withdraw mode amountDebounced, token, // when the token changes - setGasSummaryStatus + setGasSummaryStatus, + isConnected // when the user connects/disconnects their wallet ]) return gasSummary From 31ca5184e73f3c6aeae9a22ada5959a1b708c048 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 12 Feb 2024 15:55:32 +0100 Subject: [PATCH 14/57] Allow token import for non connected user --- packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts index 029063db28..1ca124fef6 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts @@ -773,10 +773,6 @@ export const useArbTokenBridge = ( let l1Address: string let l2Address: string | undefined - if (!walletAddress) { - return - } - const lowercasedErc20L1orL2Address = erc20L1orL2Address.toLowerCase() const maybeL1Address = await getL1ERC20Address({ erc20L2Address: lowercasedErc20L1orL2Address, From 2bc8d60d2a32c0a7f2d141ac50c33708df110617 Mon Sep 17 00:00:00 2001 From: Fionna Chan Date: Wed, 6 Mar 2024 19:52:03 +0000 Subject: [PATCH 15/57] update padding --- .../src/components/TransferPanel/TransferPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index 6c18452ee0..d5ea63396e 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -1094,7 +1094,7 @@ export function TransferPanel() { From 70009f607e11ce2926782f8f32e249d52f4a3de0 Mon Sep 17 00:00:00 2001 From: Fionna Chan Date: Wed, 6 Mar 2024 19:56:42 +0000 Subject: [PATCH 16/57] clean up --- .../TransferPanel/TransferPanelMain.tsx | 1 - .../common/atoms/SettingsToggle.tsx | 19 ------------------- .../src/hooks/TransferPanel/useGasSummary.ts | 5 +---- .../arb-token-bridge-ui/tailwind.config.js | 1 - 4 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx index 29148c14df..89a907ecf4 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain.tsx @@ -332,7 +332,6 @@ export function TransferPanelMain({ setAmount: (value: string) => void errorMessage?: TransferReadinessRichErrorMessage | string }) { - const { isConnected } = useAccount() const actions = useActions() const [networks, setNetworks] = useNetworks() const { childChain, childChainProvider, parentChainProvider, isDepositMode } = diff --git a/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx b/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx deleted file mode 100644 index c1d0c7f2ba..0000000000 --- a/packages/arb-token-bridge-ui/src/components/common/atoms/SettingsToggle.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Cog6ToothIcon } from '@heroicons/react/24/outline' - -import { useArbQueryParams } from '../../../hooks/useArbQueryParams' - -export function SettingsToggle() { - const [, setQueryParams] = useArbQueryParams() - - return ( - - ) -} diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts index a76d650347..62cccba170 100644 --- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts +++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts @@ -172,10 +172,7 @@ export function useGasSummary(): UseGasSummaryResult { } } - if (!isConnected) { - setGasSummaryStatus('unavailable') - return - } + estimateGas() }, [ // Re-run gas estimation when: estimateGas, diff --git a/packages/arb-token-bridge-ui/tailwind.config.js b/packages/arb-token-bridge-ui/tailwind.config.js index 5fdb680f53..14f911b5a8 100644 --- a/packages/arb-token-bridge-ui/tailwind.config.js +++ b/packages/arb-token-bridge-ui/tailwind.config.js @@ -35,7 +35,6 @@ module.exports = { 'gray-4': '#CCCCCC', 'gray-5': '#AEAEAE', 'gray-6': '#999999', - 'gray-header-menu': '#8d8e8e', 'gray-7': '#BDBDBD', 'gray-dark': '#6D6D6D', 'line-gray': '#F4F4F4', From 0cfd82be23d1a79a4f2d43bbbd4ae9314a70c414 Mon Sep 17 00:00:00 2001 From: Bartek Date: Thu, 7 Mar 2024 14:01:35 +0100 Subject: [PATCH 17/57] feat: add Xai Sepolia (#1580) --- .../src/util/__tests__/networks.test.ts | 4 +- .../src/util/orbitChainsList.ts | 59 +++++++++++-------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts b/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts index 3974162c7b..62a8121204 100644 --- a/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts +++ b/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts @@ -7,7 +7,7 @@ import { } from '../networks' import { orbitTestnets } from '../orbitChainsList' -const xaiTestnetChainId = 47279324479 +const xaiTestnetChainId = 37714555429 beforeAll(() => { const xaiTestnet = orbitTestnets[xaiTestnetChainId] @@ -136,7 +136,7 @@ describe('getBaseChainIdByChainId', () => { getBaseChainIdByChainId({ chainId: xaiTestnetChainId }) - ).toBe(ChainId.Goerli) + ).toBe(ChainId.Sepolia) expect( getBaseChainIdByChainId({ diff --git a/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts b/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts index e0170b926d..c890445060 100644 --- a/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts +++ b/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts @@ -229,40 +229,41 @@ export const orbitMainnets: { } export const orbitTestnets: { [key in number]: OrbitChainConfig } = { - 47279324479: { - chainID: 47279324479, - confirmPeriodBlocks: 20, + 37714555429: { + chainID: 37714555429, + confirmPeriodBlocks: 150, ethBridge: { - bridge: '0xf958e56d431eA78C7444Cf6A6184Af732Ae6a8A3', - inbox: '0x8b842ad88AAffD63d52EC54f6428fb7ff83060a8', - outbox: '0xDfe36Bea935F11260b0159dCA255b6668925d743', - rollup: '0x082742561295f6e1b43c4f5d1e2d52d7FfE082f1', - sequencerInbox: '0x5fD0cCc5D31748A44b43cf8DFBFA0FAA32665464' + bridge: '0x6c7FAC4edC72E86B3388B48979eF37Ecca5027e6', + inbox: '0x6396825803B720bc6A43c63caa1DcD7B31EB4dd0', + outbox: '0xc7491a559b416540427f9f112C5c98b1412c5d51', + rollup: '0xeedE9367Df91913ab149e828BDd6bE336df2c892', + sequencerInbox: '0x529a2061A1973be80D315770bA9469F3Da40D938' }, - explorerUrl: 'https://testnet-explorer.xai-chain.net', - rpcUrl: 'https://testnet.xai-chain.net/rpc', + nativeToken: '0x4e6f41acbfa8eb4a3b25e151834d9a14b49b69d2', + explorerUrl: 'https://testnet-explorer-v2.xai-chain.net', + rpcUrl: 'https://testnet-v2.xai-chain.net/rpc', isArbitrum: true, isCustom: true, - name: 'Xai Orbit Testnet', + name: 'Xai Testnet', slug: 'xai-testnet', - partnerChainID: 421613, + partnerChainID: 421614, partnerChainIDs: [], retryableLifetimeSeconds: 604800, tokenBridge: { - l1CustomGateway: '0xdBbDc3EE848C05792CC93EA140c59731f920c3F2', - l1ERC20Gateway: '0xC033fBAFd978440460d943efe6A3bF6A1a990e80', - l1GatewayRouter: '0xCb0Fe28c36a60Cf6254f4dd74c13B0fe98FFE5Db', - l1MultiCall: '0x21779e0950A87DDD57E341d54fc12Ab10F6eE167', - l1ProxyAdmin: '0xc80853e91f8Ac0AaD6ff939F3861600Ab34Dfe12', - l1Weth: '0xe39Ab88f8A4777030A534146A9Ca3B52bd5D43A3', - l1WethGateway: '0x58ea20BE21b971Fa282905EdA74bA46540eEd977', - l2CustomGateway: '0xc60622D1FbDD63Cf9c173D1b69715Ef2B725D792', - l2ERC20Gateway: '0x47ab2DfD627360fC6ac4Ae2fB9fa6f3539aFfeCc', - l2GatewayRouter: '0x75c2848D0B2116d6832Ff3758df09D4209b4b7ce', - l2Multicall: '0xE2fBe979bD0df59554Fded36f3A3BF5206f287a2', - l2ProxyAdmin: '0x81DeEc20158a367f7039ab3a563C1eB63cc2b3D6', - l2Weth: '0xea77c06A6703A781f9442EFa083e21F3F75907F8', - l2WethGateway: '0x927b59cCde7a92acDa085514FdEA39f0c4D1a2DC' + l1CustomGateway: '0x04e14E04949D49ae9c551ca8Cc3192310Ce65D88', + l1ERC20Gateway: '0xCcB451C4Df22addCFe1447c58bC6b2f264Bb1256', + l1GatewayRouter: '0x185b868DBBF41554465fcb99C6FAb9383E15f47A', + l1MultiCall: '0xA115146782b7143fAdB3065D86eACB54c169d092', + l1ProxyAdmin: '0x022c515aEAb29aaFf82e86A10950cE14eA89C9c5', + l1Weth: '0x0000000000000000000000000000000000000000', + l1WethGateway: '0x0000000000000000000000000000000000000000', + l2CustomGateway: '0xea1ce1CC75C948488515A3058E10aa82da40cE8F', + l2ERC20Gateway: '0xD840761a09609394FaFA3404bEEAb312059AC558', + l2GatewayRouter: '0x3B8ba769a43f34cdD67a20aF60d08D54C9C8f1AD', + l2Multicall: '0x5CBd60Ae5Af80A42FA8b0F20ADF95A8879844984', + l2ProxyAdmin: '0x7C1BA251d812fb34aF5C2566040C3C30585aFed9', + l2Weth: '0x0000000000000000000000000000000000000000', + l2WethGateway: '0x0000000000000000000000000000000000000000' }, nitroGenesisBlock: 0, nitroGenesisL1Block: 0, @@ -274,6 +275,12 @@ export const orbitTestnets: { [key in number]: OrbitChainConfig } = { name: 'Xai Testnet', logo: '/images/XaiLogo.svg', description: 'The testnet for Xai’s gaming chain.' + }, + nativeTokenData: { + name: 'Xai', + symbol: 'sXAI', + decimals: 18, + logoUrl: '/images/XaiLogo.svg' } } } From 3559b13036b62497af56722adf7e95d683f2544a Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 8 Mar 2024 17:22:54 +0000 Subject: [PATCH 18/57] Move addBridgeTokenListToBridge to useArbTokenBridge --- .../components/TransferPanel/TokenSearch.tsx | 5 +- .../components/syncers/TokenListSyncer.tsx | 18 +- .../src/hooks/arbTokenBridge.types.ts | 2 + .../src/hooks/useArbTokenBridge.ts | 259 ++++++++++-------- .../src/util/TokenListUtils.ts | 14 - 5 files changed, 158 insertions(+), 140 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx index 803d25cc06..8da3ed6517 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx @@ -9,7 +9,6 @@ import { useActions, useAppState } from '../../state' import { BRIDGE_TOKEN_LISTS, BridgeTokenList, - addBridgeTokenListToBridge, SPECIAL_ARBITRUM_TOKEN_TOKEN_LIST_ID } from '../../util/TokenListUtils' import { @@ -70,10 +69,10 @@ function TokenListRow({ tokenList }: { tokenList: BridgeTokenList }) { if (isActive) { token.removeTokensFromList(bridgeTokenList.id) } else { - addBridgeTokenListToBridge(bridgeTokenList, arbTokenBridge) + token.addBridgeTokenListToBridge(bridgeTokenList) } }, - [arbTokenBridge, token] + [token] ) const isActive = Object.keys(bridgeTokens ?? []).some(address => { diff --git a/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx b/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx index 656e8f0b60..dbcdf05398 100644 --- a/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx +++ b/packages/arb-token-bridge-ui/src/components/syncers/TokenListSyncer.tsx @@ -1,13 +1,9 @@ import { useEffect } from 'react' -import { useAccount } from 'wagmi' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { useAppState } from '../../state' -import { - addBridgeTokenListToBridge, - BRIDGE_TOKEN_LISTS -} from '../../util/TokenListUtils' +import { BRIDGE_TOKEN_LISTS } from '../../util/TokenListUtils' // Adds whitelisted tokens to the bridge data on app load // In the token list we should show later only tokens with positive balances @@ -22,23 +18,25 @@ const TokenListSyncer = (): JSX.Element => { if (!arbTokenBridgeLoaded) { return } - const tokenListsToSet = BRIDGE_TOKEN_LISTS.filter(bridgeTokenList => { // Always load the Arbitrum Token token list if (bridgeTokenList.isArbitrumTokenTokenList) { return true } - return ( bridgeTokenList.originChainID === childChain.id && bridgeTokenList.isDefault ) }) - tokenListsToSet.forEach(bridgeTokenList => { - addBridgeTokenListToBridge(bridgeTokenList, arbTokenBridge) + arbTokenBridge.token.addBridgeTokenListToBridge(bridgeTokenList) }) - }, [childChain.id, arbTokenBridgeLoaded]) + }, [ + // arbTokenBridge.token is not a memoized object, adding it here would cause infinite loop + childChain.id, + arbTokenBridgeLoaded, + arbTokenBridge.token?.addBridgeTokenListToBridge + ]) return <> } diff --git a/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts b/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts index 3e9c37e3cf..440780c3bb 100644 --- a/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts +++ b/packages/arb-token-bridge-ui/src/hooks/arbTokenBridge.types.ts @@ -24,6 +24,7 @@ import { Transaction, L1ToL2MessageData } from './useTransactions' +import { BridgeTokenList } from '../util/TokenListUtils' export { OutgoingMessageState } @@ -162,6 +163,7 @@ export interface ArbTokenBridgeToken { addL2NativeToken: (erc20L2Address: string) => void addTokensFromList: (tokenList: TokenList, listID: number) => void removeTokensFromList: (listID: number) => void + addBridgeTokenListToBridge: (bridgeTokenList: BridgeTokenList) => void updateTokenData: (l1Address: string) => Promise approve: (params: { erc20L1Address: string diff --git a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts index d8a72a56a9..9958f321a3 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useArbTokenBridge.ts @@ -49,6 +49,7 @@ import { addDepositToCache, getProvider } from '../components/TransactionHistory/helpers' +import { BridgeTokenList, fetchTokenListFromURL } from '../util/TokenListUtils' export const wait = (ms = 0) => { return new Promise(res => setTimeout(res, ms)) @@ -653,142 +654,173 @@ export const useArbTokenBridge = ( }) } - const addTokensFromList = async (arbTokenList: TokenList, listId: number) => { - const l1ChainID = l1.network.id - const l2ChainID = l2.network.id + const addTokensFromList = useCallback( + async (arbTokenList: TokenList, listId: number) => { + const l1ChainID = l1.network.id + const l2ChainID = l2.network.id - const bridgeTokensToAdd: ContractStorage = {} + const bridgeTokensToAdd: ContractStorage = {} - const candidateUnbridgedTokensToAdd: ERC20BridgeToken[] = [] + const candidateUnbridgedTokensToAdd: ERC20BridgeToken[] = [] - for (const tokenData of arbTokenList.tokens) { - const { address, name, symbol, extensions, decimals, logoURI, chainId } = - tokenData + for (const tokenData of arbTokenList.tokens) { + const { + address, + name, + symbol, + extensions, + decimals, + logoURI, + chainId + } = tokenData - if (![l1ChainID, l2ChainID].includes(chainId)) { - continue - } + if (![l1ChainID, l2ChainID].includes(chainId)) { + continue + } - const bridgeInfo = (() => { - // TODO: parsing the token list format could be from arbts or the tokenlist package - interface Extensions { - bridgeInfo: { - [chainId: string]: { - tokenAddress: string - originBridgeAddress: string - destBridgeAddress: string + const bridgeInfo = (() => { + // TODO: parsing the token list format could be from arbts or the tokenlist package + interface Extensions { + bridgeInfo: { + [chainId: string]: { + tokenAddress: string + originBridgeAddress: string + destBridgeAddress: string + } } } - } - const isExtensions = (obj: any): obj is Extensions => { - if (!obj) return false - if (!obj['bridgeInfo']) return false - return Object.keys(obj['bridgeInfo']) - .map(key => obj['bridgeInfo'][key]) - .every( - e => - e && - 'tokenAddress' in e && - 'originBridgeAddress' in e && - 'destBridgeAddress' in e - ) - } - if (!isExtensions(extensions)) { - return null - } else { - return extensions.bridgeInfo - } - })() + const isExtensions = (obj: any): obj is Extensions => { + if (!obj) return false + if (!obj['bridgeInfo']) return false + return Object.keys(obj['bridgeInfo']) + .map(key => obj['bridgeInfo'][key]) + .every( + e => + e && + 'tokenAddress' in e && + 'originBridgeAddress' in e && + 'destBridgeAddress' in e + ) + } + if (!isExtensions(extensions)) { + return null + } else { + return extensions.bridgeInfo + } + })() - if (bridgeInfo) { - const l1Address = bridgeInfo[l1NetworkID]?.tokenAddress.toLowerCase() + if (bridgeInfo) { + const l1Address = bridgeInfo[l1NetworkID]?.tokenAddress.toLowerCase() - if (!l1Address) { - return - } + if (!l1Address) { + return + } - bridgeTokensToAdd[l1Address] = { - name, - type: TokenType.ERC20, - symbol, - address: l1Address, - l2Address: address.toLowerCase(), - decimals, - logoURI, - listIds: new Set([listId]) + bridgeTokensToAdd[l1Address] = { + name, + type: TokenType.ERC20, + symbol, + address: l1Address, + l2Address: address.toLowerCase(), + decimals, + logoURI, + listIds: new Set([listId]) + } + } + // save potentially unbridged L1 tokens: + // stopgap: giant lists (i.e., CMC list) currently severaly hurts page performace, so for now we only add the bridged tokens + else if (arbTokenList.tokens.length < 1000) { + candidateUnbridgedTokensToAdd.push({ + name, + type: TokenType.ERC20, + symbol, + address: address.toLowerCase(), + decimals, + logoURI, + listIds: new Set([listId]) + }) } } - // save potentially unbridged L1 tokens: - // stopgap: giant lists (i.e., CMC list) currently severaly hurts page performace, so for now we only add the bridged tokens - else if (arbTokenList.tokens.length < 1000) { - candidateUnbridgedTokensToAdd.push({ - name, - type: TokenType.ERC20, - symbol, - address: address.toLowerCase(), - decimals, - logoURI, - listIds: new Set([listId]) - }) - } - } - // add L1 tokens only if they aren't already bridged (i.e., if they haven't already beed added as L2 arb-tokens to the list) - const l1AddressesOfBridgedTokens = new Set( - Object.keys(bridgeTokensToAdd).map( - l1Address => - l1Address.toLowerCase() /* lists should have the checksummed case anyway, but just in case (pun unintended) */ + // add L1 tokens only if they aren't already bridged (i.e., if they haven't already beed added as L2 arb-tokens to the list) + const l1AddressesOfBridgedTokens = new Set( + Object.keys(bridgeTokensToAdd).map( + l1Address => + l1Address.toLowerCase() /* lists should have the checksummed case anyway, but just in case (pun unintended) */ + ) ) - ) - for (const l1TokenData of candidateUnbridgedTokensToAdd) { - if (!l1AddressesOfBridgedTokens.has(l1TokenData.address.toLowerCase())) { - bridgeTokensToAdd[l1TokenData.address] = l1TokenData + for (const l1TokenData of candidateUnbridgedTokensToAdd) { + if ( + !l1AddressesOfBridgedTokens.has(l1TokenData.address.toLowerCase()) + ) { + bridgeTokensToAdd[l1TokenData.address] = l1TokenData + } } - } - - // Callback is used here, so we can add listId to the set of listIds rather than creating a new set everytime - setBridgeTokens(oldBridgeTokens => { - const l1Addresses: string[] = [] - const l2Addresses: string[] = [] - // USDC is not on any token list as it's unbridgeable - // but we still want to detect its balance on user's wallet - if (isNetwork(l2ChainID).isArbitrumOne) { - l2Addresses.push(CommonAddress.ArbitrumOne.USDC) - } - if (isNetwork(l2ChainID).isArbitrumSepolia) { - l2Addresses.push(CommonAddress.ArbitrumSepolia.USDC) - } + // Callback is used here, so we can add listId to the set of listIds rather than creating a new set everytime + setBridgeTokens(oldBridgeTokens => { + const l1Addresses: string[] = [] + const l2Addresses: string[] = [] - for (const tokenAddress in bridgeTokensToAdd) { - const tokenToAdd = bridgeTokensToAdd[tokenAddress] - if (!tokenToAdd) { - return + // USDC is not on any token list as it's unbridgeable + // but we still want to detect its balance on user's wallet + if (isNetwork(l2ChainID).isArbitrumOne) { + l2Addresses.push(CommonAddress.ArbitrumOne.USDC) } - const { address, l2Address } = tokenToAdd - if (address) { - l1Addresses.push(address) + if (isNetwork(l2ChainID).isArbitrumSepolia) { + l2Addresses.push(CommonAddress.ArbitrumSepolia.USDC) } - if (l2Address) { - l2Addresses.push(l2Address) + + for (const tokenAddress in bridgeTokensToAdd) { + const tokenToAdd = bridgeTokensToAdd[tokenAddress] + if (!tokenToAdd) { + return + } + const { address, l2Address } = tokenToAdd + if (address) { + l1Addresses.push(address) + } + if (l2Address) { + l2Addresses.push(l2Address) + } + + // Add the new list id being imported (`listId`) to the existing list ids (from `oldBridgeTokens[address]`) + // Set the result to token added to `bridgeTokens` : `tokenToAdd.listIds` + const oldListIds = + oldBridgeTokens?.[tokenToAdd.address]?.listIds || new Set() + tokenToAdd.listIds = new Set([...oldListIds, listId]) } - // Add the new list id being imported (`listId`) to the existing list ids (from `oldBridgeTokens[address]`) - // Set the result to token added to `bridgeTokens` : `tokenToAdd.listIds` - const oldListIds = - oldBridgeTokens?.[tokenToAdd.address]?.listIds || new Set() - tokenToAdd.listIds = new Set([...oldListIds, listId]) - } + updateErc20L1Balance(l1Addresses) + updateErc20L2Balance(l2Addresses) + + return { + ...oldBridgeTokens, + ...bridgeTokensToAdd + } + }) + }, + [ + l1.network.id, + l1NetworkID, + l2.network.id, + updateErc20L1Balance, + updateErc20L2Balance + ] + ) - updateErc20L1Balance(l1Addresses) - updateErc20L2Balance(l2Addresses) + const addBridgeTokenListToBridge = useCallback( + (bridgeTokenList: BridgeTokenList) => { + fetchTokenListFromURL(bridgeTokenList.url).then( + ({ isValid, data: tokenList }) => { + if (!isValid) return - return { - ...oldBridgeTokens, - ...bridgeTokensToAdd - } - }) - } + addTokensFromList(tokenList!, bridgeTokenList.id) + } + ) + }, + [addTokensFromList] + ) async function addToken(erc20L1orL2Address: string) { let l1Address: string @@ -1004,6 +1036,7 @@ export const useArbTokenBridge = ( addL2NativeToken, addTokensFromList, removeTokensFromList, + addBridgeTokenListToBridge, updateTokenData, approve: approveToken, approveL2: approveTokenL2, diff --git a/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts b/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts index d146fe1fd1..ebe1431fc2 100644 --- a/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/TokenListUtils.ts @@ -8,7 +8,6 @@ import GeminiLogo from '@/images/lists/gemini.png' import CMCLogo from '@/images/lists/cmc.png' import CoinGeckoLogo from '@/images/lists/coinGecko.svg' import ArbitrumLogo from '@/images/lists/ArbitrumLogo.png' -import { ArbTokenBridge } from '../hooks/arbTokenBridge.types' import { ChainId } from './networks' export const SPECIAL_ARBITRUM_TOKEN_TOKEN_LIST_ID = 0 @@ -205,19 +204,6 @@ export const validateTokenList = (tokenList: TokenList) => { return validate(tokenList) } -export const addBridgeTokenListToBridge = ( - bridgeTokenList: BridgeTokenList, - arbTokenBridge: ArbTokenBridge -) => { - fetchTokenListFromURL(bridgeTokenList.url).then( - ({ isValid, data: tokenList }) => { - if (!isValid) return - - arbTokenBridge.token.addTokensFromList(tokenList!, bridgeTokenList.id) - } - ) -} - export async function fetchTokenListFromURL(tokenListURL: string): Promise<{ isValid: boolean data: TokenList | undefined From 8da44c8af39f87f5170e2015a5cb0ef2186ca870 Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 8 Mar 2024 17:23:15 +0000 Subject: [PATCH 19/57] Add condition for non connected user in usGasSummary --- .../src/hooks/TransferPanel/useGasSummary.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts index 62cccba170..82232519d3 100644 --- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts +++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts @@ -96,6 +96,11 @@ export function useGasSummary(): UseGasSummaryResult { const estimateGas = useCallback(async () => { if (!walletAddress) { + setGasSummary({ + status: 'success', + estimatedL1GasFees: 0, + estimatedL2GasFees: 0 + }) return } From 372d448576609fa3a63f749d4048ecfd92d28c74 Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 8 Mar 2024 17:23:29 +0000 Subject: [PATCH 20/57] Show 0 balance for non connected user in TokenRow --- .../src/components/TransferPanel/TokenRow.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx index aae1f86fce..70d90a701b 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx @@ -207,6 +207,10 @@ function useTokenInfo(token: ERC20BridgeToken | null) { : ethL2Balance } + if (!walletAddress) { + return constants.Zero + } + return isDepositMode ? ethL1Balance : ethL2Balance } @@ -226,7 +230,8 @@ function useTokenInfo(token: ERC20BridgeToken | null) { erc20L2Balances, isDepositMode, nativeCurrency, - token + token, + walletAddress ]) const isArbitrumToken = useMemo(() => { From cac297df9fbc8fdff0af71b106082500fe511c52 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 13:43:33 +0000 Subject: [PATCH 21/57] Fix e2e tests --- packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts | 2 +- packages/arb-token-bridge-ui/tests/support/commands.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts index 57d16befda..922939f029 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts @@ -23,7 +23,7 @@ describe('Login Account', () => { cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() - cy.findByText('Connect a Wallet').should('be.visible') + cy.findByText('Connect Wallet').should('be.visible').click() cy.findByText('MetaMask').should('be.visible') }) diff --git a/packages/arb-token-bridge-ui/tests/support/commands.ts b/packages/arb-token-bridge-ui/tests/support/commands.ts index 80cb975416..b20559815f 100644 --- a/packages/arb-token-bridge-ui/tests/support/commands.ts +++ b/packages/arb-token-bridge-ui/tests/support/commands.ts @@ -107,7 +107,7 @@ export const connectToApp = () => { cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() - cy.findByText('Connect a Wallet').should('be.visible') + cy.findByText('Connect Wallet').should('be.visible').click() cy.findByText('MetaMask').should('be.visible').click() } From 4d1d3a09f6cd506b9671118e22861206dd2ffab5 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 14:53:05 +0000 Subject: [PATCH 22/57] Record e2e --- packages/arb-token-bridge-ui/tests/e2e/specfiles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json index 294ed5769a..247c6732de 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json +++ b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json @@ -2,7 +2,7 @@ { "name": "Login and balance check", "file": "tests/e2e/specs/**/login.cy.{js,jsx,ts,tsx}", - "recordVideo": "false" + "recordVideo": "true" }, { "name": "Deposit ETH", From ccaa45ba2f6c04eaa5e38ae6012d9077a154825f Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 16:43:26 +0100 Subject: [PATCH 23/57] Set URL with query param in cy.visit --- packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts index 922939f029..07515320d8 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts @@ -19,7 +19,9 @@ describe('Login Account', () => { }) it('should show connect wallet if not logged in', () => { - cy.visit('/') + cy.visit( + '/?destinationChain=custom-localhost&sourceChain=arbitrum-localhost' + ) cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() From ad56e666976a049b4260daee3b022a3d684f9bb9 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 16:44:53 +0100 Subject: [PATCH 24/57] Pass query param in login --- packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts index 07515320d8..87b992d1f5 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts @@ -30,7 +30,13 @@ describe('Login Account', () => { }) it('should connect wallet using MetaMask and display L1 and L2 balances', () => { - cy.login({ networkType: 'L1' }) + cy.login({ + networkType: 'L1', + query: { + destinationChain: 'custom-localhost', + sourceChain: 'arbitrum-localhost' + } + }) // Balance: is in a different element so we check for siblings cy.findByText(l1ETHbal) .should('be.visible') From bd63a10f7db442de96d1f120221126710625f4ad Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 16:55:18 +0100 Subject: [PATCH 25/57] Remove query param, fix connect wallet getter --- .../tests/e2e/specs/login.cy.ts | 14 +++----------- .../arb-token-bridge-ui/tests/support/commands.ts | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts index 87b992d1f5..2e774097d2 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts @@ -19,24 +19,16 @@ describe('Login Account', () => { }) it('should show connect wallet if not logged in', () => { - cy.visit( - '/?destinationChain=custom-localhost&sourceChain=arbitrum-localhost' - ) + cy.visit('/') cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() - cy.findByText('Connect Wallet').should('be.visible').click() + cy.findAllByText('Connect Wallet').first().should('be.visible').click() cy.findByText('MetaMask').should('be.visible') }) it('should connect wallet using MetaMask and display L1 and L2 balances', () => { - cy.login({ - networkType: 'L1', - query: { - destinationChain: 'custom-localhost', - sourceChain: 'arbitrum-localhost' - } - }) + cy.login({ networkType: 'L1' }) // Balance: is in a different element so we check for siblings cy.findByText(l1ETHbal) .should('be.visible') diff --git a/packages/arb-token-bridge-ui/tests/support/commands.ts b/packages/arb-token-bridge-ui/tests/support/commands.ts index b20559815f..dba5776d3b 100644 --- a/packages/arb-token-bridge-ui/tests/support/commands.ts +++ b/packages/arb-token-bridge-ui/tests/support/commands.ts @@ -107,7 +107,7 @@ export const connectToApp = () => { cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() - cy.findByText('Connect Wallet').should('be.visible').click() + cy.findAllByText('Connect Wallet').first().should('be.visible').click() cy.findByText('MetaMask').should('be.visible').click() } From d48713237a77d5b381672ebfcf405f86ae0c4bd0 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 11 Mar 2024 17:07:58 +0100 Subject: [PATCH 26/57] Remove video record --- packages/arb-token-bridge-ui/tests/e2e/specfiles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json index 247c6732de..294ed5769a 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json +++ b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json @@ -2,7 +2,7 @@ { "name": "Login and balance check", "file": "tests/e2e/specs/**/login.cy.{js,jsx,ts,tsx}", - "recordVideo": "true" + "recordVideo": "false" }, { "name": "Deposit ETH", From 17fcc0e71ca64da5a65b994d019192a0f42fdfbd Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 13:36:56 +0000 Subject: [PATCH 27/57] Fix import token test --- .../tests/e2e/cypress.d.ts | 8 +------ .../tests/e2e/specs/importToken.cy.ts | 2 +- .../tests/support/commands.ts | 14 +++++++---- .../tests/support/common.ts | 24 ++++++++++++------- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts b/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts index 991c8c5a42..ee56e6940f 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts @@ -9,7 +9,6 @@ import { fundUserUsdcTestnet, fundUserWalletEth } from '../support/commands' -import { NetworkType, NetworkName } from '../support/common' declare global { namespace Cypress { @@ -20,12 +19,7 @@ declare global { */ connectToApp(): typeof connectToApp // eslint-disable-next-line no-unused-vars - login(options: { - networkType: NetworkType - networkName?: NetworkName - url?: string - query?: { [s: string]: string } - }): typeof login + login: typeof login logout(): typeof logout openTransactionsPanel(): typeof openTransactionsPanel resetCctpAllowance: typeof resetCctpAllowance diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts index ccb7effdf4..74dfdf354d 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts @@ -22,7 +22,7 @@ describe('Import token', () => { }) context('User uses L1 address', () => { it('should import token through its L1 address', () => { - cy.login({ networkType: 'L1' }) + cy.login({ networkType: 'L1', connectMetamask: false }) importTokenThroughUI(ERC20TokenAddressL1) // Select the ERC-20 token diff --git a/packages/arb-token-bridge-ui/tests/support/commands.ts b/packages/arb-token-bridge-ui/tests/support/commands.ts index dba5776d3b..9d3a8bf533 100644 --- a/packages/arb-token-bridge-ui/tests/support/commands.ts +++ b/packages/arb-token-bridge-ui/tests/support/commands.ts @@ -38,12 +38,14 @@ export function login({ networkType, networkName, url, - query + query, + connectMetamask = true }: { networkType: NetworkType networkName?: NetworkName url?: string query?: { [s: string]: string } + connectMetamask?: boolean }) { // if networkName is not specified we connect to default network from config const network = @@ -53,7 +55,7 @@ export function login({ function _startWebApp() { const sourceChain = networkNameWithDefault === 'mainnet' ? 'ethereum' : networkNameWithDefault - startWebApp(url, { ...query, sourceChain }) + startWebApp(url, { query: { ...query, sourceChain }, connectMetamask }) } shouldChangeNetwork(networkNameWithDefault).then(changeNetwork => { @@ -102,13 +104,15 @@ export const logout = () => { }) } -export const connectToApp = () => { +export const connectToApp = (connectMetamask: boolean) => { // initial modal prompts which come in the web-app cy.findByText(/Agree to Terms and Continue/i) .should('be.visible') .click() - cy.findAllByText('Connect Wallet').first().should('be.visible').click() - cy.findByText('MetaMask').should('be.visible').click() + if (connectMetamask) { + cy.findAllByText('Connect Wallet').first().should('be.visible').click() + cy.findByText('MetaMask').should('be.visible').click() + } } export const openTransactionsPanel = () => { diff --git a/packages/arb-token-bridge-ui/tests/support/common.ts b/packages/arb-token-bridge-ui/tests/support/common.ts index afa6045b87..35111ed7cb 100644 --- a/packages/arb-token-bridge-ui/tests/support/common.ts +++ b/packages/arb-token-bridge-ui/tests/support/common.ts @@ -136,24 +136,32 @@ export const acceptMetamaskAccess = () => { }) } -export const startWebApp = (url = '/', qs: { [s: string]: string } = {}) => { +export const startWebApp = ( + url = '/', + options: { + query: { [s: string]: string } + connectMetamask: boolean + } +) => { // once all the metamask setup is done, we can start the actual web-app for testing // clear local storage for terms to always have it pop up cy.clearLocalStorage('arbitrum:bridge:tos-v2') cy.visit(url, { - qs + qs: options.query }) if (Cypress.currentRetry > 0) { // ensures we don't test with the same state that could have caused the test to fail cy.reload(true) } cy.connectToApp() - cy.task('getWalletConnectedToDapp').then(connected => { - if (!connected) { - acceptMetamaskAccess() - cy.task('setWalletConnectedToDapp') - } - }) + if (options.connectMetamask) { + cy.task('getWalletConnectedToDapp').then(connected => { + if (!connected) { + acceptMetamaskAccess() + cy.task('setWalletConnectedToDapp') + } + }) + } } export const visitAfterSomeDelay = ( From 185f985d6a4f548ec55762071405a3a62744d280 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 14:10:47 +0000 Subject: [PATCH 28/57] Rework type --- .../arb-token-bridge-ui/tests/e2e/cypress.d.ts | 18 ++++++------------ .../tests/support/common.ts | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts b/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts index 668f0cf495..099e69bd82 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/cypress.d.ts @@ -19,23 +19,17 @@ declare global { * Custom command to connect MetaMask to the UI. * @example cy.login() */ - connectToApp(): typeof connectToApp + connectToApp: typeof connectToApp // eslint-disable-next-line no-unused-vars login: typeof login - logout(): typeof logout - openTransactionsPanel(): typeof openTransactionsPanel + logout: typeof logout + openTransactionsPanel: typeof openTransactionsPanel resetCctpAllowance: typeof resetCctpAllowance fundUserUsdcTestnet: typeof fundUserUsdcTestnet fundUserWalletEth: typeof fundUserWalletEth - typeRecursively(text: string): Chainable> - searchAndSelectToken({ - tokenName, - tokenAddress - }: { - tokenName: string - tokenAddress: string - }): typeof searchAndSelectToken - fillCustomDestinationAddress(): typeof fillCustomDestinationAddress + typeRecursively: Chainable> + searchAndSelectToken: typeof searchAndSelectToken + fillCustomDestinationAddress: typeof fillCustomDestinationAddress } } } diff --git a/packages/arb-token-bridge-ui/tests/support/common.ts b/packages/arb-token-bridge-ui/tests/support/common.ts index 35111ed7cb..c43b2ee631 100644 --- a/packages/arb-token-bridge-ui/tests/support/common.ts +++ b/packages/arb-token-bridge-ui/tests/support/common.ts @@ -153,7 +153,7 @@ export const startWebApp = ( // ensures we don't test with the same state that could have caused the test to fail cy.reload(true) } - cy.connectToApp() + cy.connectToApp(options.connectMetamask) if (options.connectMetamask) { cy.task('getWalletConnectedToDapp').then(connected => { if (!connected) { From cff40a4bbfcc05f7cdc2b338b2f53d83c0f8e6e9 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 18:31:14 +0000 Subject: [PATCH 29/57] Remove cypress logs --- .../arb-token-bridge-ui/tests/support/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/arb-token-bridge-ui/tests/support/index.ts b/packages/arb-token-bridge-ui/tests/support/index.ts index cb65bc4a25..fdefb3d98c 100644 --- a/packages/arb-token-bridge-ui/tests/support/index.ts +++ b/packages/arb-token-bridge-ui/tests/support/index.ts @@ -13,7 +13,19 @@ Cypress.Keyboard.defaults({ keystrokeDelay: 150 }) -logCollector() +const options = { + // Log console output only + collectTypes: [ + 'cons:log', + 'cons:info', + 'cons:warn', + 'cons:error', + 'cy:command', + 'cy:log' + ] +} as const + +logCollector(options) before(() => { // connect to goerli to avoid connecting to localhost twice and failing From 1fb780b1d5f1097c854460d05731682609949fe3 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 18:31:23 +0000 Subject: [PATCH 30/57] Record failling tests --- packages/arb-token-bridge-ui/tests/e2e/specfiles.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json index 294ed5769a..e3b114640e 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specfiles.json +++ b/packages/arb-token-bridge-ui/tests/e2e/specfiles.json @@ -17,17 +17,17 @@ { "name": "Deposit ERC20", "file": "tests/e2e/specs/**/depositERC20.cy.{js,jsx,ts,tsx}", - "recordVideo": "false" + "recordVideo": "true" }, { "name": "Withdraw ERC20", "file": "tests/e2e/specs/**/withdrawERC20.cy.{js,jsx,ts,tsx}", - "recordVideo": "false" + "recordVideo": "true" }, { "name": "TX history", "file": "tests/e2e/specs/**/txHistory.cy.{js,jsx,ts,tsx}", - "recordVideo": "false" + "recordVideo": "true" }, { "name": "Approve ERC20", @@ -37,7 +37,7 @@ { "name": "Import test ERC20", "file": "tests/e2e/specs/**/importToken.cy.{js,jsx,ts,tsx}", - "recordVideo": "false" + "recordVideo": "true" }, { "name": "Read classic deposits", From 9c6386f853cdb025e5babf52519045c3b5287a76 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 18:31:30 +0000 Subject: [PATCH 31/57] WIP tx history --- .../tests/e2e/specs/txHistory.cy.ts | 177 +++++++++--------- 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/txHistory.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/txHistory.cy.ts index 86ba1edf99..db2aec8759 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/txHistory.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/txHistory.cy.ts @@ -2,104 +2,107 @@ const DEPOSIT_ROW_IDENTIFIER = /deposit-row-*/i const CLAIMABLE_ROW_IDENTIFIER = /claimable-row-*/i describe('Transaction History', () => { - it('should successfully open and use pending transactions panel', () => { - cy.login({ - networkType: 'L1', - networkName: 'goerli', - query: { - sourceChain: 'goerli', - destinationChain: 'arbitrum-goerli' - } - }) - // open tx history panel - context('open transactions history panel', () => { - cy.openTransactionsPanel() - }) + context('User has transactions', () => { + it('should successfully open and use pending transactions panel', () => { + cy.login({ + networkType: 'L1', + networkName: 'goerli', + query: { + sourceChain: 'goerli', + destinationChain: 'arbitrum-goerli' + } + }) + // open tx history panel + context('open transactions history panel', () => { + cy.openTransactionsPanel() + }) - context('pending tab should be selected', () => { - cy.findByRole('tab', { name: 'show pending transactions' }) - .should('be.visible') - .should('have.attr', 'data-headlessui-state') - .and('equal', 'selected') - }) + context('pending tab should be selected', () => { + cy.findByRole('tab', { name: 'show pending transactions' }) + .should('be.visible') + .should('have.attr', 'data-headlessui-state') + .and('equal', 'selected') + }) - // We load 3 transactions in a batch, and only we load more only if these transactions happened last month - // Our 3 most recent transactions are settled transactions. - // That means 'Load more' button click is required to fetch our pending transaction. - cy.waitUntil( - () => cy.findByRole('button', { name: 'Load more' }).should('be.visible'), - { - errorMsg: 'Did not find Load more button.', - timeout: 30_000, - interval: 500 - } - ).then(btn => { - cy.wrap(btn).click() - }) + // We load 3 transactions in a batch, and only we load more only if these transactions happened last month + // Our 3 most recent transactions are settled transactions. + // That means 'Load more' button click is required to fetch our pending transaction. + cy.waitUntil( + () => + cy.findByRole('button', { name: 'Load more' }).should('be.visible'), + { + errorMsg: 'Did not find Load more button.', + timeout: 30_000, + interval: 500 + } + ).then(btn => { + cy.wrap(btn).click() + }) - // wait for transactions to fetch - cy.waitUntil( - () => - cy - .findByText(/Showing \d+ pending transactions made in/) - .should('be.visible'), - { - errorMsg: 'Failed to fetch transactions.', - timeout: 30_000, - interval: 500 - } - ).then(() => { - const numberOfWithdrawals = cy - .findAllByTestId(CLAIMABLE_ROW_IDENTIFIER) - .its('length') + // wait for transactions to fetch + cy.waitUntil( + () => + cy + .findByText(/Showing \d+ pending transactions made in/) + .should('be.visible'), + { + errorMsg: 'Failed to fetch transactions.', + timeout: 30_000, + interval: 500 + } + ).then(() => { + const numberOfWithdrawals = cy + .findAllByTestId(CLAIMABLE_ROW_IDENTIFIER) + .its('length') - numberOfWithdrawals.should('be.gt', 0) + numberOfWithdrawals.should('be.gt', 0) + }) }) - }) - it('should successfully open and use settled transactions panel', () => { - cy.login({ - networkType: 'L1', - networkName: 'goerli', - query: { - sourceChain: 'goerli', - destinationChain: 'arbitrum-goerli' - } - }) - context('open transactions history panel', () => { - cy.openTransactionsPanel() - }) + it('should successfully open and use settled transactions panel', () => { + cy.login({ + networkType: 'L1', + networkName: 'goerli', + query: { + sourceChain: 'goerli', + destinationChain: 'arbitrum-goerli' + } + }) + context('open transactions history panel', () => { + cy.openTransactionsPanel() + }) - context('settled tab should be selected after click', () => { - cy.findByRole('tab', { name: 'show settled transactions' }) - .should('be.visible') - .click() - .should('have.attr', 'data-headlessui-state') - .and('equal', 'selected') - }) + context('settled tab should be selected after click', () => { + cy.findByRole('tab', { name: 'show settled transactions' }) + .should('be.visible') + .click() + .should('have.attr', 'data-headlessui-state') + .and('equal', 'selected') + }) - cy.waitUntil( - () => - cy - .findByText(/Showing \d+ settled transactions made in/) - .should('be.visible'), - { - errorMsg: 'Failed to fetch transactions.', - timeout: 30_000, - interval: 500 - } - ).then(() => { - const numberOfWithdrawals = cy - .findAllByTestId(CLAIMABLE_ROW_IDENTIFIER) - .its('length') + cy.waitUntil( + () => + cy + .findByText(/Showing \d+ settled transactions made in/) + .should('be.visible'), + { + errorMsg: 'Failed to fetch transactions.', + timeout: 30_000, + interval: 500 + } + ).then(() => { + const numberOfWithdrawals = cy + .findAllByTestId(CLAIMABLE_ROW_IDENTIFIER) + .its('length') - numberOfWithdrawals.should('be.gt', 0) + numberOfWithdrawals.should('be.gt', 0) - const numberOfDeposits = cy - .findAllByTestId(DEPOSIT_ROW_IDENTIFIER) - .its('length') + const numberOfDeposits = cy + .findAllByTestId(DEPOSIT_ROW_IDENTIFIER) + .its('length') - numberOfDeposits.should('be.gt', 0) + numberOfDeposits.should('be.gt', 0) + }) }) }) }) From fa6956b18d80b38211f0d9e3af445a634ba17077 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 21:19:16 +0100 Subject: [PATCH 32/57] Fix import token test --- .../src/components/TransferPanel/TokenRow.tsx | 4 ++++ .../src/components/TransferPanel/TokenSearch.tsx | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx index 70d90a701b..fbead6fe31 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx @@ -200,6 +200,10 @@ function useTokenInfo(token: ERC20BridgeToken | null) { }, [token, nativeCurrency]) const balance = useMemo(() => { + if (!walletAddress) { + return constants.Zero + } + if (!token) { if (nativeCurrency.isCustom) { return isDepositMode diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx index 8da3ed6517..de6aeeac26 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenSearch.tsx @@ -347,10 +347,6 @@ function TokensPanel({ ]) const storeNewToken = async () => { - if (!walletAddress) { - return - } - let error = 'Token not found on this network.' let isSuccessful = false From a3e5a46c113f4798cfa2a90197bb44a4b8b44200 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 21:51:37 +0100 Subject: [PATCH 33/57] Add minimum amount in e2e tests --- .../tests/e2e/specs/depositERC20.cy.ts | 8 ++++++-- .../tests/e2e/specs/withdrawERC20.cy.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/depositERC20.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/depositERC20.cy.ts index 90bdd4e51d..0df2b2e970 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/depositERC20.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/depositERC20.cy.ts @@ -42,7 +42,9 @@ describe('Deposit ERC20 Token', () => { }) it('should deposit ERC-20 successfully to the same address', () => { - const ERC20AmountToSend = Number((Math.random() * 0.001).toFixed(5)) // randomize the amount to be sure that previous transactions are not checked in e2e + const ERC20AmountToSend = Number( + (Math.random() * 0.001 + 0.001).toFixed(5) + ) // randomize the amount to be sure that previous transactions are not checked in e2e cy.login({ networkType: 'L1' }) context('should add a new token', () => { @@ -103,7 +105,9 @@ describe('Deposit ERC20 Token', () => { }) it('should deposit ERC-20 to custom destination address successfully', () => { - const ERC20AmountToSend = Number((Math.random() * 0.001).toFixed(5)) // randomize the amount to be sure that previous transactions are not checked in e2e + const ERC20AmountToSend = Number( + (Math.random() * 0.001 + 0.001).toFixed(5) + ) // randomize the amount to be sure that previous transactions are not checked in e2e cy.login({ networkType: 'L1' }) context('should add a new token', () => { diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/withdrawERC20.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/withdrawERC20.cy.ts index 7b91e3b2d2..cbecc5246a 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/withdrawERC20.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/withdrawERC20.cy.ts @@ -52,7 +52,9 @@ describe('Withdraw ERC20 Token', () => { }) it('should withdraw ERC-20 to the same address successfully', () => { - const ERC20AmountToSend = Number((Math.random() * 0.001).toFixed(5)) // randomize the amount to be sure that previous transactions are not checked in e2e + const ERC20AmountToSend = Number( + (Math.random() * 0.001 + 0.001).toFixed(5) + ) // randomize the amount to be sure that previous transactions are not checked in e2e cy.login({ networkType: 'L2' }) context('should add ERC-20 correctly', () => { @@ -132,7 +134,9 @@ describe('Withdraw ERC20 Token', () => { }) it('should withdraw ERC-20 to custom destination address successfully', () => { - const ERC20AmountToSend = Number((Math.random() * 0.001).toFixed(5)) // randomize the amount to be sure that previous transactions are not checked in e2e + const ERC20AmountToSend = Number( + (Math.random() * 0.001 + 0.001).toFixed(5) + ) // randomize the amount to be sure that previous transactions are not checked in e2e cy.login({ networkType: 'L2' }) context('should add a new token', () => { From b081628c554ba731f07ac0dd64cbd19c0a6b1cf2 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 21:51:45 +0100 Subject: [PATCH 34/57] Don't connect metamask in importToken test --- .../tests/e2e/specs/importToken.cy.ts | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts index 74dfdf354d..a57bfedcd6 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts @@ -43,7 +43,7 @@ describe('Import token', () => { context('User uses L2 address', () => { it('should import token through its L2 address', () => { - cy.login({ networkType: 'L1' }) + cy.login({ networkType: 'L1', connectMetamask: false }) importTokenThroughUI(ERC20TokenAddressL2) // Select the ERC-20 token @@ -60,7 +60,7 @@ describe('Import token', () => { context('User uses invalid address', () => { it('should display an error message after invalid input', () => { - cy.login({ networkType: 'L1' }) + cy.login({ networkType: 'L1', connectMetamask: false }) importTokenThroughUI(invalidTokenAddress) // Error message is displayed @@ -73,7 +73,8 @@ describe('Import token', () => { // we don't have the token list locally so we test on mainnet cy.login({ networkType: 'L1', - networkName: 'mainnet' + networkName: 'mainnet', + connectMetamask: false }) cy.findByRole('button', { name: 'Select Token' }) @@ -100,7 +101,8 @@ describe('Import token', () => { // we don't have the token list locally so we test on mainnet cy.login({ networkType: 'L1', - networkName: 'mainnet' + networkName: 'mainnet', + connectMetamask: false }) cy.findByRole('button', { name: 'Select Token' }) @@ -148,7 +150,7 @@ describe('Import token', () => { ERC20TokenAddressL1.length - 1 ) - cy.login({ networkType: 'L1' }) + cy.login({ networkType: 'L1', connectMetamask: false }) cy.findByRole('button', { name: 'Select Token' }) .should('be.visible') .should('have.text', 'ETH') @@ -189,7 +191,8 @@ describe('Import token', () => { url: '/', query: { token: ERC20TokenAddressL1 - } + }, + connectMetamask: false }) // waiting for metamask notification to disappear @@ -206,9 +209,7 @@ describe('Import token', () => { // Import token cy.findByRole('button', { name: 'Import token' }) .should('be.visible') - .trigger('click', { - force: true - }) + .trigger('click') .then(() => { cy.findByRole('button', { name: 'Select Token' }) .should('be.visible') @@ -229,7 +230,8 @@ describe('Import token', () => { url: '/', query: { token: ERC20TokenAddressL2 - } + }, + connectMetamask: false }) // waiting for metamask notification to disappear @@ -268,7 +270,8 @@ describe('Import token', () => { url: '/', query: { token: invalidTokenAddress - } + }, + connectMetamask: false }) visitAfterSomeDelay('/', { @@ -285,9 +288,7 @@ describe('Import token', () => { // Close modal cy.findByRole('button', { name: 'Dialog Cancel' }) .should('be.visible') - .trigger('click', { - force: true - }) + .trigger('click') .then(() => { cy.findByRole('button', { name: 'Select Token' }) .should('be.visible') From b155e33a448ba2bc06fd5da1382d1005a12ffba5 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 21:34:09 +0000 Subject: [PATCH 35/57] Remove unecessary wait --- .../arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts index a57bfedcd6..bbc7376b55 100644 --- a/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts +++ b/packages/arb-token-bridge-ui/tests/e2e/specs/importToken.cy.ts @@ -195,10 +195,6 @@ describe('Import token', () => { connectMetamask: false }) - // waiting for metamask notification to disappear - // eslint-disable-next-line - cy.wait(3000) - // Modal is displayed cy.get('h2') .contains(/import unknown token/i) @@ -234,10 +230,6 @@ describe('Import token', () => { connectMetamask: false }) - // waiting for metamask notification to disappear - // eslint-disable-next-line - cy.wait(3000) - // Modal is displayed cy.get('h2') .contains(/import unknown token/i) From 9e2cbf55b4690900bdb601d491d19fd0653e7692 Mon Sep 17 00:00:00 2001 From: Christophe Date: Wed, 13 Mar 2024 21:40:24 +0000 Subject: [PATCH 36/57] Update connect wallet button color --- .../src/components/TransferPanel/TransferPanel.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index d5ea63396e..786d6b470a 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -1094,6 +1094,10 @@ export function TransferPanel() {