From deaaefe187e4935f7b7e3491edc4933b2c7e00f4 Mon Sep 17 00:00:00 2001 From: Sergey White Date: Thu, 23 May 2024 16:51:28 +0300 Subject: [PATCH] fix: l2-bridge-mantle fetch withdrawalEvents by pagination method --- .../src/clients/mantle_provider.spec.ts | 85 ++++++++++++++---- .../src/clients/mantle_provider.ts | 51 +++++++---- .../src/clients/proxy_contract_client.spec.ts | 90 +++++++++++++++++++ .../src/services/monitor_withdrawals.ts | 4 +- 4 files changed, 193 insertions(+), 37 deletions(-) create mode 100644 l2-bridge-mantle/src/clients/proxy_contract_client.spec.ts diff --git a/l2-bridge-mantle/src/clients/mantle_provider.spec.ts b/l2-bridge-mantle/src/clients/mantle_provider.spec.ts index 3624f2fa..22a59242 100644 --- a/l2-bridge-mantle/src/clients/mantle_provider.spec.ts +++ b/l2-bridge-mantle/src/clients/mantle_provider.spec.ts @@ -1,28 +1,79 @@ import { App } from '../app' import BigNumber from 'bignumber.js' -import { ETH_DECIMALS } from '../utils/constants' +import { Address, ETH_DECIMALS } from '../utils/constants' import * as E from 'fp-ts/Either' +import * as Winston from 'winston' +import { ethers } from 'ethers' +import { ERC20Short__factory, L2ERC20TokenBridge__factory } from '../generated' +import { MantleClient } from './mantle_provider' +import { AVG_BLOCK_TIME_2SECONDS, HOURS_48 } from '../services/monitor_withdrawals' +import { expect } from '@jest/globals' + +const timeout = 120_000 describe('MantleProvider', () => { - test('fetchBlocks', async () => { - const app = await App.getInstance() + test( + 'fetchBlocks', + async () => { + const app = await App.getInstance() + + const start = 50_183_000 + const end = 50_184_000 + const blocks = await app.mantleClient.fetchL2Blocks(start, end) + + expect(blocks.length).toEqual(end - start + 1) + }, + timeout, + ) + + test( + 'getWstEthTotalSupply is 9.860230303930711579 wsETH', + async () => { + const app = await App.getInstance() + + const baseBlockNumber = 62_393_461 + const balance = await app.mantleClient.getWstEthTotalSupply(baseBlockNumber) + if (E.isLeft(balance)) { + throw balance.left + } + + expect(balance.right.dividedBy(ETH_DECIMALS)).toEqual(new BigNumber('9.860230303930711579')) + }, + timeout, + ) + + test( + 'getWithdrawalEvents fetches 86_401 blocks for getting withdrawal events', + async () => { + const adr = Address + + const logger: Winston.Logger = Winston.createLogger({ + format: Winston.format.simple(), + transports: [new Winston.transports.Console()], + }) + + const mantleRpcURL = 'https://rpc.mantle.xyz' + + const baseNetworkID = 5000 + const mantleProvider = new ethers.providers.JsonRpcProvider(mantleRpcURL, baseNetworkID) + + const l2Bridge = L2ERC20TokenBridge__factory.connect(adr.MANTLE_L2ERC20_TOKEN_BRIDGE_ADDRESS, mantleProvider) + const bridgedWSthEthRunner = ERC20Short__factory.connect(adr.MANTLE_WSTETH_ADDRESS, mantleProvider) + const mantleClient = new MantleClient(mantleProvider, logger, l2Bridge, bridgedWSthEthRunner) - const start = 50_183_000 - const end = 50_184_000 - const blocks = await app.mantleClient.fetchL2Blocks(start, end) + const currentBlock = 64_170_875 - expect(blocks.length).toEqual(end - start + 1) - }, 120_000) + const pastBlock = currentBlock - Math.ceil(HOURS_48 / AVG_BLOCK_TIME_2SECONDS) - test('getWstEthTotalSupply is 9.860230303930711579 wsETH', async () => { - const app = await App.getInstance() + expect(86401).toEqual(currentBlock - pastBlock + 1) - const baseBlockNumber = 62_393_461 - const balance = await app.mantleClient.getWstEthTotalSupply(baseBlockNumber) - if (E.isLeft(balance)) { - throw balance.left - } + const withdrawalEvents = await mantleClient.getWithdrawalEvents(pastBlock, currentBlock - 1) + if (E.isLeft(withdrawalEvents)) { + throw withdrawalEvents + } - expect(balance.right.dividedBy(ETH_DECIMALS)).toEqual(new BigNumber('9.860230303930711579')) - }, 120_000) + expect(withdrawalEvents.right.length).toEqual(2) + }, + timeout, + ) }) diff --git a/l2-bridge-mantle/src/clients/mantle_provider.ts b/l2-bridge-mantle/src/clients/mantle_provider.ts index 7dd94c00..87d7bae4 100644 --- a/l2-bridge-mantle/src/clients/mantle_provider.ts +++ b/l2-bridge-mantle/src/clients/mantle_provider.ts @@ -109,7 +109,7 @@ export class MantleClient implements IMantleClient, IMonitorWithdrawalsClient, I const blocks = await doRequest(request) out.push(...blocks) } catch (e) { - this.logger.warning(`${e}`) + this.logger.warn(`${e}`) if (allowedExtraRequest === 0) { break } @@ -144,7 +144,7 @@ export class MantleClient implements IMantleClient, IMonitorWithdrawalsClient, I { delay: 500, maxTry: 5 }, ) } catch (e) { - this.logger.warning( + this.logger.warn( `Could not fetch blocks logs. cause: ${e}, startBlock: ${start}, toBlock: ${end}. Total ${end - start}`, ) @@ -213,25 +213,40 @@ export class MantleClient implements IMantleClient, IMonitorWithdrawalsClient, I } public async getWithdrawalEvents( - fromBlockNumber: number, - toBlockNumber: number, + startBlock: number, + endBlock: number, ): Promise> { - try { - const out = await retryAsync( - async (): Promise => { - return await this.L2ERC20TokenBridge.queryFilter( - this.L2ERC20TokenBridge.filters.WithdrawalInitiated(), - fromBlockNumber, - toBlockNumber, - ) - }, - { delay: 500, maxTry: 5 }, - ) + const batchSize = 10_000 - return E.right(out) - } catch (e) { - return E.left(new NetworkError(e, `Could not fetch withdrawEvents`)) + const events: WithdrawalInitiatedEvent[] = [] + for (let i = startBlock; i <= endBlock; i += batchSize) { + const start = i + const end = Math.min(i + batchSize - 1, endBlock) + + let chunkEvents: WithdrawalInitiatedEvent[] = [] + try { + chunkEvents = await retryAsync( + async (): Promise => { + return await this.L2ERC20TokenBridge.queryFilter( + this.L2ERC20TokenBridge.filters.WithdrawalInitiated(), + start, + end, + ) + }, + { delay: 500, maxTry: 5 }, + ) + } catch (e) { + this.logger.warn( + `Could not fetch withdrawEvents. cause: ${e}, startBlock: ${start}, toBlock: ${end}. Total ${end - start}`, + ) + + continue + } + + events.push(...chunkEvents) } + + return E.right(events) } public async getWithdrawalRecords( diff --git a/l2-bridge-mantle/src/clients/proxy_contract_client.spec.ts b/l2-bridge-mantle/src/clients/proxy_contract_client.spec.ts new file mode 100644 index 00000000..931bb115 --- /dev/null +++ b/l2-bridge-mantle/src/clients/proxy_contract_client.spec.ts @@ -0,0 +1,90 @@ +import { ProxyContractClient } from './proxy_contract_client' +import { ERC20Short__factory, L2ERC20TokenBridge__factory, OssifiableProxy__factory } from '../generated' +import { Address } from '../utils/constants' +import * as Winston from 'winston' +import { ethers } from 'ethers' +import * as E from 'fp-ts/Either' +import { MantleClient } from './mantle_provider' +import { expect } from '@jest/globals' + +const timeout = 120_000 + +describe('Proxy_watcher tests', () => { + const adr = Address + + const logger: Winston.Logger = Winston.createLogger({ + format: Winston.format.simple(), + transports: [new Winston.transports.Console()], + }) + + const mantleRpcURL = 'https://rpc.mantle.xyz' + + const baseNetworkID = 5000 + const mantleProvider = new ethers.providers.JsonRpcProvider(mantleRpcURL, baseNetworkID) + + const l2Bridge = L2ERC20TokenBridge__factory.connect(adr.MANTLE_L2ERC20_TOKEN_BRIDGE_ADDRESS, mantleProvider) + const bridgedWSthEthRunner = ERC20Short__factory.connect(adr.MANTLE_WSTETH_ADDRESS, mantleProvider) + const mantleClient = new MantleClient(mantleProvider, logger, l2Bridge, bridgedWSthEthRunner) + + test( + 'test MANTLE_L2ERC20_TOKEN_BRIDGED proxy client', + async () => { + const latestL2Block = await mantleClient.getLatestL2Block() + if (E.isLeft(latestL2Block)) { + throw latestL2Block.left + } + + const client = new ProxyContractClient( + adr.MANTLE_L2ERC20_TOKEN_BRIDGED.name, + adr.MANTLE_L2ERC20_TOKEN_BRIDGED.address, + OssifiableProxy__factory.connect(adr.MANTLE_L2ERC20_TOKEN_BRIDGED.address, mantleProvider), + ) + + const proxyImpl = await client.getProxyImplementation(latestL2Block.right.number) + if (E.isLeft(proxyImpl)) { + throw proxyImpl.left + } + + expect(proxyImpl.right).toEqual('0xf10A7ffC613a9b23Abc36167925A375bf5986181') + + const proxyAdm = await client.getProxyAdmin(latestL2Block.right.number) + if (E.isLeft(proxyAdm)) { + throw proxyAdm.left + } + + expect(proxyAdm.right).toEqual('0x3a7B055BF88CdC59D20D0245809C6E6B3c5819dd') + }, + timeout, + ) + + test( + 'test MANTLE_WSTETH_BRIDGED proxy client', + async () => { + const latestL2Block = await mantleClient.getLatestL2Block() + if (E.isLeft(latestL2Block)) { + throw latestL2Block.left + } + + const client = new ProxyContractClient( + adr.MANTLE_WSTETH_BRIDGED.name, + adr.MANTLE_WSTETH_BRIDGED.address, + OssifiableProxy__factory.connect(adr.MANTLE_WSTETH_BRIDGED.address, mantleProvider), + ) + + const proxyImpl = await client.getProxyImplementation(latestL2Block.right.number) + if (E.isLeft(proxyImpl)) { + throw proxyImpl.left + } + + expect(proxyImpl.right).toEqual('0x1FaBaAec88198291A4efCc85Cabb33a3785165ba') + + const proxyAdm = await client.getProxyAdmin(latestL2Block.right.number) + if (E.isLeft(proxyAdm)) { + throw proxyAdm.left + } + + expect(proxyAdm.right).toEqual('0x3a7B055BF88CdC59D20D0245809C6E6B3c5819dd') + }, + timeout, + ) +}) diff --git a/l2-bridge-mantle/src/services/monitor_withdrawals.ts b/l2-bridge-mantle/src/services/monitor_withdrawals.ts index 30db225e..c6171a1f 100644 --- a/l2-bridge-mantle/src/services/monitor_withdrawals.ts +++ b/l2-bridge-mantle/src/services/monitor_withdrawals.ts @@ -16,8 +16,8 @@ const MAX_WITHDRAWALS_10K_WstEth = 10_000 export type MonitorWithdrawalsInitResp = { currentWithdrawals: string } -const HOURS_48 = 60 * 60 * 24 * 2 -const AVG_BLOCK_TIME_2SECONDS: number = 2 //s +export const HOURS_48 = 60 * 60 * 24 * 2 +export const AVG_BLOCK_TIME_2SECONDS: number = 2 //s export class MonitorWithdrawals { private readonly name: string = 'WithdrawalsMonitor'