diff --git a/packages/arb-token-bridge-ui/src/components/TransactionHistory/TransactionsTableRowAction.tsx b/packages/arb-token-bridge-ui/src/components/TransactionHistory/TransactionsTableRowAction.tsx
index 629aec8aaa..1b6bce2c75 100644
--- a/packages/arb-token-bridge-ui/src/components/TransactionHistory/TransactionsTableRowAction.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransactionHistory/TransactionsTableRowAction.tsx
@@ -1,4 +1,6 @@
import { useCallback } from 'react'
+import { useAccount, useNetwork } from 'wagmi'
+
import { GET_HELP_LINK } from '../../constants'
import { useClaimWithdrawal } from '../../hooks/useClaimWithdrawal'
import { useClaimCctp } from '../../state/cctpState'
@@ -13,7 +15,6 @@ import { getNetworkName } from '../../util/networks'
import { errorToast } from '../common/atoms/Toast'
import { Button } from '../common/Button'
import { useSwitchNetworkWithConfig } from '../../hooks/useSwitchNetworkWithConfig'
-import { useNetwork } from 'wagmi'
import { isDepositReadyToRedeem } from '../../state/app/utils'
import { useRedeemRetryable } from '../../hooks/useRedeemRetryable'
import { TransferCountdown } from '../common/TransferCountdown'
@@ -23,6 +24,7 @@ import { useRedeemTeleporter } from '../../hooks/useRedeemTeleporter'
import { sanitizeTokenSymbol } from '../../util/TokenUtils'
import { formatAmount } from '../../util/NumberUtils'
import { useTransactionHistoryAddressStore } from './TransactionHistorySearchBar'
+import { Tooltip } from '../common/Tooltip'
export function TransactionsTableRowAction({
tx,
@@ -33,10 +35,17 @@ export function TransactionsTableRowAction({
isError: boolean
type: 'deposits' | 'withdrawals'
}) {
+ const { address: connectedAddress } = useAccount()
const { chain } = useNetwork()
const { switchNetworkAsync } = useSwitchNetworkWithConfig()
const networkName = getNetworkName(chain?.id ?? 0)
- const { sanitizedAddress } = useTransactionHistoryAddressStore()
+ const { sanitizedAddress: searchedAddress } =
+ useTransactionHistoryAddressStore()
+
+ const isViewingAnotherAddress =
+ connectedAddress &&
+ searchedAddress &&
+ connectedAddress.toLowerCase() !== searchedAddress.toLowerCase()
const tokenSymbol = sanitizeTokenSymbol(tx.asset, {
erc20L1Address: tx.tokenAddress,
@@ -47,10 +56,10 @@ export function TransactionsTableRowAction({
const { claim: claimCctp, isClaiming: isClaimingCctp } = useClaimCctp(tx)
const { redeem, isRedeeming: isRetryableRedeeming } = useRedeemRetryable(
tx,
- sanitizedAddress
+ searchedAddress
)
const { redeem: teleporterRedeem, isRedeeming: isTeleporterRedeeming } =
- useRedeemTeleporter(tx, sanitizedAddress)
+ useRedeemTeleporter(tx, searchedAddress)
const isRedeeming = isRetryableRedeeming || isTeleporterRedeeming
@@ -162,16 +171,25 @@ export function TransactionsTableRowAction({
return isClaiming || isClaimingCctp ? (
Claiming...
) : (
-
+
+
)
}
diff --git a/packages/arb-token-bridge-ui/src/hooks/useClaimWithdrawal.ts b/packages/arb-token-bridge-ui/src/hooks/useClaimWithdrawal.ts
index f174dc8fb3..be9b21769d 100644
--- a/packages/arb-token-bridge-ui/src/hooks/useClaimWithdrawal.ts
+++ b/packages/arb-token-bridge-ui/src/hooks/useClaimWithdrawal.ts
@@ -15,6 +15,7 @@ import { fetchErc20Data } from '../util/TokenUtils'
import { fetchNativeCurrency } from './useNativeCurrency'
import { getProviderForChainId } from '@/token-bridge-sdk/utils'
import { captureSentryErrorWithExtraData } from '../util/SentryUtils'
+import { useTransactionHistoryAddressStore } from '../components/TransactionHistory/TransactionHistorySearchBar'
export type UseClaimWithdrawalResult = {
claim: () => Promise
@@ -28,8 +29,11 @@ export function useClaimWithdrawal(
app: { arbTokenBridge }
} = useAppState()
const { address } = useAccount()
+ const { sanitizedAddress } = useTransactionHistoryAddressStore()
const { data: signer } = useSigner({ chainId: tx.parentChainId })
- const { updatePendingTransaction } = useTransactionHistory(address)
+ const { updatePendingTransaction } = useTransactionHistory(
+ sanitizedAddress ?? address
+ )
const [isClaiming, setIsClaiming] = useState(false)
const claim = useCallback(async () => {
diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts
index ab8ce17bfb..ff4ca58a60 100644
--- a/packages/arb-token-bridge-ui/src/util/networks.ts
+++ b/packages/arb-token-bridge-ui/src/util/networks.ts
@@ -1,4 +1,4 @@
-import { StaticJsonRpcProvider } from '@ethersproject/providers'
+import { Provider, StaticJsonRpcProvider } from '@ethersproject/providers'
import {
ArbitrumNetwork,
getChildrenForNetwork,
@@ -11,6 +11,7 @@ import { loadEnvironmentVariableWithFallback } from './index'
import { getBridgeUiConfigForChain } from './bridgeUiConfig'
import { chainIdToInfuraUrl } from './infura'
import { fetchErc20Data } from './TokenUtils'
+import { orbitChains } from './orbitChainsList'
export enum ChainId {
// L1
@@ -581,6 +582,16 @@ export function getSupportedChainIds({
})
}
+export function isAlchemyChain(chainId: number) {
+ const chain = orbitChains[chainId]
+
+ if (typeof chain === 'undefined') {
+ return false
+ }
+
+ return chain.rpcUrl.toLowerCase().includes('alchemy.com')
+}
+
export function mapCustomChainToNetworkData(chain: ChainWithRpcUrl) {
// custom chain details need to be added to various objects to make it work with the UI
//
diff --git a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
index 69ca450659..ba4db224dd 100644
--- a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
+++ b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
@@ -435,7 +435,8 @@
"name": "SX Network",
"symbol": "SX",
"logoUrl": "/images/sxTokenLogo.png"
- }
+ },
+ "fastWithdrawalTime": 21600000
}
},
{
diff --git a/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts b/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
index 4b748a2080..d32c467a51 100644
--- a/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
+++ b/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
@@ -148,14 +148,13 @@ export function getProps(targetChainKey: string | null) {
chains
})
+ wallets[0]?.wallets.push(okxWallet({ chains, projectId }))
+
const connectors = connectorsForWallets([
...wallets,
{
groupName: 'More',
- wallets: [
- trustWallet({ chains, projectId }),
- okxWallet({ chains, projectId })
- ]
+ wallets: [trustWallet({ chains, projectId })]
}
])
diff --git a/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts
index 5087788d3c..3e421ca077 100644
--- a/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts
+++ b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts
@@ -1,41 +1,25 @@
import { constants } from 'ethers'
import { Provider, BlockTag } from '@ethersproject/providers'
-import { Erc20Bridger, getArbitrumNetwork } from '@arbitrum/sdk'
+import { Erc20Bridger } from '@arbitrum/sdk'
import {
fetchTokenWithdrawalsFromEventLogs,
FetchTokenWithdrawalsFromEventLogsParams
} from './fetchTokenWithdrawalsFromEventLogs'
-import { getNonce } from '../AddressUtils'
-import { fetchL2Gateways } from '../fetchL2Gateways'
-import { backOff, wait } from '../ExponentialBackoffUtils'
-async function getGateways(provider: Provider): Promise<{
- standardGateway: string
- wethGateway: string
- customGateway: string
- otherGateways: string[]
-}> {
- const network = await getArbitrumNetwork(provider)
-
- const standardGateway = network.tokenBridge?.childErc20Gateway
- const customGateway = network.tokenBridge?.childCustomGateway
- const wethGateway = network.tokenBridge?.childWethGateway
- const otherGateways = await fetchL2Gateways(provider)
-
- return {
- standardGateway: standardGateway ?? constants.AddressZero,
- wethGateway: wethGateway ?? constants.AddressZero,
- customGateway: customGateway ?? constants.AddressZero,
- otherGateways
- }
-}
+import { backOff, wait } from '../ExponentialBackoffUtils'
-type TokenWithdrawalQuery = {
+type FetchTokenWithdrawalsFromEventLogsQuery = {
params: FetchTokenWithdrawalsFromEventLogsParams
priority: number
}
+export type Query = {
+ sender?: string
+ receiver?: string
+ gateways?: string[]
+}
+
export type FetchTokenWithdrawalsFromEventLogsSequentiallyParams = {
sender?: string
receiver?: string
@@ -43,9 +27,10 @@ export type FetchTokenWithdrawalsFromEventLogsSequentiallyParams = {
fromBlock?: BlockTag
toBlock?: BlockTag
/**
- * How long to delay in-between queries of different priority.
+ * How long to delay in-between queries of different priority. Defaults to 0.
*/
delayMs?: number
+ queries: Query[]
}
export type FetchTokenWithdrawalsFromEventLogsSequentiallyResult = Awaited<
@@ -53,28 +38,24 @@ export type FetchTokenWithdrawalsFromEventLogsSequentiallyResult = Awaited<
>
export async function fetchTokenWithdrawalsFromEventLogsSequentially({
- sender,
- receiver,
provider,
fromBlock = 0,
toBlock = 'latest',
- delayMs = 2_000
+ delayMs = 0,
+ queries: queriesProp
}: FetchTokenWithdrawalsFromEventLogsSequentiallyParams): Promise {
// keep track of priority; increment as queries are added
let priority = 0
+
// keep track of queries
- const queries: TokenWithdrawalQuery[] = []
+ const queries: FetchTokenWithdrawalsFromEventLogsQuery[] = []
// helper function to reuse common params
function buildQueryParams({
sender,
receiver,
gateways = []
- }: {
- sender?: string
- receiver?: string
- gateways?: string[]
- }): TokenWithdrawalQuery['params'] {
+ }: Query): FetchTokenWithdrawalsFromEventLogsQuery['params'] {
return {
sender,
receiver,
@@ -86,7 +67,7 @@ export async function fetchTokenWithdrawalsFromEventLogsSequentially({
}
// for sanitizing, adding queries and incrementing priority
- function addQuery(params: TokenWithdrawalQuery['params']) {
+ function addQuery(params: FetchTokenWithdrawalsFromEventLogsQuery['params']) {
const gateways = params.l2GatewayAddresses ?? []
const gatewaysSanitized = gateways.filter(g => g !== constants.AddressZero)
@@ -100,22 +81,9 @@ export async function fetchTokenWithdrawalsFromEventLogsSequentially({
})
}
- const gateways = await getGateways(provider)
- const senderNonce = await backOff(() => getNonce(sender, { provider }))
-
- // sender queries; only add if nonce > 0
- if (senderNonce > 0) {
- addQuery(buildQueryParams({ sender, gateways: [gateways.standardGateway] }))
- addQuery(buildQueryParams({ sender, gateways: [gateways.wethGateway] }))
- addQuery(buildQueryParams({ sender, gateways: [gateways.customGateway] }))
- addQuery(buildQueryParams({ sender, gateways: gateways.otherGateways }))
- }
-
- // receiver queries
- addQuery(buildQueryParams({ receiver, gateways: [gateways.standardGateway] }))
- addQuery(buildQueryParams({ receiver, gateways: [gateways.wethGateway] }))
- addQuery(buildQueryParams({ receiver, gateways: [gateways.customGateway] }))
- addQuery(buildQueryParams({ receiver, gateways: gateways.otherGateways }))
+ queriesProp.forEach(query => {
+ addQuery(buildQueryParams(query))
+ })
// for iterating through all priorities in the while loop below
let currentPriority = 1
diff --git a/packages/arb-token-bridge-ui/src/util/withdrawals/fetchWithdrawals.ts b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchWithdrawals.ts
index 9b8e1b6274..aba40e7207 100644
--- a/packages/arb-token-bridge-ui/src/util/withdrawals/fetchWithdrawals.ts
+++ b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchWithdrawals.ts
@@ -11,8 +11,37 @@ import { fetchLatestSubgraphBlockNumber } from '../SubgraphUtils'
import { Withdrawal } from '../../hooks/useTransactionHistory'
import { attachTimestampToTokenWithdrawal } from './helpers'
import { WithdrawalInitiated } from '../../hooks/arbTokenBridge.types'
-import { fetchTokenWithdrawalsFromEventLogsSequentially } from './fetchTokenWithdrawalsFromEventLogsSequentially'
+import {
+ Query,
+ fetchTokenWithdrawalsFromEventLogsSequentially
+} from './fetchTokenWithdrawalsFromEventLogsSequentially'
import { backOff, wait } from '../ExponentialBackoffUtils'
+import { isAlchemyChain } from '../networks'
+import { getArbitrumNetwork } from '@arbitrum/sdk'
+import { fetchL2Gateways } from '../fetchL2Gateways'
+import { constants } from 'ethers'
+import { getNonce } from '../AddressUtils'
+
+async function getGateways(provider: Provider): Promise<{
+ standardGateway: string
+ wethGateway: string
+ customGateway: string
+ otherGateways: string[]
+}> {
+ const network = await getArbitrumNetwork(provider)
+
+ const standardGateway = network.tokenBridge?.childErc20Gateway
+ const customGateway = network.tokenBridge?.childCustomGateway
+ const wethGateway = network.tokenBridge?.childWethGateway
+ const otherGateways = await fetchL2Gateways(provider)
+
+ return {
+ standardGateway: standardGateway ?? constants.AddressZero,
+ wethGateway: wethGateway ?? constants.AddressZero,
+ customGateway: customGateway ?? constants.AddressZero,
+ otherGateways
+ }
+}
export type FetchWithdrawalsParams = {
sender?: string
@@ -84,6 +113,47 @@ export async function fetchWithdrawals({
console.log('Error fetching withdrawals from subgraph', error)
}
+ const gateways = await getGateways(l2Provider)
+ const senderNonce = await getNonce(sender, { provider: l2Provider })
+
+ const queries: Query[] = []
+
+ // alchemy as a raas has a global rate limit across their chains, so we have to fetch sequentially and wait in-between requests to work around this
+ const isAlchemy = isAlchemyChain(l2ChainID)
+ const delayMs = isAlchemy ? 2_000 : 0
+
+ const allGateways = [
+ gateways.standardGateway,
+ gateways.wethGateway,
+ gateways.customGateway,
+ ...gateways.otherGateways
+ ]
+
+ // sender queries; only add if nonce > 0
+ if (senderNonce > 0) {
+ if (isAlchemy) {
+ // for alchemy, fetch sequentially
+ queries.push({ sender, gateways: [gateways.standardGateway] })
+ queries.push({ sender, gateways: [gateways.wethGateway] })
+ queries.push({ sender, gateways: [gateways.customGateway] })
+ queries.push({ sender, gateways: gateways.otherGateways })
+ } else {
+ // for other chains, fetch in parallel
+ queries.push({ sender, gateways: allGateways })
+ }
+ }
+
+ if (isAlchemy) {
+ // for alchemy, fetch sequentially
+ queries.push({ receiver, gateways: [gateways.standardGateway] })
+ queries.push({ receiver, gateways: [gateways.wethGateway] })
+ queries.push({ receiver, gateways: [gateways.customGateway] })
+ queries.push({ receiver, gateways: gateways.otherGateways })
+ } else {
+ // for other chains, fetch in parallel
+ queries.push({ receiver, gateways: allGateways })
+ }
+
const ethWithdrawalsFromEventLogs = await backOff(() =>
fetchETHWithdrawalsFromEventLogs({
receiver,
@@ -95,7 +165,7 @@ export async function fetchWithdrawals({
})
)
- await wait(2_000)
+ await wait(delayMs)
const tokenWithdrawalsFromEventLogs =
await fetchTokenWithdrawalsFromEventLogsSequentially({
@@ -103,7 +173,8 @@ export async function fetchWithdrawals({
receiver,
fromBlock: toBlock + 1,
toBlock: 'latest',
- provider: l2Provider
+ provider: l2Provider,
+ queries
})
const mappedEthWithdrawalsFromEventLogs: Withdrawal[] =