From f4373a90020cbc8bfbc16da6c32babe627e7d4ae Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Fri, 19 Jan 2024 16:38:12 +0000 Subject: [PATCH] feat(ethereum-connector): support block monitoring with http only connection - Update web3.js to 4.4 (I was hoping to use requested by me `safeDisconnect` method, but it seem to be still unavailable in this version) - Support monitoring without websocket ethereum node access by using http polling method. Method is chosed automatically during runtime, based on supplied ethereum node URL. - Refactored `WatchBlocksV1Endpoint` into base class and child classes that implement monitoring strategies. `WatchBlocksV1Endpoint` is now instantiated with factory method. This will allow easier addition of new strategies in the future. - Add monitoring tests to ethereum connector pacakge, remove overlaping tests from verifier-integration-with-ethereum-connector.test. Signed-off-by: Michal Bajer --- .../README.md | 43 +- .../package.json | 8 +- .../src/main/json/openapi.json | 14 +- .../generated/openapi/typescript-axios/api.ts | 14 +- .../plugin-ledger-connector-ethereum.ts | 73 ++- .../web-services/watch-blocks-v1-endpoint.ts | 408 +++++++++++--- ...oy-and-invoke-using-json-object-v1.test.ts | 2 +- ...eploy-and-invoke-using-keychain-v1.test.ts | 2 +- .../geth-invoke-web3-method-v1.test.ts | 2 +- .../geth-monitoring-blocks.test.ts | 321 +++++++++++ .../geth-transact-and-gas-fees.test.ts | 2 +- .../package.json | 4 +- ...ntegration-with-ethereum-connector.test.ts | 58 +- yarn.lock | 508 ++++++++---------- 14 files changed, 969 insertions(+), 490 deletions(-) create mode 100644 packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-monitoring-blocks.test.ts diff --git a/packages/cactus-plugin-ledger-connector-ethereum/README.md b/packages/cactus-plugin-ledger-connector-ethereum/README.md index 065367c152..82491dcf56 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/README.md +++ b/packages/cactus-plugin-ledger-connector-ethereum/README.md @@ -181,36 +181,27 @@ await apiClient.runTransactionV1({ }); ``` -### Offline signing utils -- Use `signTransaction` from this package to sign transactions payload locally (outside of connector process). -- Offline signed transaction can be send with `Web3SigningCredentialType.None` signing credetnial type in runTransactionV1 endpoint. +### watchBlocksV1 +- ApiClient can be used to monitor for new blocks from the ledger with `watchBlocksV1` method. +- When etherum node supports subscription (e.g. websocket protocol is used), then blocks connector will subscribe to new block header event (recommended). +- If ethereum node supports HTTP access only, then polling method will be used. + +#### Example ``` typescript -// Offline sign transaction -const { serializedTransactionHex } = signTransaction( - { - to: anotherAccount, - value: 10e6, - maxPriorityFeePerGas: 0, - maxFeePerGas: 0x40000000, - gasLimit: 21000, - type: 2 - }, - myPrivateKey, - { - networkId: 10, - chainId: 10, - defaultHardfork: "london", - }, -); +const watchObservable = apiClient.watchBlocksV1({ + getBlockData, // true - return transactions, false - return header only (default) + lastSeenBlock, // connector will push all blocks since lastSeenBlock (default - latest) + httpPollInterval // how often to poll the node (only for http-polling method) +}); -// Send transaction payload to connector -await apiClient.runTransactionV1({ - web3SigningCredential: { - type: Web3SigningCredentialType.None, +const subscription = watchObservable.subscribe({ + next(event) { + // process block data }, - transactionConfig: { - rawTransaction: serializedTransactionHex, + error(err) { + // handle error + subscription.unsubscribe(); }, }); ``` diff --git a/packages/cactus-plugin-ledger-connector-ethereum/package.json b/packages/cactus-plugin-ledger-connector-ethereum/package.json index 37450f88bb..506f903c87 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/package.json +++ b/packages/cactus-plugin-ledger-connector-ethereum/package.json @@ -80,9 +80,9 @@ "sanitize-html": "2.7.0", "socket.io-client-fixed-types": "4.5.4", "typescript-optional": "2.0.1", - "web3": "4.1.2", - "web3-eth": "4.2.0", - "web3-eth-contract": "4.1.0" + "web3": "4.4.0", + "web3-eth": "4.4.0", + "web3-eth-contract": "4.2.0" }, "devDependencies": { "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", @@ -99,7 +99,7 @@ "js-yaml": "4.1.0", "socket.io": "4.5.4", "uuid": "9.0.1", - "web3-eth-accounts": "4.0.6" + "web3-eth-accounts": "4.1.1" }, "engines": { "node": ">=18", diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/main/json/openapi.json b/packages/cactus-plugin-ledger-connector-ethereum/src/main/json/openapi.json index 0f9f8824dc..0ce13c9492 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/main/json/openapi.json +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/main/json/openapi.json @@ -662,7 +662,19 @@ "type": "object", "properties": { "getBlockData": { - "type": "boolean" + "type": "boolean", + "description": "Include entire block data if flag is true, otherwise just a header is returned (default)", + "default": "false" + }, + "lastSeenBlock": { + "type": "number", + "description": "Block from which we want to start the monitoring process.", + "default": "latest" + }, + "httpPollInterval": { + "type": "number", + "description": "How often to poll ethereum node for new blocks. Not used if the node supports subscription based monitoring (i.e. WebSocket).", + "default": "5 seconds" } } }, diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/generated/openapi/typescript-axios/api.ts index d25c5445ed..43057a2589 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -756,11 +756,23 @@ export type WatchBlocksV1BlockDataTimestamp = number | string; */ export interface WatchBlocksV1Options { /** - * + * Include entire block data if flag is true, otherwise just a header is returned (default) * @type {boolean} * @memberof WatchBlocksV1Options */ 'getBlockData'?: boolean; + /** + * Block from which we want to start the monitoring process. + * @type {number} + * @memberof WatchBlocksV1Options + */ + 'lastSeenBlock'?: number; + /** + * How often to poll ethereum node for new blocks. Not used if the node supports subscription based monitoring (i.e. WebSocket). + * @type {number} + * @memberof WatchBlocksV1Options + */ + 'httpPollInterval'?: number; } /** * diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/plugin-ledger-connector-ethereum.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/plugin-ledger-connector-ethereum.ts index 75ff90d91b..ea0d7e75c8 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/plugin-ledger-connector-ethereum.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/plugin-ledger-connector-ethereum.ts @@ -11,7 +11,6 @@ import Web3, { TransactionReceiptBase, WebSocketProvider, } from "web3"; -import { NewHeadsSubscription } from "web3-eth"; import { PayableMethodObject } from "web3-eth-contract"; import OAS from "../json/openapi.json"; @@ -63,7 +62,10 @@ import { import { RunTransactionEndpoint } from "./web-services/run-transaction-v1-endpoint"; import { InvokeContractEndpoint } from "./web-services/invoke-contract-v1-endpoint"; -import { WatchBlocksV1Endpoint } from "./web-services/watch-blocks-v1-endpoint"; +import { + createWatchBlocksV1Endpoint, + WatchBlocksV1Endpoint, +} from "./web-services/watch-blocks-v1-endpoint"; import { GetPrometheusExporterMetricsEndpointV1 } from "./web-services/get-prometheus-exporter-metrics-v1-endpoint"; import { InvokeRawWeb3EthMethodEndpoint } from "./web-services/invoke-raw-web3eth-method-v1-endpoint"; import { InvokeRawWeb3EthContractEndpoint } from "./web-services/invoke-raw-web3eth-contract-v1-endpoint"; @@ -140,11 +142,10 @@ export class PluginLedgerConnectorEthereum public prometheusExporter: PrometheusExporter; private readonly instanceId: string; private readonly log: Logger; - private readonly web3: Web3; - private readonly web3WatchBlock?: Web3; + private readonly web3: InstanceType; private endpoints: IWebServiceEndpoint[] | undefined; public static readonly CLASS_NAME = "PluginLedgerConnectorEthereum"; - private watchBlocksSubscriptions: Map = + private watchBlocksSubscriptions: Map = new Map(); public get className(): string { @@ -196,9 +197,6 @@ export class PluginLedgerConnectorEthereum const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); this.web3 = new Web3(this.createWeb3Provider()); - if (this.options.rpcApiWsHost) { - this.web3WatchBlock = new Web3(this.createWeb3WsProvider()); - } this.instanceId = options.instanceId; this.pluginRegistry = options.pluginRegistry as PluginRegistry; @@ -292,10 +290,7 @@ export class PluginLedgerConnectorEthereum } await this.closeWeb3jsConnection( - this.web3.currentProvider as WebSocketProvider, - ); - await this.closeWeb3jsConnection( - this.web3WatchBlock?.currentProvider as WebSocketProvider, + this.web3.currentProvider as unknown as WebSocketProvider, ); } @@ -311,35 +306,31 @@ export class PluginLedgerConnectorEthereum const webServices = await this.getOrCreateWebServices(); await Promise.all(webServices.map((ws) => ws.registerExpress(app))); - if (this.web3WatchBlock) { - this.log.debug(`WebSocketProvider created for socketio endpoints`); - wsApi.on("connection", (socket: SocketIoSocket) => { - this.log.info(`New Socket connected. ID=${socket.id}`); - - socket.on(WatchBlocksV1.Subscribe, (options?: WatchBlocksV1Options) => { - new WatchBlocksV1Endpoint({ - web3: this.web3WatchBlock as typeof this.web3WatchBlock, - socket, - logLevel, - options, - }).subscribe(); - }); - }); - } else { - this.log.info( - `WebSocketProvider was NOT created for socketio endpoints! Socket.IO will not be handled!`, + wsApi.on("connection", (socket: SocketIoSocket) => { + this.log.info(`New socket connection id ${socket.id}`); + + // WatchBlocksV1Endpoint + socket.on( + WatchBlocksV1.Subscribe, + async (options?: WatchBlocksV1Options) => { + try { + const endpoint = createWatchBlocksV1Endpoint({ + web3: this.web3, + socket, + logLevel, + options, + }); + this.watchBlocksSubscriptions.set( + socket.id, + await endpoint.subscribe(), + ); + this.log.debug(`${endpoint.className} created for ${socket.id}`); + } catch (error) { + this.log.error("Error when creating WatchBlocksV1Endpoint:", error); + } + }, ); - wsApi.on("connection", (socket: SocketIoSocket) => { - this.log.info( - "Socket connected but no async endpoint is supported - disconnecting...", - ); - socket.emit( - WatchBlocksV1.Error, - "Missing rpcApiWsHost - can't listen for new blocks on HTTP provider", - ); - socket.disconnect(); - }); - } + }); // Register JSON-RPC proxy to pass requests directly to ethereum node if (this.options.rpcApiHttpHost) { @@ -355,7 +346,7 @@ export class PluginLedgerConnectorEthereum [".*"]: "", }, onProxyReq: fixRequestBody, - logLevel: "error", + logLevel: "warn", }), ); this.log.info(`Registered proxy from ${proxyUrl} to ${targetUrl}`); diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/web-services/watch-blocks-v1-endpoint.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/web-services/watch-blocks-v1-endpoint.ts index 5d3648c7fb..6c1264e15c 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/web-services/watch-blocks-v1-endpoint.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/main/typescript/web-services/watch-blocks-v1-endpoint.ts @@ -1,3 +1,9 @@ +/** + * Contains abstract base WatchBlocksV1Endpoint, it specific implementation (with WebSockets and HTTP polling) and some helper methods. + * In the future we may consider dividing this into separate files, but for now (since codebase is small) it makes more sense to keep + * everything in one place for simplicity. + */ + import Web3, { BlockHeaderOutput, FMT_BYTES, FMT_NUMBER } from "web3"; import { NewHeadsSubscription } from "web3-eth"; import { Socket as SocketIoSocket } from "socket.io"; @@ -20,26 +26,77 @@ import { Web3StringReturnFormat, } from "../types/util-types"; +const DEFAULT_HTTP_POLL_INTERVAL = 1000 * 5; // 5 seconds +const LAST_SEEN_LATEST_BLOCK = -1; // must be negative number, will be replaced with latest block in code + export interface IWatchBlocksV1EndpointConfiguration { logLevel?: LogLevelDesc; socket: SocketIoSocket; - web3: Web3; + web3: InstanceType; options?: WatchBlocksV1Options; } -export class WatchBlocksV1Endpoint { - public static readonly CLASS_NAME = "WatchBlocksV1Endpoint"; +/** + * Returns true if provider of given web3js instance supports subscriptions (e.g. websocket connection) + * + * @param web3 web3js instance + * @returns boolean + */ +function isWeb3SubscriptionSupported(web3: InstanceType) { + const provider = web3.currentProvider; + if (!provider) { + throw new Error( + "Missing Web3 provider, can't monitor new blocks in any way", + ); + } + return provider.supportsSubscriptions(); +} + +/** + * Factory method for creating either subscription based or HTTP-poll based `WatchBlocksV1Endpoint` + * (depending on web3js instance capability) + * + * @param config `WatchBlocksV1Endpoint` configuration + * @returns `WatchBlocksV1Endpoint` + */ +export function createWatchBlocksV1Endpoint( + config: IWatchBlocksV1EndpointConfiguration, +): WatchBlocksV1Endpoint { + if (isWeb3SubscriptionSupported(config.web3)) { + return new WatchBlocksV1SubscriptionEndpoint(config); + } else { + return new WatchBlocksV1HttpPollEndpoint(config); + } +} - private readonly log: Logger; - private readonly socket: SocketIoSocket< +/** + * Base abstract class to be extended by specific WatchBlocks strategies. + * Contains common logic for all monitoring endpoints. + */ +export abstract class WatchBlocksV1Endpoint { + protected readonly log: Logger; + protected readonly socket: SocketIoSocket< Record void>, Record void> >; - private readonly web3: Web3; - private readonly isGetBlockData: boolean; + protected readonly web3: InstanceType; + protected readonly isGetBlockData: boolean; + protected lastSeenBlock: number; + private _isSubscribed = false; + /** + * Note: should be overwritten by the strategy classes. + */ public get className(): string { - return WatchBlocksV1Endpoint.CLASS_NAME; + return "WatchBlocksV1Endpoint"; + } + + public get isSubscribed(): boolean { + return !this.socket.disconnected && this._isSubscribed; + } + + public set isSubscribed(value: boolean) { + this._isSubscribed = value; } constructor(public readonly config: IWatchBlocksV1EndpointConfiguration) { @@ -50,82 +107,311 @@ export class WatchBlocksV1Endpoint { this.web3 = config.web3; this.socket = config.socket; - this.isGetBlockData = config.options?.getBlockData == true; + this.isGetBlockData = config.options?.getBlockData === true; + this.lastSeenBlock = + config.options?.lastSeenBlock ?? LAST_SEEN_LATEST_BLOCK; const level = this.config.logLevel || "INFO"; const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); + + this.socket.on("disconnect", async (reason: string) => { + this.log.info( + `WebSocket:disconnect => ${this.socket.id} reason: ${reason}`, + ); + await this.unsubscribe(); + }); + + this.socket.on(WatchBlocksV1.Unsubscribe, async () => { + this.log.info(`${WatchBlocksV1.Unsubscribe} => ${this.socket.id}`); + await this.unsubscribe(); + }); + } + + /** + * Get block with specific number from ethereum, parse it and return + * `WatchBlocksV1Progress` with `blockData`. + * + * @param blockNumber + * @returns `WatchBlocksV1Progress + */ + protected async getFullBlockProgress( + blockNumber: number, + ): Promise { + const web3BlockData = await this.web3.eth.getBlock(blockNumber, true, { + number: FMT_NUMBER.STR, + bytes: FMT_BYTES.HEX, + }); + + return { + blockData: { + ...web3BlockData, + // force empty transactions object instead of undefined, also narrow from string[] + transactions: (web3BlockData.transactions ?? + []) as unknown as Web3Transaction[], + }, + }; + } + + /** + * Parse block header data and return `WatchBlocksV1Progress` with `blockHeader`. + * @param web3BlockData `BlockHeaderOutput` + * @returns `WatchBlocksV1Progress` + */ + protected async headerDataToBlockProgress( + web3BlockData: BlockHeaderOutput, + ): Promise { + // Force fix type of sha3Uncles + let sha3Uncles: string = web3BlockData.sha3Uncles as unknown as string; + if (Array.isArray(web3BlockData.sha3Uncles)) { + sha3Uncles = web3BlockData.sha3Uncles.toString(); + } + + return { + blockHeader: { + ...(web3BlockData as ConvertWeb3ReturnToString), + sha3Uncles, + }, + }; } - public async subscribe(): Promise { + /** + * Push to the socketio client all missing blocks since `lastSeenBlock`, up to the current latest block. + * Will not push if subscription was stopped in the meantime. + * Can throw exceptions. + */ + protected async emitAllSinceLastSeenBlock(): Promise { const { socket, log, web3, isGetBlockData } = this; - log.info(`${WatchBlocksV1.Subscribe} => ${socket.id}`); - const newBlocksSubscription = await web3.eth.subscribe( - "newBlockHeaders", - undefined, - Web3StringReturnFormat, - ); + const latestBlockNumber = await web3.eth.getBlockNumber({ + number: FMT_NUMBER.NUMBER, + bytes: FMT_BYTES.HEX, + }); - newBlocksSubscription.on("data", async (blockHeader) => { - log.debug("newBlockHeaders: BlockHeader=%o", blockHeader); - let next: WatchBlocksV1Progress; + if (this.lastSeenBlock === LAST_SEEN_LATEST_BLOCK) { + this.lastSeenBlock = latestBlockNumber; + log.debug( + "emitAllSinceLastSeenBlock() - Using latest block number as lastSeenBlock:", + latestBlockNumber, + ); + } + while (this.lastSeenBlock < latestBlockNumber) { + const blockNumber = this.lastSeenBlock + 1; + log.debug( + `emitAllSinceLastSeenBlock() - pushing block ${blockNumber} (latest ${latestBlockNumber})`, + ); + + let next: WatchBlocksV1Progress; if (isGetBlockData) { - const web3BlockData = await web3.eth.getBlock( - blockHeader.number, - true, - { - number: FMT_NUMBER.STR, - bytes: FMT_BYTES.HEX, - }, - ); - next = { - blockData: { - ...web3BlockData, - // Return with full tx objects is not detected, must manually force correct type - transactions: (web3BlockData.transactions ?? - []) as unknown as Web3Transaction[], - }, - }; + next = await this.getFullBlockProgress(blockNumber); } else { - // Force fix type of sha3Uncles - let sha3Uncles: string = blockHeader.sha3Uncles as unknown as string; - if (Array.isArray(blockHeader.sha3Uncles)) { - sha3Uncles = blockHeader.sha3Uncles.toString(); - } + const web3BlockData = await web3.eth.getBlock(blockNumber, false, { + number: FMT_NUMBER.STR, + bytes: FMT_BYTES.HEX, + }); + next = await this.headerDataToBlockProgress({ + ...web3BlockData, + sha3Uncles: web3BlockData.sha3Uncles as any, + size: undefined, + totalDifficulty: undefined, + uncles: undefined, + transactions: undefined, + }); + } - next = { - blockHeader: { - ...(blockHeader as ConvertWeb3ReturnToString), - sha3Uncles, - }, - }; + if (!this.isSubscribed) { + log.info( + "emitAllSinceLastSeenBlock() - not subscribed anymore, stopping...", + ); + break; } socket.emit(WatchBlocksV1.Next, next); - }); - newBlocksSubscription.on("error", async (error) => { - console.log("Error when subscribing to New block header: ", error); - socket.emit(WatchBlocksV1.Error, safeStringifyException(error)); - newBlocksSubscription.unsubscribe(); - }); + this.lastSeenBlock = blockNumber; + } + + log.debug("emitAllSinceLastSeenBlock() - done"); + } + + /** + * Start monitoring new blocks from the ledger (either full blocks with transaction data or just the headers). + * Will fetch and push missing blocks since `lastSeenBlock` provided. + */ + public abstract subscribe(): Promise; + + /** + * Stop monitoring new blocks. + */ + public abstract unsubscribe(): Promise; +} + +//////////////////////////////////////////////////////////////////////////////// +// WatchBlocksV1HttpPollEndpoint +//////////////////////////////////////////////////////////////////////////////// + +/** + * Implementation of `WatchBlocksV1Endpoint` using HTTP polling method. + * Should be used if ethereum node (i.e. web3js connection) doesn't support + * async subscriptions. + */ +export class WatchBlocksV1HttpPollEndpoint extends WatchBlocksV1Endpoint { + private monitoringInterval: NodeJS.Timer | undefined; + private httpPollInterval: number; + + public get className(): string { + return "WatchBlocksV1HttpPollEndpoint"; + } + + constructor(public readonly config: IWatchBlocksV1EndpointConfiguration) { + super(config); + this.httpPollInterval = + config.options?.httpPollInterval ?? DEFAULT_HTTP_POLL_INTERVAL; + } + + public async subscribe() { + const { socket, log } = this; + log.info(`${WatchBlocksV1.Subscribe} [HTTP Polling] => ${socket.id}`); + + if (this.isSubscribed) { + this.log.error( + "subscribe() - monitoring has already been started! Restarting it...", + ); + await this.unsubscribe(); + } + this.isSubscribed = true; + + socket.on("disconnect", async () => this.unsubscribe()); + socket.on(WatchBlocksV1.Unsubscribe, async () => this.unsubscribe()); + + log.debug("Starting new HTTP polling interval..."); + this.monitoringInterval = setInterval(async () => { + try { + await this.emitAllSinceLastSeenBlock(); + } catch (error) { + log.warn(`${this.className} - polling thread exception:`, error); + } + }, this.httpPollInterval); + + return this; + } + + public async unsubscribe(): Promise { + this.log.debug("Unsubscribing HTTP polling monitor..."); + try { + clearInterval(this.monitoringInterval); + } catch (error) { + this.log.info( + `Could not clear polling interval id ${this.monitoringInterval}, error:`, + error, + ); + } + this.monitoringInterval = undefined; + this.isSubscribed = false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// WatchBlocksV1SubscriptionEndpoint +//////////////////////////////////////////////////////////////////////////////// + +/** + * Implementation of `WatchBlocksV1Endpoint` using web3js subscription (WebSocket) + * Should be used if ethereum node (i.e. web3js connection) supports async subscriptions. + * Throws if wrong web3js provider was used. + */ + +export class WatchBlocksV1SubscriptionEndpoint extends WatchBlocksV1Endpoint { + private newBlocksSubscription: NewHeadsSubscription | undefined; + + public get className(): string { + return "WatchBlocksV1SubscriptionEndpoint"; + } + + constructor(public readonly config: IWatchBlocksV1EndpointConfiguration) { + super(config); + if (!isWeb3SubscriptionSupported(this.web3)) { + throw new Error("Provided web3 provider doesn't support subscriptions!"); + } + } + + public async subscribe() { + const { socket, log, web3, isGetBlockData } = this; + log.info(`${WatchBlocksV1.Subscribe} [WS Subscription] => ${socket.id}`); + + if (this.isSubscribed) { + this.log.error( + "subscribe() - monitoring has already been started! Restarting it...", + ); + await this.unsubscribe(); + } + this.isSubscribed = true; + + log.info("Pushing missing blocks since lastSeenBlock..."); + await this.emitAllSinceLastSeenBlock(); log.debug("Subscribing to Web3 new block headers event..."); + this.newBlocksSubscription = await web3.eth.subscribe( + "newBlockHeaders", + undefined, + Web3StringReturnFormat, + ); - socket.on("disconnect", async (reason: string) => { - log.info("WebSocket:disconnect reason=%o", reason); - await newBlocksSubscription.unsubscribe(); + this.newBlocksSubscription.on("data", async (blockHeader) => { + try { + log.debug("newBlockHeaders:", blockHeader); + + if (typeof blockHeader.number === undefined) { + throw new Error( + `Missing block number in received block header (number: ${blockHeader.number}, hash: ${blockHeader.hash})`, + ); + } + const blockNumber = Number(blockHeader.number); + if (blockNumber - this.lastSeenBlock > 2) { + log.info( + `Detected missing blocks since latest one (blockNumber: ${blockNumber}, lastSeenBlock: ${this.lastSeenBlock})`, + ); + await this.emitAllSinceLastSeenBlock(); + } + + let next: WatchBlocksV1Progress; + if (isGetBlockData) { + next = await this.getFullBlockProgress(blockNumber); + } else { + next = await this.headerDataToBlockProgress(blockHeader); + } + + socket.emit(WatchBlocksV1.Next, next); + + this.lastSeenBlock = blockNumber; + } catch (error) { + log.warn("Error when parsing subscribed block data:", error); + } }); - socket.on(WatchBlocksV1.Unsubscribe, async () => { - log.debug(`${WatchBlocksV1.Unsubscribe}: unsubscribing Web3...`); - await newBlocksSubscription.unsubscribe(); - log.debug("Web3 unsubscribe done."); + this.newBlocksSubscription.on("error", async (error) => { + console.log("Error when subscribing to new block header: ", error); + socket.emit(WatchBlocksV1.Error, safeStringifyException(error)); + await this.unsubscribe(); }); - log.debug("Subscribing to Web3 new block headers event..."); - return newBlocksSubscription as NewHeadsSubscription; + return this; + } + + public async unsubscribe(): Promise { + this.log.debug("Unsubscribing block subscription monitor..."); + if (this.newBlocksSubscription) { + try { + await this.newBlocksSubscription.unsubscribe(); + } catch (error) { + this.log.info( + "Could not unsubscribe from web3js monitor, error:", + error, + ); + } + } + this.newBlocksSubscription = undefined; + this.isSubscribed = false; } } diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-json-object-v1.test.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-json-object-v1.test.ts index 726d91f28a..8c6815ad9a 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-json-object-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-json-object-v1.test.ts @@ -55,7 +55,7 @@ describe("Ethereum contract deploy and invoke using keychain tests", () => { address: HexString; privateKey: HexString; }, - web3: Web3, + web3: InstanceType, addressInfo, address: string, port: number, diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-keychain-v1.test.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-keychain-v1.test.ts index 40488ae634..70f4f4dda7 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-keychain-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-contract-deploy-and-invoke-using-keychain-v1.test.ts @@ -59,7 +59,7 @@ describe("Ethereum contract deploy and invoke using keychain tests", () => { address: HexString; privateKey: HexString; }, - web3: Web3, + web3: InstanceType, addressInfo, address: string, port: number, diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-invoke-web3-method-v1.test.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-invoke-web3-method-v1.test.ts index d2b8968f00..5cf120279a 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-invoke-web3-method-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-invoke-web3-method-v1.test.ts @@ -48,7 +48,7 @@ const containerImageVersion = "2023-07-27-2a8c48ed6"; describe("invokeRawWeb3EthMethod Tests", () => { let ethereumTestLedger: GethTestLedger; let connector: PluginLedgerConnectorEthereum; - let web3: Web3; + let web3: InstanceType; let apiHost: string; const expressApp = express(); expressApp.use(bodyParser.json({ limit: "250mb" })); diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-monitoring-blocks.test.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-monitoring-blocks.test.ts new file mode 100644 index 0000000000..d8711d6ed1 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-monitoring-blocks.test.ts @@ -0,0 +1,321 @@ +/** + * Tests for block monitoring endpoint. + */ + +////////////////////////////////// +// Constants +////////////////////////////////// + +const testLogLevel: LogLevelDesc = "info"; +const containerImageName = "ghcr.io/hyperledger/cacti-geth-all-in-one"; +const containerImageVersion = "2023-07-27-2a8c48ed6"; +const asyncTestTimeout = 1000 * 60 * 5; // 5 minutes + +import "jest-extended"; +import express from "express"; +import bodyParser from "body-parser"; +import http from "http"; +import { v4 as uuidV4 } from "uuid"; +import { Server as SocketIoServer } from "socket.io"; +import type { Subscription } from "rxjs"; + +import { + LogLevelDesc, + Servers, + Logger, + LoggerProvider, +} from "@hyperledger/cactus-common"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { Configuration, Constants } from "@hyperledger/cactus-core-api"; +import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; +import { GethTestLedger } from "@hyperledger/cactus-test-geth-ledger"; + +import { + PluginLedgerConnectorEthereum, + EthereumApiClient, + WatchBlocksV1Progress, + Web3BlockHeader, +} from "../../../main/typescript/public-api"; + +const log: Logger = LoggerProvider.getOrCreate({ + label: "geth-monitoring-blocks.test", + level: testLogLevel, +}); +const NODE_TYPE_WEBSOCKET = "WebSocket"; +const NODE_TYPE_HTTP = "HTTP"; + +/** + * Common helper function for testing block monitoring scenarios. + * + * @param apiClient apiClient to running connector + * @param getBlockData true / false to get full block data or just the headers + * @param count test will wait and return `count` from the connector. + * @param lastSeenBlock block to start monitoring from + * @returns `count` number of blocks + */ +async function testWatchBlock( + apiClient: EthereumApiClient, + getBlockData: boolean, + count = 1, + lastSeenBlock?: number, +) { + let subscription: Subscription | undefined = undefined; + const blocksReceived: WatchBlocksV1Progress[] = []; + + // Wait for blocks + await new Promise((resolve, reject) => { + const watchObservable = apiClient.watchBlocksV1({ + getBlockData, + lastSeenBlock, + httpPollInterval: 1000, + }); + + subscription = watchObservable.subscribe({ + next(event) { + blocksReceived.push(event); + log.debug( + "Received event:", + JSON.stringify(event), + "count:", + blocksReceived.length, + ); + if (blocksReceived.length >= count) { + subscription?.unsubscribe(); + resolve(true); + } + }, + error(err) { + log.error("watchBlocksV1() error:", err); + subscription?.unsubscribe(); + reject(err); + }, + }); + }); + + return blocksReceived; +} + +/** + * Function for validating some block header fields. + * @param header block header from connector + */ +function assertBlockHeader(header?: Web3BlockHeader) { + if (!header) { + throw new Error("Header is missing!"); + } + + // Check if defined and with expected type + // Ignore nullable / undefine-able fields + expect(typeof header.parentHash).toEqual("string"); + expect(typeof header.sha3Uncles).toEqual("string"); + expect(typeof header.miner).toEqual("string"); + expect(typeof header.number).toEqual("string"); + expect(typeof header.gasLimit).toEqual("string"); + expect(typeof header.gasUsed).toEqual("string"); + expect(typeof header.difficulty).toEqual("string"); +} + +/** + * All monitoring tests use single ledger instance for performance reasons. + */ +describe("Ethereum monitoring endpoints tests", () => { + let ledger: GethTestLedger; + let rpcApiWsHost: string; + let rpcApiHttpHost: string; + + ////////////////////////////////// + // Setup ledger + ////////////////////////////////// + + beforeAll(async () => { + const pruning = pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + await expect(pruning).resolves.toBeTruthy(); + + ledger = new GethTestLedger({ + containerImageName, + containerImageVersion, + }); + await ledger.start(); + rpcApiHttpHost = await ledger.getRpcApiHttpHost(); + rpcApiWsHost = await ledger.getRpcApiWebSocketHost(); + }); + + afterAll(async () => { + if (ledger) { + log.info("Closing ethereum ledger"); + await ledger.stop(); + await ledger.destroy(); + } + + const pruning = pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + await expect(pruning).resolves.toBeTruthy(); + }); + + ////////////////////////////////// + // Tests + ////////////////////////////////// + + /** + * Test suite will run for the following setups: + * - WS ethereum node (subscription method) + * - HTTP ethereum node (HTTP polling method) + */ + describe.each([[NODE_TYPE_WEBSOCKET], [NODE_TYPE_HTTP]])( + "Monitoring ethereum blocks with %p node connection test", + (nodeType: string) => { + let apiClient: EthereumApiClient; + let connector: PluginLedgerConnectorEthereum; + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + const wsApi = new SocketIoServer(server, { + path: Constants.SocketIoConnectionPathV1, + }); + + beforeAll(async () => { + log.warn("Using ledger node connection type:", nodeType); + + const addressInfo = await Servers.listen({ + hostname: "127.0.0.1", + port: 0, + server, + }); + apiClient = new EthereumApiClient( + new Configuration({ + basePath: `http://${addressInfo.address}:${addressInfo.port}`, + }), + ); + + connector = new PluginLedgerConnectorEthereum({ + instanceId: uuidV4(), + rpcApiHttpHost: + nodeType === NODE_TYPE_HTTP ? rpcApiHttpHost : undefined, + rpcApiWsHost: + nodeType === NODE_TYPE_WEBSOCKET ? rpcApiWsHost : undefined, + logLevel: testLogLevel, + pluginRegistry: new PluginRegistry({ plugins: [] }), + }); + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp, wsApi); + }); + + afterAll(async () => { + if (server) { + log.info("Shutdown connector servers"); + await Servers.shutdown(server); + } + + if (connector) { + log.info("Shutdown connector"); + await connector.shutdown(); + } + }); + + test( + "Monitor new blocks headers on Ethereum", + async () => { + const ledgerEvents = await testWatchBlock(apiClient, false); + expect(ledgerEvents).toBeTruthy(); + expect(ledgerEvents.length).toEqual(1); + const ledgerEvent = ledgerEvents[0]; + // blockData should not be present if called with empty options + expect(ledgerEvent.blockData).toBeUndefined(); + expect(ledgerEvent.blockHeader).toBeTruthy(); + expect((ledgerEvent as any).blockHeader.transactions).toBeUndefined(); + + // check some fields + assertBlockHeader(ledgerEvent.blockHeader); + }, + asyncTestTimeout, + ); + + test( + "Monitor new blocks data on Ethereum", + async () => { + const ledgerEvents = await testWatchBlock(apiClient, true); + expect(ledgerEvents).toBeTruthy(); + expect(ledgerEvents.length).toEqual(1); + const ledgerEvent = ledgerEvents[0]; + // blockHeader should not be present if called with getBlockData option + expect(ledgerEvent.blockHeader).toBeUndefined(); + expect(ledgerEvent.blockData).toBeTruthy(); + + // check some fields + assertBlockHeader(ledgerEvent.blockData as Web3BlockHeader); + expect(typeof ledgerEvent.blockData?.transactions).toEqual("object"); + expect(typeof ledgerEvent.blockData?.size).toEqual("string"); + expect(typeof ledgerEvent.blockData?.totalDifficulty).toEqual( + "string", + ); + expect(typeof ledgerEvent.blockData?.uncles).toEqual("object"); + }, + asyncTestTimeout, + ); + + /** + * Tests checks if missing blocks since lastSeenBlock are also pushed, and also that: + * - Blocks are reported in order + * - Blocks are not duplicated + */ + test( + "Monitor pushes missing block since lastSeenBlock", + async () => { + const missingBlocksCount = 3; + + // Wait until some blocks are created + const olderBlocks = await testWatchBlock( + apiClient, + false, + missingBlocksCount, + ); + expect(olderBlocks).toBeTruthy(); + expect(olderBlocks.length).toEqual(missingBlocksCount); + const missingBlockNumbers = olderBlocks.map((block) => + parseInt(block.blockHeader?.number as string, 10), + ); + // should be pushed in order + expect(missingBlockNumbers).toEqual( + missingBlockNumbers.sort((a, b) => a - b), + ); + // should push unique blocks (no duplicates) + expect(new Set(missingBlockNumbers).size).toEqual( + missingBlockNumbers.length, + ); + log.debug("missingBlockNumbers:", missingBlockNumbers); + + // get blocks including missing ones + const newBlocksToGet = 1; + const blocksWithMissingOnes = await testWatchBlock( + apiClient, + false, + missingBlocksCount + newBlocksToGet, // wait for all the missing and some new blocks + missingBlockNumbers[0] - 1, // assume we've seen one block before the first missing one + ); + expect(blocksWithMissingOnes).toBeTruthy(); + expect(blocksWithMissingOnes.length).toEqual( + missingBlocksCount + newBlocksToGet, + ); + const returnedBlockNumbers = blocksWithMissingOnes.map((block) => + parseInt(block.blockHeader?.number as string, 10), + ); + // should be pushed in order + expect(returnedBlockNumbers).toEqual( + returnedBlockNumbers.sort((a, b) => a - b), + ); + // should push unique blocks (no duplicates) + expect(new Set(returnedBlockNumbers).size).toEqual( + returnedBlockNumbers.length, + ); + log.debug("returnedBlockNumbers:", returnedBlockNumbers); + + // Ensure missing blocks were returned + expect(returnedBlockNumbers).toIncludeAllMembers(missingBlockNumbers); + expect(returnedBlockNumbers.slice(0, missingBlocksCount)).toEqual( + missingBlockNumbers, + ); // should start with the missing blocks + }, + asyncTestTimeout, + ); + }, + ); +}); diff --git a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-transact-and-gas-fees.test.ts b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-transact-and-gas-fees.test.ts index 668274459c..4b8cadff0e 100644 --- a/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-transact-and-gas-fees.test.ts +++ b/packages/cactus-plugin-ledger-connector-ethereum/src/test/typescript/integration/geth-transact-and-gas-fees.test.ts @@ -41,7 +41,7 @@ const containerImageName = "ghcr.io/hyperledger/cacti-geth-all-in-one"; const containerImageVersion = "2023-07-27-2a8c48ed6"; describe("Running ethereum transactions with different gas configurations", () => { - let web3: Web3, + let web3: InstanceType, addressInfo, address: string, port: number, diff --git a/packages/cactus-test-plugin-ledger-connector-ethereum/package.json b/packages/cactus-test-plugin-ledger-connector-ethereum/package.json index 5bc2e5a5c3..1244f6dbdc 100644 --- a/packages/cactus-test-plugin-ledger-connector-ethereum/package.json +++ b/packages/cactus-test-plugin-ledger-connector-ethereum/package.json @@ -57,7 +57,7 @@ "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.0.0-alpha.2", "@hyperledger/cactus-verifier-client": "2.0.0-alpha.2", - "web3-eth-contract": "4.1.0" + "web3-eth-contract": "4.2.0" }, "devDependencies": { "@hyperledger/cactus-test-geth-ledger": "2.0.0-alpha.2", @@ -66,7 +66,7 @@ "@types/uuid": "9.0.6", "lodash": "4.17.21", "uuid": "9.0.1", - "web3": "4.1.0" + "web3": "4.4.0" }, "engines": { "node": ">=18", diff --git a/packages/cactus-test-plugin-ledger-connector-ethereum/src/test/typescript/integration/api-client/verifier-integration-with-ethereum-connector.test.ts b/packages/cactus-test-plugin-ledger-connector-ethereum/src/test/typescript/integration/api-client/verifier-integration-with-ethereum-connector.test.ts index 01e78c8a11..dd5138ce84 100644 --- a/packages/cactus-test-plugin-ledger-connector-ethereum/src/test/typescript/integration/api-client/verifier-integration-with-ethereum-connector.test.ts +++ b/packages/cactus-test-plugin-ledger-connector-ethereum/src/test/typescript/integration/api-client/verifier-integration-with-ethereum-connector.test.ts @@ -22,7 +22,6 @@ import { PluginLedgerConnectorEthereum, EthereumApiClient, WatchBlocksV1Progress, - Web3BlockHeader, Web3SigningCredentialType, } from "@hyperledger/cactus-plugin-ledger-connector-ethereum"; import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; @@ -63,7 +62,7 @@ describe("Verifier integration with ethereum connector tests", () => { let ethereumTestLedger: GethTestLedger; let apiServer: ApiServer; let connector: PluginLedgerConnectorEthereum; - let web3: Web3; + let web3: InstanceType; let keychainPlugin: PluginKeychainMemory; const ethereumValidatorId = "testEthereumId"; let globalVerifierFactory: VerifierFactory; @@ -578,59 +577,4 @@ describe("Verifier integration with ethereum connector tests", () => { console.log("sendSyncRequest failed as expected"); } }); - - function assertBlockHeader(header?: Web3BlockHeader) { - if (!header) { - throw new Error("Header is missing!"); - } - - // Check if defined and with expected type - // Ignore nullable / undefine-able fields - expect(typeof header.parentHash).toEqual("string"); - expect(typeof header.sha3Uncles).toEqual("string"); - expect(typeof header.miner).toEqual("string"); - expect(typeof header.number).toEqual("string"); - expect(typeof header.gasLimit).toEqual("string"); - expect(typeof header.gasUsed).toEqual("string"); - expect(typeof header.difficulty).toEqual("string"); - } - - test("Monitor new blocks headers on Ethereum", async () => { - const ledgerEvent = await monitorAndGetBlock(); - // assert well-formed output - expect(ledgerEvent.id).toEqual(""); - expect(ledgerEvent.verifierId).toEqual(ethereumValidatorId); - expect(ledgerEvent.data).toBeTruthy(); - - // blockData should not be present if called with empty options - expect(ledgerEvent.data?.blockData).toBeUndefined(); - expect(ledgerEvent.data?.blockHeader).toBeTruthy(); - - // check some fields - assertBlockHeader(ledgerEvent.data?.blockHeader); - }); - - test("Monitor new blocks data on Ethereum", async () => { - const ledgerEvent = await monitorAndGetBlock({ getBlockData: true }); - //const ledgerEvent = await monitorAndGetBlock(); - log.info("ledgerEvent", ledgerEvent); - // assert well-formed output - expect(ledgerEvent.id).toEqual(""); - expect(ledgerEvent.verifierId).toEqual(ethereumValidatorId); - expect(ledgerEvent.data).toBeTruthy(); - - // blockHeader should not be present if called with getBlockData option - expect(ledgerEvent.data?.blockHeader).toBeFalsy(); - expect(ledgerEvent.data?.blockData).toBeTruthy(); - - // check some fields - assertBlockHeader( - ledgerEvent.data?.blockData as unknown as Web3BlockHeader, - ); // remove as unknown - expect(typeof ledgerEvent.data?.blockData?.size).toEqual("string"); - expect(typeof ledgerEvent.data?.blockData?.totalDifficulty).toEqual( - "string", - ); - expect(typeof ledgerEvent.data?.blockData?.uncles).toEqual("object"); - }); }); diff --git a/yarn.lock b/yarn.lock index e87fe39f72..333145d3fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7896,10 +7896,10 @@ __metadata: socket.io-client-fixed-types: 4.5.4 typescript-optional: 2.0.1 uuid: 9.0.1 - web3: 4.1.2 - web3-eth: 4.2.0 - web3-eth-accounts: 4.0.6 - web3-eth-contract: 4.1.0 + web3: 4.4.0 + web3-eth: 4.4.0 + web3-eth-accounts: 4.1.1 + web3-eth-contract: 4.2.0 bin: cacti-ethereum-connector-status: dist/lib/scripts/get-ethereum-connector-status.js languageName: unknown @@ -8480,8 +8480,8 @@ __metadata: "@types/uuid": 9.0.6 lodash: 4.17.21 uuid: 9.0.1 - web3: 4.1.0 - web3-eth-contract: 4.1.0 + web3: 4.4.0 + web3-eth-contract: 4.2.0 languageName: unknown linkType: soft @@ -49489,7 +49489,7 @@ __metadata: languageName: node linkType: hard -"web3-core@npm:^4.1.0, web3-core@npm:^4.3.0": +"web3-core@npm:^4.3.0": version: 4.3.0 resolution: "web3-core@npm:4.3.0" dependencies: @@ -49508,41 +49508,42 @@ __metadata: languageName: node linkType: hard -"web3-core@npm:^4.2.0": - version: 4.2.0 - resolution: "web3-core@npm:4.2.0" +"web3-core@npm:^4.3.1": + version: 4.3.1 + resolution: "web3-core@npm:4.3.1" dependencies: - web3-errors: ^1.1.2 - web3-eth-iban: ^4.0.6 - web3-providers-http: ^4.0.6 - web3-providers-ipc: ^4.0.6 - web3-providers-ws: ^4.0.6 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 + web3-errors: ^1.1.4 + web3-eth-iban: ^4.0.7 + web3-providers-http: ^4.1.0 + web3-providers-ipc: ^4.0.7 + web3-providers-ws: ^4.0.7 + web3-types: ^1.3.1 + web3-utils: ^4.0.7 + web3-validator: ^2.0.3 dependenciesMeta: web3-providers-ipc: optional: true - checksum: d3514d078d74ab13d2ca25738499dc58347fd7f42af4e98fe31367b404f7fc6260a7ad3cd1c1480077c2960fb874f9e3fdbaf8fb1424d0537c76d8c0e88dc74e + checksum: f6ba6ef0154d9523aee5d9b375f339bf5b817be88fa6f574bde80359104d93c50586c09db3b42044c5ee6a970f84fce5554de5067d17934daa59fb92f4cc9dd5 languageName: node linkType: hard -"web3-core@npm:^4.3.1": - version: 4.3.1 - resolution: "web3-core@npm:4.3.1" +"web3-core@npm:^4.3.2": + version: 4.3.2 + resolution: "web3-core@npm:4.3.2" dependencies: web3-errors: ^1.1.4 + web3-eth-accounts: ^4.1.0 web3-eth-iban: ^4.0.7 web3-providers-http: ^4.1.0 web3-providers-ipc: ^4.0.7 web3-providers-ws: ^4.0.7 web3-types: ^1.3.1 - web3-utils: ^4.0.7 + web3-utils: ^4.1.0 web3-validator: ^2.0.3 dependenciesMeta: web3-providers-ipc: optional: true - checksum: f6ba6ef0154d9523aee5d9b375f339bf5b817be88fa6f574bde80359104d93c50586c09db3b42044c5ee6a970f84fce5554de5067d17934daa59fb92f4cc9dd5 + checksum: 7505186c5b7de1ebf03bbf9ce109c809618652402ed01e93a98292432a2d31f958cb284af8b7a286a149736f0943839a098150d02034232036243b058f57d739 languageName: node linkType: hard @@ -49555,15 +49556,6 @@ __metadata: languageName: node linkType: hard -"web3-errors@npm:^1.1.0, web3-errors@npm:^1.1.3": - version: 1.1.3 - resolution: "web3-errors@npm:1.1.3" - dependencies: - web3-types: ^1.3.0 - checksum: d9c61ff437daa9257e1ee38120e3eb8a907f6afd4da36777ab264487d35781b4bb15489fb0d9edc9668fb0ba6ec5d325a33f20add8f88c5418d7b48596098347 - languageName: node - linkType: hard - "web3-errors@npm:^1.1.1": version: 1.1.1 resolution: "web3-errors@npm:1.1.1" @@ -49582,6 +49574,15 @@ __metadata: languageName: node linkType: hard +"web3-errors@npm:^1.1.3": + version: 1.1.3 + resolution: "web3-errors@npm:1.1.3" + dependencies: + web3-types: ^1.3.0 + checksum: d9c61ff437daa9257e1ee38120e3eb8a907f6afd4da36777ab264487d35781b4bb15489fb0d9edc9668fb0ba6ec5d325a33f20add8f88c5418d7b48596098347 + languageName: node + linkType: hard + "web3-errors@npm:^1.1.4": version: 1.1.4 resolution: "web3-errors@npm:1.1.4" @@ -49677,42 +49678,42 @@ __metadata: languageName: node linkType: hard -"web3-eth-abi@npm:^4.1.0, web3-eth-abi@npm:^4.1.4": - version: 4.1.4 - resolution: "web3-eth-abi@npm:4.1.4" +"web3-eth-abi@npm:^4.1.3": + version: 4.1.3 + resolution: "web3-eth-abi@npm:4.1.3" dependencies: abitype: 0.7.1 web3-errors: ^1.1.3 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 35b1db84ab4490e71d79709676e173883295225fe433f3f75b77a7ebc5be4474a8feccc19b08ddece292f7195bfa9658f8f312822ac52165d9796c275ac4dd6d - languageName: node - linkType: hard - -"web3-eth-abi@npm:^4.1.2": - version: 4.1.2 - resolution: "web3-eth-abi@npm:4.1.2" - dependencies: - "@ethersproject/abi": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - checksum: 72c4374a29e6db0e2ddf74a8cc952c74a9cda16150c3a6df7fd54848ee00519b544dd313eadbfea53584f01eccd0ba285f5119bc8323bb5199678639ad28eda3 + checksum: 82739061ed63e2cac9ce9fdce9deecd6c4996621f4edf2ac501f3fd0a59d42b95ea253ffa63131bbf9a4eec43060501077190ffb17458bebe6a7cdf833b4d340 languageName: node linkType: hard -"web3-eth-abi@npm:^4.1.3": - version: 4.1.3 - resolution: "web3-eth-abi@npm:4.1.3" +"web3-eth-abi@npm:^4.1.4": + version: 4.1.4 + resolution: "web3-eth-abi@npm:4.1.4" dependencies: abitype: 0.7.1 web3-errors: ^1.1.3 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 82739061ed63e2cac9ce9fdce9deecd6c4996621f4edf2ac501f3fd0a59d42b95ea253ffa63131bbf9a4eec43060501077190ffb17458bebe6a7cdf833b4d340 + checksum: 35b1db84ab4490e71d79709676e173883295225fe433f3f75b77a7ebc5be4474a8feccc19b08ddece292f7195bfa9658f8f312822ac52165d9796c275ac4dd6d + languageName: node + linkType: hard + +"web3-eth-abi@npm:^4.2.0": + version: 4.2.0 + resolution: "web3-eth-abi@npm:4.2.0" + dependencies: + abitype: 0.7.1 + web3-errors: ^1.1.4 + web3-types: ^1.3.1 + web3-utils: ^4.1.1 + web3-validator: ^2.0.4 + checksum: 4abe8d2457ff55dab158f26831133bb2232d17d8c53bb4e00d6c0f921b61cefea630d65bc778d899d99f2189c69a5fe21f0fbf61fe20cb1d5d6561e8b9a3b66e languageName: node linkType: hard @@ -49843,18 +49844,18 @@ __metadata: languageName: node linkType: hard -"web3-eth-accounts@npm:4.0.6, web3-eth-accounts@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-eth-accounts@npm:4.0.6" +"web3-eth-accounts@npm:4.1.1, web3-eth-accounts@npm:^4.1.1": + version: 4.1.1 + resolution: "web3-eth-accounts@npm:4.1.1" dependencies: "@ethereumjs/rlp": ^4.0.1 crc-32: ^1.2.2 ethereum-cryptography: ^2.0.0 - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: 07fc3f5b6ccb862696ea2c34cc104323ad2b1e85c54bb8bd8dcb61154b09f592a2cc899ff0ac7bdd2a2e6f39afe3a4cdf2e7630ddc9b4150bf0b45e7004fe209 + web3-errors: ^1.1.4 + web3-types: ^1.3.1 + web3-utils: ^4.1.1 + web3-validator: ^2.0.4 + checksum: f87f0bdf7b0bce35adb3ffd7039888c876576bcf3b82651ff2e86dde75282fcc8a5d92569e9f7a1fc441df7c52e3d6feceac608066d4c54ec5fc696ff9804de1 languageName: node linkType: hard @@ -49873,7 +49874,7 @@ __metadata: languageName: node linkType: hard -"web3-eth-accounts@npm:^4.0.4, web3-eth-accounts@npm:^4.1.0": +"web3-eth-accounts@npm:^4.1.0": version: 4.1.0 resolution: "web3-eth-accounts@npm:4.1.0" dependencies: @@ -49984,18 +49985,18 @@ __metadata: languageName: node linkType: hard -"web3-eth-contract@npm:4.1.0, web3-eth-contract@npm:^4.1.0": - version: 4.1.0 - resolution: "web3-eth-contract@npm:4.1.0" +"web3-eth-contract@npm:4.2.0, web3-eth-contract@npm:^4.2.0": + version: 4.2.0 + resolution: "web3-eth-contract@npm:4.2.0" dependencies: - web3-core: ^4.2.0 - web3-errors: ^1.1.2 - web3-eth: ^4.2.0 - web3-eth-abi: ^4.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: 063f2c12f10c17040362f7a88865a7a727f875d7a51e69f5c804b16e61813d79af7b1c1016a856c8a2ceb585ba8f60881eb66e4df5106ff36ce4bae16fe0340b + web3-core: ^4.3.2 + web3-errors: ^1.1.4 + web3-eth: ^4.4.0 + web3-eth-abi: ^4.2.0 + web3-types: ^1.3.1 + web3-utils: ^4.1.1 + web3-validator: ^2.0.4 + checksum: 0547609dd9c2b4c30562304a1ade703f7cdf9acfc995e0719bbbeacb386ce76422bd713a915222e1dfcbc8564ebab322e64b965b18fc51dc066b1aabf29011e8 languageName: node linkType: hard @@ -50014,33 +50015,33 @@ __metadata: languageName: node linkType: hard -"web3-eth-contract@npm:^4.0.4, web3-eth-contract@npm:^4.1.2": - version: 4.1.2 - resolution: "web3-eth-contract@npm:4.1.2" +"web3-eth-contract@npm:^4.1.1": + version: 4.1.3 + resolution: "web3-eth-contract@npm:4.1.3" dependencies: - web3-core: ^4.3.0 - web3-errors: ^1.1.3 + web3-core: ^4.3.1 + web3-errors: ^1.1.4 web3-eth: ^4.3.1 web3-eth-abi: ^4.1.4 - web3-types: ^1.3.0 + web3-types: ^1.3.1 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 209fd9dfa0d70434dbf37b933024777bc4b5be3cfba46ea331c28ea131c446fc7e33671fb2013588e09fbcab598f47386b37384bcf6891bd4237ef750b303d85 + checksum: 3e578ecffb982e67e06269fa53099b39634c81843abdf8b2d048d35089b6d1a8332e9ceba837aec2496740f1f3c620086c6e802cc9be15538e43bb5c74951cd6 languageName: node linkType: hard -"web3-eth-contract@npm:^4.1.1": - version: 4.1.3 - resolution: "web3-eth-contract@npm:4.1.3" +"web3-eth-contract@npm:^4.1.2": + version: 4.1.2 + resolution: "web3-eth-contract@npm:4.1.2" dependencies: - web3-core: ^4.3.1 - web3-errors: ^1.1.4 + web3-core: ^4.3.0 + web3-errors: ^1.1.3 web3-eth: ^4.3.1 web3-eth-abi: ^4.1.4 - web3-types: ^1.3.1 + web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 3e578ecffb982e67e06269fa53099b39634c81843abdf8b2d048d35089b6d1a8332e9ceba837aec2496740f1f3c620086c6e802cc9be15538e43bb5c74951cd6 + checksum: 209fd9dfa0d70434dbf37b933024777bc4b5be3cfba46ea331c28ea131c446fc7e33671fb2013588e09fbcab598f47386b37384bcf6891bd4237ef750b303d85 languageName: node linkType: hard @@ -50157,54 +50158,37 @@ __metadata: languageName: node linkType: hard -"web3-eth-ens@npm:^4.0.4": - version: 4.0.8 - resolution: "web3-eth-ens@npm:4.0.8" +"web3-eth-ens@npm:^4.0.7": + version: 4.0.7 + resolution: "web3-eth-ens@npm:4.0.7" dependencies: "@adraffy/ens-normalize": ^1.8.8 web3-core: ^4.3.0 web3-errors: ^1.1.3 - web3-eth: ^4.3.1 - web3-eth-contract: ^4.1.2 + web3-eth: ^4.3.0 + web3-eth-contract: ^4.1.1 web3-net: ^4.0.7 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 78c47d003b7b36845886ca85d815d4209d83f2f112b32abb9a996a87a849840cb79391b40ddd5273337e29642e5b59afecc6e2143a19462cda7bf59f4cba1c2c - languageName: node - linkType: hard - -"web3-eth-ens@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-eth-ens@npm:4.0.6" - dependencies: - "@adraffy/ens-normalize": ^1.8.8 - web3-core: ^4.2.0 - web3-errors: ^1.1.2 - web3-eth: ^4.2.0 - web3-eth-contract: ^4.1.0 - web3-net: ^4.0.6 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: 8417a5938c59f2a7d04b103c36868ea612d88afc18c35783ab60c48b375d355b47b994d753ad8507a304b3845d2f8e5d812e9ada5105ad276051f7305ccedafa + checksum: b8222fd5d9395767e3a585006fa89d1e85feb5625f53fe1a57c81a7031b27fb9405287f964ec3285963332c51db8de1a618e08e8034c43d54455d53c5000dcaf languageName: node linkType: hard -"web3-eth-ens@npm:^4.0.7": - version: 4.0.7 - resolution: "web3-eth-ens@npm:4.0.7" +"web3-eth-ens@npm:^4.0.8": + version: 4.0.8 + resolution: "web3-eth-ens@npm:4.0.8" dependencies: "@adraffy/ens-normalize": ^1.8.8 web3-core: ^4.3.0 web3-errors: ^1.1.3 - web3-eth: ^4.3.0 - web3-eth-contract: ^4.1.1 + web3-eth: ^4.3.1 + web3-eth-contract: ^4.1.2 web3-net: ^4.0.7 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: b8222fd5d9395767e3a585006fa89d1e85feb5625f53fe1a57c81a7031b27fb9405287f964ec3285963332c51db8de1a618e08e8034c43d54455d53c5000dcaf + checksum: 78c47d003b7b36845886ca85d815d4209d83f2f112b32abb9a996a87a849840cb79391b40ddd5273337e29642e5b59afecc6e2143a19462cda7bf59f4cba1c2c languageName: node linkType: hard @@ -50290,7 +50274,7 @@ __metadata: languageName: node linkType: hard -"web3-eth-iban@npm:^4.0.4, web3-eth-iban@npm:^4.0.7": +"web3-eth-iban@npm:^4.0.7": version: 4.0.7 resolution: "web3-eth-iban@npm:4.0.7" dependencies: @@ -50302,18 +50286,6 @@ __metadata: languageName: node linkType: hard -"web3-eth-iban@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-eth-iban@npm:4.0.6" - dependencies: - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: 7932961def8972aae01b409e28a98ccda6aece344bd3741bf967304b878a1722d77805d364ff61ca71c70cda937aadb077b506c9671e6b33db88c6a4e59ce5e8 - languageName: node - linkType: hard - "web3-eth-personal@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-personal@npm:1.10.0" @@ -50412,45 +50384,31 @@ __metadata: languageName: node linkType: hard -"web3-eth-personal@npm:^4.0.4": - version: 4.0.8 - resolution: "web3-eth-personal@npm:4.0.8" +"web3-eth-personal@npm:^4.0.7": + version: 4.0.7 + resolution: "web3-eth-personal@npm:4.0.7" dependencies: web3-core: ^4.3.0 - web3-eth: ^4.3.1 + web3-eth: ^4.3.0 web3-rpc-methods: ^1.1.3 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: 73e6f4f10548c1a564a0c8d34b8c841b9c52281a6b19a368d7dcdb4910c7c60310f954c14b05932062fb2f3343cb4102d282399ca1a900e44d4e2317ee8d5d7c - languageName: node - linkType: hard - -"web3-eth-personal@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-eth-personal@npm:4.0.6" - dependencies: - web3-core: ^4.2.0 - web3-eth: ^4.2.0 - web3-rpc-methods: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: 7d6066b3cdaa20e6c19b581c44feea546fe0dd32b5f7db502626db2bd90de1e034cf36dcb5262fe3fdb145665925ae4cc81cb3ae051b7cf38765cd0a7e638ca8 + checksum: d5235c167ce85b654ca9747818d7baf8848c9f5328eb1fdec5859ffb3283e1499d74491705f89e84322315e18f92f876d533c8f80d07757fae7ca3e0103df82e languageName: node linkType: hard -"web3-eth-personal@npm:^4.0.7": - version: 4.0.7 - resolution: "web3-eth-personal@npm:4.0.7" +"web3-eth-personal@npm:^4.0.8": + version: 4.0.8 + resolution: "web3-eth-personal@npm:4.0.8" dependencies: web3-core: ^4.3.0 - web3-eth: ^4.3.0 + web3-eth: ^4.3.1 web3-rpc-methods: ^1.1.3 web3-types: ^1.3.0 web3-utils: ^4.0.7 web3-validator: ^2.0.3 - checksum: d5235c167ce85b654ca9747818d7baf8848c9f5328eb1fdec5859ffb3283e1499d74491705f89e84322315e18f92f876d533c8f80d07757fae7ca3e0103df82e + checksum: 73e6f4f10548c1a564a0c8d34b8c841b9c52281a6b19a368d7dcdb4910c7c60310f954c14b05932062fb2f3343cb4102d282399ca1a900e44d4e2317ee8d5d7c languageName: node linkType: hard @@ -50593,26 +50551,26 @@ __metadata: languageName: node linkType: hard -"web3-eth@npm:4.2.0, web3-eth@npm:^4.2.0": - version: 4.2.0 - resolution: "web3-eth@npm:4.2.0" +"web3-eth@npm:4.4.0, web3-eth@npm:^4.4.0": + version: 4.4.0 + resolution: "web3-eth@npm:4.4.0" dependencies: setimmediate: ^1.0.5 - web3-core: ^4.2.0 - web3-errors: ^1.1.2 - web3-eth-abi: ^4.1.2 - web3-eth-accounts: ^4.0.6 - web3-net: ^4.0.6 - web3-providers-ws: ^4.0.6 - web3-rpc-methods: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: e8453ced9c2e9b12a2c80d0383d568ba597c9ca052b4a847794758a6c1589c35b919ceddedef8aaab7abdb800d15ff4cb6103c7ccbccb41e6e3cf1bb61344071 + web3-core: ^4.3.2 + web3-errors: ^1.1.4 + web3-eth-abi: ^4.2.0 + web3-eth-accounts: ^4.1.1 + web3-net: ^4.0.7 + web3-providers-ws: ^4.0.7 + web3-rpc-methods: ^1.1.4 + web3-types: ^1.3.1 + web3-utils: ^4.1.1 + web3-validator: ^2.0.4 + checksum: a65af603ea5e6a985127deaa511eb606d0fd2b916b07094db1dd396a0d5bea1b45a0ef839c5b5d997609aabca3025d60ec42c562c7efcc32fe3f32c4f763d05b languageName: node linkType: hard -"web3-eth@npm:^4.1.0, web3-eth@npm:^4.3.0, web3-eth@npm:^4.3.1": +"web3-eth@npm:^4.3.0, web3-eth@npm:^4.3.1": version: 4.3.1 resolution: "web3-eth@npm:4.3.1" dependencies: @@ -50709,7 +50667,7 @@ __metadata: languageName: node linkType: hard -"web3-net@npm:^4.0.4, web3-net@npm:^4.0.7": +"web3-net@npm:^4.0.7": version: 4.0.7 resolution: "web3-net@npm:4.0.7" dependencies: @@ -50721,18 +50679,6 @@ __metadata: languageName: node linkType: hard -"web3-net@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-net@npm:4.0.6" - dependencies: - web3-core: ^4.2.0 - web3-rpc-methods: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - checksum: 840ae451ca7cd7386cf68d1839bd4bf9ceda987bd8e74dee179375ab4297d36fddff7b4ec1472f66779326714e8c90912f612c124facea75c2039b3ac06d1e42 - languageName: node - linkType: hard - "web3-providers-http@npm:1.10.0": version: 1.10.0 resolution: "web3-providers-http@npm:1.10.0" @@ -50821,7 +50767,7 @@ __metadata: languageName: node linkType: hard -"web3-providers-http@npm:^4.0.4, web3-providers-http@npm:^4.1.0": +"web3-providers-http@npm:^4.1.0": version: 4.1.0 resolution: "web3-providers-http@npm:4.1.0" dependencies: @@ -50833,18 +50779,6 @@ __metadata: languageName: node linkType: hard -"web3-providers-http@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-providers-http@npm:4.0.6" - dependencies: - cross-fetch: ^3.1.5 - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - checksum: a15b282a711c8a67ec69f2f54e057ef23ae67cd0f9bbe0f6189a8f7059bb5d80b55a1635eb2f13ff6e3a2fed13e18b67cdf60305ae1a35ff95fc1b288daaf7b5 - languageName: node - linkType: hard - "web3-providers-ipc@npm:1.10.0": version: 1.10.0 resolution: "web3-providers-ipc@npm:1.10.0" @@ -50926,17 +50860,6 @@ __metadata: languageName: node linkType: hard -"web3-providers-ipc@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-providers-ipc@npm:4.0.6" - dependencies: - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - checksum: 2939b47ab2828106f79df5a7c96b3a15802565ce8f72b8b3684af65925a930c9298ed691e94589871ba87e70a4f626669f9087e25b7aa9086fca205dc415b8ac - languageName: node - linkType: hard - "web3-providers-ipc@npm:^4.0.7": version: 4.0.7 resolution: "web3-providers-ipc@npm:4.0.7" @@ -51039,7 +50962,7 @@ __metadata: languageName: node linkType: hard -"web3-providers-ws@npm:^4.0.4, web3-providers-ws@npm:^4.0.7": +"web3-providers-ws@npm:^4.0.7": version: 4.0.7 resolution: "web3-providers-ws@npm:4.0.7" dependencies: @@ -51053,20 +50976,6 @@ __metadata: languageName: node linkType: hard -"web3-providers-ws@npm:^4.0.6": - version: 4.0.6 - resolution: "web3-providers-ws@npm:4.0.6" - dependencies: - "@types/ws": 8.5.3 - isomorphic-ws: ^5.0.0 - web3-errors: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - ws: ^8.8.1 - checksum: af43ccabafcf85ef363bcb13796cee1c8849283fff822d25d7044774917fe5827c8f93dcf55dd98d1540b3198cb1c4bc65b01985af1791f764ef6a8a5f197f4a - languageName: node - linkType: hard - "web3-rpc-methods@npm:^1.0.2, web3-rpc-methods@npm:^1.1.1": version: 1.1.1 resolution: "web3-rpc-methods@npm:1.1.1" @@ -51078,7 +50987,7 @@ __metadata: languageName: node linkType: hard -"web3-rpc-methods@npm:^1.1.0, web3-rpc-methods@npm:^1.1.3": +"web3-rpc-methods@npm:^1.1.3": version: 1.1.3 resolution: "web3-rpc-methods@npm:1.1.3" dependencies: @@ -51089,14 +50998,14 @@ __metadata: languageName: node linkType: hard -"web3-rpc-methods@npm:^1.1.2": - version: 1.1.2 - resolution: "web3-rpc-methods@npm:1.1.2" +"web3-rpc-methods@npm:^1.1.4": + version: 1.1.4 + resolution: "web3-rpc-methods@npm:1.1.4" dependencies: - web3-core: ^4.2.0 - web3-types: ^1.2.0 - web3-validator: ^2.0.2 - checksum: 452dcd18993d7fa2ab37a062d39a317100223b65f13fa9ecc0e95d91e05312e013b7cc3e21aaaf583f8a3261e819022d69d1c1ab1ac65a40afe14d28ff11becf + web3-core: ^4.3.2 + web3-types: ^1.3.1 + web3-validator: ^2.0.3 + checksum: b51098af5eaee5f57f5684a1b6e3763f61d8141de398a4457ed2cdca2a4e7fabe49de1ef597694e98581884d5c0d74fec697fbf8d67baa3ad5d10f1e131d6c43 languageName: node linkType: hard @@ -51179,13 +51088,6 @@ __metadata: languageName: node linkType: hard -"web3-types@npm:^1.1.0, web3-types@npm:^1.3.0": - version: 1.3.0 - resolution: "web3-types@npm:1.3.0" - checksum: 1d0319dce670c7f288fd7347421c79871f38a703634191265bd0d357a009ddbf7d972fd758894349501229e1ce2e88d0db3a95436667f7d8c19cb7414672f450 - languageName: node - linkType: hard - "web3-types@npm:^1.1.1": version: 1.1.1 resolution: "web3-types@npm:1.1.1" @@ -51200,6 +51102,13 @@ __metadata: languageName: node linkType: hard +"web3-types@npm:^1.3.0": + version: 1.3.0 + resolution: "web3-types@npm:1.3.0" + checksum: 1d0319dce670c7f288fd7347421c79871f38a703634191265bd0d357a009ddbf7d972fd758894349501229e1ce2e88d0db3a95436667f7d8c19cb7414672f450 + languageName: node + linkType: hard + "web3-types@npm:^1.3.1": version: 1.3.1 resolution: "web3-types@npm:1.3.1" @@ -51337,7 +51246,7 @@ __metadata: languageName: node linkType: hard -"web3-utils@npm:4.0.6, web3-utils@npm:^4.0.6": +"web3-utils@npm:4.0.6": version: 4.0.6 resolution: "web3-utils@npm:4.0.6" dependencies: @@ -51349,7 +51258,7 @@ __metadata: languageName: node linkType: hard -"web3-utils@npm:^4.0.4, web3-utils@npm:^4.0.7": +"web3-utils@npm:^4.0.7": version: 4.0.7 resolution: "web3-utils@npm:4.0.7" dependencies: @@ -51361,6 +51270,30 @@ __metadata: languageName: node linkType: hard +"web3-utils@npm:^4.1.0": + version: 4.1.0 + resolution: "web3-utils@npm:4.1.0" + dependencies: + ethereum-cryptography: ^2.0.0 + web3-errors: ^1.1.4 + web3-types: ^1.3.1 + web3-validator: ^2.0.3 + checksum: 5072ebc78ac62f26b5e17043f327f1046b4284a8e8a80f4771712ee9fc2ee895a0e292a225785b7392b647b6edc090d57f2262de5efd0a19571cd583c708c1c3 + languageName: node + linkType: hard + +"web3-utils@npm:^4.1.1": + version: 4.1.1 + resolution: "web3-utils@npm:4.1.1" + dependencies: + ethereum-cryptography: ^2.0.0 + web3-errors: ^1.1.4 + web3-types: ^1.3.1 + web3-validator: ^2.0.4 + checksum: 040240845c388d3e040cccae75f6369b0b06f5b260aef4f888ef54471e0b0d6704f3a485d904aba5b957494021733c281f6032454de22ad9e6e8f9301573e54d + languageName: node + linkType: hard + "web3-validator@npm:2.0.2, web3-validator@npm:^2.0.2": version: 2.0.2 resolution: "web3-validator@npm:2.0.2" @@ -51387,7 +51320,20 @@ __metadata: languageName: node linkType: hard -"web3-validator@npm:^2.0.0, web3-validator@npm:^2.0.3": +"web3-validator@npm:^2.0.1": + version: 2.0.1 + resolution: "web3-validator@npm:2.0.1" + dependencies: + ethereum-cryptography: ^2.0.0 + util: ^0.12.5 + web3-errors: ^1.1.1 + web3-types: ^1.1.1 + zod: ^3.21.4 + checksum: 4382a0d034751ca04d3f919efd4f1115abecee8541585179158662e46dd10b051c4ee29c885067d7aeff618dec971c4a2075baeb7df63249e3ed5b2d5695b782 + languageName: node + linkType: hard + +"web3-validator@npm:^2.0.3": version: 2.0.3 resolution: "web3-validator@npm:2.0.3" dependencies: @@ -51400,16 +51346,16 @@ __metadata: languageName: node linkType: hard -"web3-validator@npm:^2.0.1": - version: 2.0.1 - resolution: "web3-validator@npm:2.0.1" +"web3-validator@npm:^2.0.4": + version: 2.0.4 + resolution: "web3-validator@npm:2.0.4" dependencies: ethereum-cryptography: ^2.0.0 util: ^0.12.5 - web3-errors: ^1.1.1 - web3-types: ^1.1.1 + web3-errors: ^1.1.4 + web3-types: ^1.3.1 zod: ^3.21.4 - checksum: 4382a0d034751ca04d3f919efd4f1115abecee8541585179158662e46dd10b051c4ee29c885067d7aeff618dec971c4a2075baeb7df63249e3ed5b2d5695b782 + checksum: 9d41bfe5764343d05f045ce526715dfd1bd88dba146ba96c2d3199c3dc9bb66c01d9dac334251078542c00f82e273489700a54db365800c16e29a2c2b30f9929 languageName: node linkType: hard @@ -51512,30 +51458,6 @@ __metadata: languageName: node linkType: hard -"web3@npm:4.1.0": - version: 4.1.0 - resolution: "web3@npm:4.1.0" - dependencies: - web3-core: ^4.1.0 - web3-errors: ^1.1.0 - web3-eth: ^4.1.0 - web3-eth-abi: ^4.1.0 - web3-eth-accounts: ^4.0.4 - web3-eth-contract: ^4.0.4 - web3-eth-ens: ^4.0.4 - web3-eth-iban: ^4.0.4 - web3-eth-personal: ^4.0.4 - web3-net: ^4.0.4 - web3-providers-http: ^4.0.4 - web3-providers-ws: ^4.0.4 - web3-rpc-methods: ^1.1.0 - web3-types: ^1.1.0 - web3-utils: ^4.0.4 - web3-validator: ^2.0.0 - checksum: ed000cbffae93da22f60ad483ec7ffaf0355ec189417b425a3afc18973c5fb6469cde5e283d47361a331bfc8c179d04a544bf28a51b8bf1325a3baed5754f953 - languageName: node - linkType: hard - "web3@npm:4.1.1": version: 4.1.1 resolution: "web3@npm:4.1.1" @@ -51560,30 +51482,6 @@ __metadata: languageName: node linkType: hard -"web3@npm:4.1.2": - version: 4.1.2 - resolution: "web3@npm:4.1.2" - dependencies: - web3-core: ^4.2.0 - web3-errors: ^1.1.2 - web3-eth: ^4.2.0 - web3-eth-abi: ^4.1.2 - web3-eth-accounts: ^4.0.6 - web3-eth-contract: ^4.1.0 - web3-eth-ens: ^4.0.6 - web3-eth-iban: ^4.0.6 - web3-eth-personal: ^4.0.6 - web3-net: ^4.0.6 - web3-providers-http: ^4.0.6 - web3-providers-ws: ^4.0.6 - web3-rpc-methods: ^1.1.2 - web3-types: ^1.2.0 - web3-utils: ^4.0.6 - web3-validator: ^2.0.2 - checksum: ecc4d83df7d011a238ee6edd7455255036b8b63f3086ab960689d60b865cac157cb457a790500ac583b585bb3211096b0e01571e558f453e8437a7e3a01177da - languageName: node - linkType: hard - "web3@npm:4.2.0": version: 4.2.0 resolution: "web3@npm:4.2.0" @@ -51608,6 +51506,30 @@ __metadata: languageName: node linkType: hard +"web3@npm:4.4.0": + version: 4.4.0 + resolution: "web3@npm:4.4.0" + dependencies: + web3-core: ^4.3.2 + web3-errors: ^1.1.4 + web3-eth: ^4.4.0 + web3-eth-abi: ^4.2.0 + web3-eth-accounts: ^4.1.1 + web3-eth-contract: ^4.2.0 + web3-eth-ens: ^4.0.8 + web3-eth-iban: ^4.0.7 + web3-eth-personal: ^4.0.8 + web3-net: ^4.0.7 + web3-providers-http: ^4.1.0 + web3-providers-ws: ^4.0.7 + web3-rpc-methods: ^1.1.4 + web3-types: ^1.3.1 + web3-utils: ^4.1.1 + web3-validator: ^2.0.4 + checksum: b3e49a9ba37ec4db58b9edcd1bde6b85e08fbf6334f06a262019fb50b416c7b549658c3280f6aaa9b06f63e9129635909fec86fdd01466b16119a16e76af5c09 + languageName: node + linkType: hard + "web3@npm:^1.2.4": version: 1.10.1 resolution: "web3@npm:1.10.1"