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/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[] =