From 312cf068f1f7245a75accce6d06ad0d202812e55 Mon Sep 17 00:00:00 2001 From: spsjvc Date: Tue, 17 Dec 2024 13:29:15 +0100 Subject: [PATCH] wip --- .../arb-token-bridge-ui/src/util/networks.ts | 16 +++- ...kenWithdrawalsFromEventLogsSequentially.ts | 38 ++++----- .../src/util/withdrawals/fetchWithdrawals.ts | 77 ++++++++++++++++++- 3 files changed, 103 insertions(+), 28 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts index ab8ce17bfb..0af57d8226 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 orbitChainsData from './orbitChainsData.json' export enum ChainId { // L1 @@ -581,6 +582,19 @@ export function getSupportedChainIds({ }) } +export async function isAlchemyChain(provider: Provider) { + const { chainId } = await getArbitrumNetwork(provider) + + const chains = [...orbitChainsData.mainnet, ...orbitChainsData.testnet] + const chain = chains.find(chain => chain.chainId === chainId) + + if (typeof chain === 'undefined') { + return false + } + + return chain.rpcUrl.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/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts index 5087788d3c..b6c1e4cec7 100644 --- a/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts +++ b/packages/arb-token-bridge-ui/src/util/withdrawals/fetchTokenWithdrawalsFromEventLogsSequentially.ts @@ -36,6 +36,12 @@ type TokenWithdrawalQuery = { priority: number } +export type BuildQueryParamsParams = { + sender?: string + receiver?: string + gateways?: string[] +} + export type FetchTokenWithdrawalsFromEventLogsSequentiallyParams = { sender?: string receiver?: string @@ -46,6 +52,7 @@ export type FetchTokenWithdrawalsFromEventLogsSequentiallyParams = { * How long to delay in-between queries of different priority. */ delayMs?: number + queries: BuildQueryParamsParams[] } export type FetchTokenWithdrawalsFromEventLogsSequentiallyResult = Awaited< @@ -53,15 +60,15 @@ export type FetchTokenWithdrawalsFromEventLogsSequentiallyResult = Awaited< > export async function fetchTokenWithdrawalsFromEventLogsSequentially({ - sender, - receiver, provider, fromBlock = 0, toBlock = 'latest', - delayMs = 2_000 + delayMs = 2_000, + queries: queriesProp }: FetchTokenWithdrawalsFromEventLogsSequentiallyParams): Promise { // keep track of priority; increment as queries are added let priority = 0 + // keep track of queries const queries: TokenWithdrawalQuery[] = [] @@ -70,11 +77,7 @@ export async function fetchTokenWithdrawalsFromEventLogsSequentially({ sender, receiver, gateways = [] - }: { - sender?: string - receiver?: string - gateways?: string[] - }): TokenWithdrawalQuery['params'] { + }: BuildQueryParamsParams): TokenWithdrawalQuery['params'] { return { sender, receiver, @@ -100,22 +103,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..85d2046f3a 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 { + BuildQueryParamsParams, + 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: BuildQueryParamsParams[] = [] + + // alchemy has a global rate limit across all their chains, so we have to fetch sequentially and wait in-between requests + const isAlchemy = await isAlchemyChain(l2Provider) + 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[] =