From 009d431914cb10338d769577ec99da5d102ca5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodolfo=20Pietro=20Calabr=C3=B2?= <33911400+rodolfopietro97@users.noreply.github.com> Date: Tue, 6 Feb 2024 10:58:20 +0100 Subject: [PATCH] eth_getLogs method (#537) * fix: convert log return type to array and fix comments on types * fix: rename helper parameter * feat: implement eth_getLogs.ts * fix: simplest approach is the best * feat: tests * fix: missing fixtures * fix: changed name * feat: edge cases * fix: typo * fix: better explanation * fix: avoid code repetitions --- .../src/thor-client/logs/logs-module.ts | 8 +- .../network/src/thor-client/logs/types.d.ts | 23 +- .../src/utils/const/rpc-mapper/rpc-methods.ts | 2 +- .../src/utils/formatter/logs/formatter.ts | 123 ++++++++++ .../src/utils/formatter/logs/index.ts | 2 + .../src/utils/formatter/logs/types.d.ts | 51 ++++ .../src/utils/helpers/transaction-helpers.ts | 6 +- .../methods-map/methods/eth_getLogs.ts | 104 +++++++- .../src/utils/rpc-mapper/rpc-mapper.ts | 5 +- .../eth_getLogs/eth_getLogs.mock.test.ts | 64 +++++ ...gs.test.ts => eth_getLogs.testnet.test.ts} | 36 +-- .../rpc-mapper/methods/eth_getLogs/fixture.ts | 231 ++++++++++++++++++ 12 files changed, 610 insertions(+), 45 deletions(-) create mode 100644 packages/provider/src/utils/formatter/logs/formatter.ts create mode 100644 packages/provider/src/utils/formatter/logs/index.ts create mode 100644 packages/provider/src/utils/formatter/logs/types.d.ts create mode 100644 packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.mock.test.ts rename packages/provider/tests/rpc-mapper/methods/eth_getLogs/{eth_getLogs.test.ts => eth_getLogs.testnet.test.ts} (53%) diff --git a/packages/network/src/thor-client/logs/logs-module.ts b/packages/network/src/thor-client/logs/logs-module.ts index b7b6605b6..f537b535e 100644 --- a/packages/network/src/thor-client/logs/logs-module.ts +++ b/packages/network/src/thor-client/logs/logs-module.ts @@ -26,7 +26,7 @@ class LogsModule { */ public async filterEventLogs( filterOptions: FilterEventLogsOptions - ): Promise { + ): Promise { return (await this.thor.httpClient.http( 'POST', thorest.logs.post.EVENT_LOGS(), @@ -35,7 +35,7 @@ class LogsModule { body: filterOptions, headers: {} } - )) as EventLogs; + )) as EventLogs[]; } /** @@ -46,7 +46,7 @@ class LogsModule { */ public async filterTransferLogs( filterOptions: FilterTransferLogsOptions - ): Promise { + ): Promise { return (await this.thor.httpClient.http( 'POST', thorest.logs.post.TRANSFER_LOGS(), @@ -55,7 +55,7 @@ class LogsModule { body: filterOptions, headers: {} } - )) as TransferLogs; + )) as TransferLogs[]; } } diff --git a/packages/network/src/thor-client/logs/types.d.ts b/packages/network/src/thor-client/logs/types.d.ts index 3971a0f32..2b2fda1d4 100644 --- a/packages/network/src/thor-client/logs/types.d.ts +++ b/packages/network/src/thor-client/logs/types.d.ts @@ -140,9 +140,20 @@ interface Metadata { * TransferCriteria interface for filtering transfer logs. */ interface TransferCriteria { - txOrigin?: string; // Transaction origin filter for transfer criteria. - sender?: string; // Sender's address filter. - recipient?: string; // Recipient's address filter. + /** + * Transaction origin filter for transfer criteria. + */ + + txOrigin?: string; + /** + * Sender's address filter. + */ + + sender?: string; + /** + * Recipient's address filter. + */ + recipient?: string; } /** @@ -190,7 +201,7 @@ interface Transfer { */ interface EventLogs extends Event { /** - * // Event logs with associated metadata + * Event logs with associated metadata */ meta: Metadata; } @@ -213,5 +224,7 @@ export type { EventLogs, FilterTransferLogsOptions, Transfer, - TransferLogs + TransferLogs, + EventCriteria, + Range }; diff --git a/packages/provider/src/utils/const/rpc-mapper/rpc-methods.ts b/packages/provider/src/utils/const/rpc-mapper/rpc-methods.ts index db31955d3..dc5c25c79 100644 --- a/packages/provider/src/utils/const/rpc-mapper/rpc-methods.ts +++ b/packages/provider/src/utils/const/rpc-mapper/rpc-methods.ts @@ -24,7 +24,7 @@ enum RPC_METHODS { eth_estimateGas = 'eth_estimateGas', // TEMPORARY COMMENT - TO IMPLEMENT eth_call = 'eth_call', // TEMPORARY COMMENT - TO IMPLEMENT eth_sendRawTransaction = 'eth_sendRawTransaction', - eth_getLogs = 'eth_getLogs', // TEMPORARY COMMENT - TO IMPLEMENT + eth_getLogs = 'eth_getLogs', eth_getBlockByHash = 'eth_getBlockByHash', eth_getBlockByNumber = 'eth_getBlockByNumber', eth_accounts = 'eth_accounts', diff --git a/packages/provider/src/utils/formatter/logs/formatter.ts b/packages/provider/src/utils/formatter/logs/formatter.ts new file mode 100644 index 000000000..01a7302c4 --- /dev/null +++ b/packages/provider/src/utils/formatter/logs/formatter.ts @@ -0,0 +1,123 @@ +import { + type EventCriteria, + type EventLogs +} from '@vechain/vechain-sdk-network'; +import { type LogsRPC } from './types'; +import { vechain_sdk_core_ethers } from '@vechain/vechain-sdk-core'; + +/** + * Output formatter for Event logs. + * It converts the Event logs into the RPC standard. + * + * @param eventLogs - The Event logs to be formatted. + */ +const formatToLogsRPC = (eventLogs: EventLogs[]): LogsRPC[] => { + // Final RPC event logs formatted + return eventLogs.map((eventLog: EventLogs) => { + return { + transactionHash: eventLog.meta.txID, + blockHash: eventLog.meta.blockID, + blockNumber: vechain_sdk_core_ethers.toQuantity( + eventLog.meta.blockNumber + ), + address: eventLog.address, + data: eventLog.data, + topics: eventLog.topics, + + // Always false for now + removed: false, + + // @NOTE: These two fields are not implemented yet. This for performance reasons. + // + /** + * @NOTE: These two fields are not implemented yet. + * This for performance reasons. + * We can implement them later if needed. + * + * To have these two fields, we need to query a block for each entry into the logs. + * After from the block, we can get the transaction index and the log index. + * This is a performance issue because we have to query a block for each entry into the logs. + */ + logIndex: '0x0', + transactionIndex: '0x0' + } satisfies LogsRPC; + }); +}; + +/** + * Convert the criteria topics into an array of topics. + * + * This because the criteria topics are not an array of topics in vechain, + * but they are directly enumerated (topic0, topic1, topic2, topic3, topic4). + * + * RPC standard requires an array of topics instead. + * + * @param criteriaTopicsArray - The criteria topics array. + * @param address - The address to filter. + */ +const _scatterArrayTopic = ( + criteriaTopicsArray: string[], + address?: string +): EventCriteria => { + return { + address, + topic0: criteriaTopicsArray[0] ?? undefined, + topic1: criteriaTopicsArray[1] ?? undefined, + topic2: criteriaTopicsArray[2] ?? undefined, + topic3: criteriaTopicsArray[3] ?? undefined, + topic4: criteriaTopicsArray[4] ?? undefined + }; +}; + +/** + * Get the criteria set for the input. + * + * Basically with vechain swagger we have: + * + * { + * address = string | undefined; + * topic1: string | undefined; + * ... + * topic4: string | undefined; + * } + * + * With RPC we can have an array of address: + * + * { + * **address = string | string[] | undefined;** + * topic1: string | undefined; + * ... + * topic4: string | undefined; + * }. + * + * To have a complete research space, we can filter by address and topics, and only by address. + * + * @param criteria - The criteria input. + */ +const getCriteriaSetForInput = (criteria: { + address?: string | string[]; + topics?: string[]; +}): EventCriteria[] => { + // String to an array of addresses and topics + let criteriaAddress: string[] = []; + let criteriaTopics: string[] = []; + + // Convert in any case to an array of addresses + if (criteria.address !== undefined) + criteriaAddress = + typeof criteria.address === 'string' + ? [criteria.address] + : criteria.address; + + // Convert in any case to an array of topics + if (criteria.topics !== undefined) criteriaTopics = criteria.topics; + + // Filtering considering the address and topics. For each address, we have to consider the topics + return criteriaAddress.length > 0 + ? criteriaAddress.map((addr: string) => { + return _scatterArrayTopic(criteriaTopics, addr); + }) + : [_scatterArrayTopic(criteriaTopics)]; +}; + +export { formatToLogsRPC, getCriteriaSetForInput }; diff --git a/packages/provider/src/utils/formatter/logs/index.ts b/packages/provider/src/utils/formatter/logs/index.ts new file mode 100644 index 000000000..a79c81b38 --- /dev/null +++ b/packages/provider/src/utils/formatter/logs/index.ts @@ -0,0 +1,2 @@ +export * from './formatter'; +export * from './types.d'; diff --git a/packages/provider/src/utils/formatter/logs/types.d.ts b/packages/provider/src/utils/formatter/logs/types.d.ts new file mode 100644 index 000000000..099f0658b --- /dev/null +++ b/packages/provider/src/utils/formatter/logs/types.d.ts @@ -0,0 +1,51 @@ +/** + * Return type of logs according to the Ethereum RPC standard. + */ +interface LogsRPC { + /** + * (boolean) true when the log was removed, due to a chain reorganization. false if it's a valid log. + */ + removed: boolean; + + /** + * Hexadecimal of the log index position in the block. Null when it is a pending log. + */ + logIndex: string; + + /** + * Hexadecimal of the transaction index position from which the log created. Null when it is a pending log. + */ + transactionIndex: string; + + /** + * 32 bytes. Hash of the transactions from which this log was created. Null when it is a pending log. + */ + transactionHash: string; + + /** + * 32 bytes. Hash of the block where this log was in. Null when it is a pending log. + */ + blockHash: string; + + /** + * Block number where this log was in. Null when it is a pending log. + */ + blockNumber: string; + + /** + * 20 bytes. Address from which this log originated. + */ + address: string; + + /** + * Contains one or more 32-bytes non-indexed arguments of the log. + */ + data: string; + + /** + * An array of 0 to 4 indexed log arguments, each 32 bytes. In solidity the first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except when you declared the event with the anonymous specifier. + */ + topics: string[]; +} + +export { type LogsRPC }; diff --git a/packages/provider/src/utils/helpers/transaction-helpers.ts b/packages/provider/src/utils/helpers/transaction-helpers.ts index de43e0da0..5272adb92 100644 --- a/packages/provider/src/utils/helpers/transaction-helpers.ts +++ b/packages/provider/src/utils/helpers/transaction-helpers.ts @@ -46,18 +46,18 @@ const getTransactionIndexIntoBlock = ( * Get the number of logs ahead of a transaction into a block. * * @param blockExpanded - The block to search in. - * @param hash - The hash of the transaction to search for. + * @param transactionId - The hash of the transaction to search for. * @param chainId - The chain ID of the network. */ const getNumberOfLogsAheadOfTransactionIntoBlockExpanded = ( blockExpanded: BlockDetail, - hash: string, + transactionId: string, chainId: string ): number => { // Get transaction index into the block const transactionIndex = getTransactionIndexIntoBlock( blocksFormatter.formatToRPCStandard(blockExpanded, chainId), - hash + transactionId ); // Count the number of logs in the txs whose number is lower than txId diff --git a/packages/provider/src/utils/rpc-mapper/methods-map/methods/eth_getLogs.ts b/packages/provider/src/utils/rpc-mapper/methods-map/methods/eth_getLogs.ts index 60fc0b926..ea4d0d81f 100644 --- a/packages/provider/src/utils/rpc-mapper/methods-map/methods/eth_getLogs.ts +++ b/packages/provider/src/utils/rpc-mapper/methods-map/methods/eth_getLogs.ts @@ -1,5 +1,20 @@ -import { type ThorClient } from '@vechain/vechain-sdk-network'; -import { buildError, FUNCTION } from '@vechain/vechain-sdk-errors'; +import { + type BlockDetail, + type EventCriteria, + type EventLogs, + type ThorClient +} from '@vechain/vechain-sdk-network'; +import { + assert, + buildProviderError, + DATA, + JSONRPC +} from '@vechain/vechain-sdk-errors'; +import { + formatToLogsRPC, + getCriteriaSetForInput, + type LogsRPC +} from '../../../formatter/logs'; /** * RPC Method eth_getLogs implementation @@ -14,19 +29,82 @@ import { buildError, FUNCTION } from '@vechain/vechain-sdk-errors'; const ethGetLogs = async ( thorClient: ThorClient, params: unknown[] -): Promise => { - // To avoid eslint error - await Promise.resolve(0); - - // Not implemented yet - throw buildError( - FUNCTION.NOT_IMPLEMENTED, - 'Method "eth_getLogs" not not implemented yet', +): Promise => { + // Check different params from eth_getBlockByNumber. Otherwise, the logic is the same. Only difference is the block number is replaced by block hash. + assert( + params.length === 1 && typeof params[0] === 'object', + DATA.INVALID_DATA_TYPE, + `Invalid params length, expected 1 object with following properties: \n {` + + `\taddress: [optional] Contract address (20 bytes) or a list of addresses from which logs should originate.` + + `\tfromBlock: [optional, default is "latest"] A hexadecimal block number, or the string latest, earliest or pending. See the default block parameter.` + + `\ttoBlock: [optional, default is "latest"] A hexadecimal block number, or the string latest, earliest or pending. See the default block parameter.` + + `\ttopics: [optional] Array of 32 bytes DATA topics. Topics are order-dependent.` + + `\tblockhash: [optional] Restricts the logs returned to the single block referenced in the 32-byte hash blockHash. Using blockHash is equivalent to setting fromBlock and toBlock to the block number referenced in the blockHash. If blockHash is present in in the filter criteria, then neither fromBlock nor toBlock are allowed.` + + `}` + ); + + // Block max limit + const MAX_LIMIT = 256; + + // Input params + const [filterOptions] = params as [ { - params, - thorClient + address?: string | string[]; + fromBlock?: string; + toBlock?: string; + topics?: string[]; + blockhash?: string; } - ); + ]; + + try { + // Get the latest block (if fromBlock or toBlock is not defined, we will use the latest block) + const latestBlock = + (await thorClient.blocks.getBestBlock()) as BlockDetail; + + // Get criteria set from input + const criteriaSet: EventCriteria[] = getCriteriaSetForInput({ + address: filterOptions.address, + topics: filterOptions.topics + }); + + // Call thor client to get logs + const logs: EventLogs[] = await thorClient.logs.filterEventLogs({ + range: { + unit: 'block', + from: + filterOptions.fromBlock !== undefined + ? parseInt(filterOptions.fromBlock, 16) + : latestBlock.number, + to: + filterOptions.toBlock !== undefined + ? parseInt(filterOptions.toBlock, 16) + : latestBlock.number + }, + criteriaSet, + order: 'asc', + options: { + offset: 0, + limit: MAX_LIMIT + } + }); + + // Format logs to RPC + return formatToLogsRPC(logs); + } catch (e) { + throw buildProviderError( + JSONRPC.INTERNAL_ERROR, + `Method 'ethGetLogs' failed: Error while getting logs ${ + params[0] as string + }\n + Params: ${JSON.stringify(params)}\n + URL: ${thorClient.httpClient.baseURL}`, + { + params, + innerError: JSON.stringify(e) + } + ); + } }; export { ethGetLogs }; diff --git a/packages/provider/src/utils/rpc-mapper/rpc-mapper.ts b/packages/provider/src/utils/rpc-mapper/rpc-mapper.ts index ef0773442..446086b79 100644 --- a/packages/provider/src/utils/rpc-mapper/rpc-mapper.ts +++ b/packages/provider/src/utils/rpc-mapper/rpc-mapper.ts @@ -85,6 +85,7 @@ import { } from '../formatter'; import { type Wallet } from '@vechain/vechain-sdk-wallet'; import { ethRequestAccounts } from './methods-map/methods/eth_requestAccounts'; +import { type LogsRPC } from '../formatter/logs'; /** * Map of RPC methods to their implementations with our SDK. @@ -139,8 +140,8 @@ const RPCMethodsMap = ( return await ethSendRawTransaction(thorClient, params); }, - [RPC_METHODS.eth_getLogs]: async (params) => { - await ethGetLogs(thorClient, params); + [RPC_METHODS.eth_getLogs]: async (params): Promise => { + return await ethGetLogs(thorClient, params); }, [RPC_METHODS.eth_getBlockByHash]: async ( diff --git a/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.mock.test.ts b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.mock.test.ts new file mode 100644 index 000000000..95e5eaab1 --- /dev/null +++ b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.mock.test.ts @@ -0,0 +1,64 @@ +import { + afterEach, + beforeEach, + describe, + expect, + jest, + test +} from '@jest/globals'; +import { RPC_METHODS, RPCMethodsMap } from '../../../../src'; +import { ThorClient } from '@vechain/vechain-sdk-network'; +import { testNetwork } from '../../../fixture'; +import { type LogsRPC } from '../../../../src/utils/formatter/logs'; +import { ProviderRpcError } from '@vechain/vechain-sdk-errors'; +import { logsFixture } from './fixture'; + +/** + * RPC Mapper integration tests for 'eth_getLogs' method + * + * @group integration/rpc-mapper/methods/eth_getLogs + */ +describe('RPC Mapper - eth_getLogs method tests', () => { + /** + * Thor client instance + */ + let thorClient: ThorClient; + + /** + * Init thor client before each test + */ + beforeEach(() => { + // Init thor client + thorClient = new ThorClient(testNetwork); + }); + + /** + * Destroy thor client after each test + */ + afterEach(() => { + thorClient.destroy(); + }); + + /** + * eth_getLogs RPC call tests - Negative cases + */ + describe('eth_getLogs - Negative cases', () => { + /** + * Negative case 2 - Should throw an error for invalid input if request is invalid + */ + test('eth_getLogs - Should throw error if request is invalid', async () => { + // Mock the getGenesisBlock method to return null + jest.spyOn(thorClient.logs, 'filterEventLogs').mockRejectedValue( + new Error() + ); + + await expect( + async () => + // Call RPC method + (await RPCMethodsMap(thorClient)[RPC_METHODS.eth_getLogs]([ + logsFixture[0].input + ])) as LogsRPC[] + ).rejects.toThrowError(ProviderRpcError); + }); + }); +}); diff --git a/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.test.ts b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.testnet.test.ts similarity index 53% rename from packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.test.ts rename to packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.testnet.test.ts index 0b7e1a440..741b882c8 100644 --- a/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.test.ts +++ b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/eth_getLogs.testnet.test.ts @@ -1,8 +1,10 @@ import { afterEach, beforeEach, describe, expect, test } from '@jest/globals'; -import { NotImplementedError } from '@vechain/vechain-sdk-errors'; import { RPC_METHODS, RPCMethodsMap } from '../../../../src'; import { ThorClient } from '@vechain/vechain-sdk-network'; import { testNetwork } from '../../../fixture'; +import { logsFixture } from './fixture'; +import { type LogsRPC } from '../../../../src/utils/formatter/logs'; +import { InvalidDataTypeError } from '@vechain/vechain-sdk-errors'; /** * RPC Mapper integration tests for 'eth_getLogs' method @@ -35,16 +37,16 @@ describe('RPC Mapper - eth_getLogs method tests', () => { */ describe('eth_getLogs - Positive cases', () => { /** - * Positive case 1 - ... Description ... + * Positive cases. Should be able to get logs */ - test('eth_getLogs - positive case 1', async () => { - // NOT IMPLEMENTED YET! - await expect( - async () => - await RPCMethodsMap(thorClient)[RPC_METHODS.eth_getLogs]([ - -1 - ]) - ).rejects.toThrowError(NotImplementedError); + logsFixture.forEach((fixture, index) => { + test(`eth_getLogs - Should be able to get logs - ${index}`, async () => { + // Call RPC method + const logs = (await RPCMethodsMap(thorClient)[ + RPC_METHODS.eth_getLogs + ]([fixture.input])) as LogsRPC[]; + expect(logs.slice(0, 4)).toStrictEqual(fixture.expectedSliced); + }); }); }); @@ -53,16 +55,16 @@ describe('RPC Mapper - eth_getLogs method tests', () => { */ describe('eth_getLogs - Negative cases', () => { /** - * Negative case 1 - ... Description ... + * Negative case 1 - Should throw an error for invalid input */ - test('eth_getLogs - negative case 1', async () => { - // NOT IMPLEMENTED YET! + test('eth_getLogs - Invalid input', async () => { await expect( async () => - await RPCMethodsMap(thorClient)[RPC_METHODS.eth_getLogs]([ - 'SOME_RANDOM_PARAM' - ]) - ).rejects.toThrowError(NotImplementedError); + // Call RPC method + (await RPCMethodsMap(thorClient)[RPC_METHODS.eth_getLogs]([ + 'INVALID_INPUT' + ])) as LogsRPC[] + ).rejects.toThrowError(InvalidDataTypeError); }); }); }); diff --git a/packages/provider/tests/rpc-mapper/methods/eth_getLogs/fixture.ts b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/fixture.ts index e69de29bb..3df606bed 100644 --- a/packages/provider/tests/rpc-mapper/methods/eth_getLogs/fixture.ts +++ b/packages/provider/tests/rpc-mapper/methods/eth_getLogs/fixture.ts @@ -0,0 +1,231 @@ +import { vechain_sdk_core_ethers } from '@vechain/vechain-sdk-core'; + +/** + * Fixtures for eth_getLogs positive cases + */ +const logsFixture = [ + // Well defined input + { + input: { + address: [ + '0x0000000000000000000000000000456e65726779', + '0x0000000000000000000000000000456e65726779' + ], + fromBlock: vechain_sdk_core_ethers.toQuantity(0), + toBlock: vechain_sdk_core_ethers.toQuantity(100000), + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ] + }, + expectedSliced: [ + { + transactionHash: + '0x0ee8df3a9de6787ec0848ea8951ed8899bb053b6b4af167228dd7c0c012f5346', + blockHash: + '0x000060716a6decc7127d221e8a53cd7b33992db6236490f79d47585f9ae7ca14', + blockNumber: '0x6071', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e55fff280', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0x86b3364c0faf2df6365b975cf1bd8046264b1eeaa2f266fe15b2df27d7954f65', + blockHash: + '0x00006135c993e6cd1ed99aac34679caac80759764ecb01431c9bea0199f3bf4c', + blockNumber: '0x6135', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0x9fada14187c54ca93741c7b20483f52dc83b3f5a934082ea1d7a7d75216c1b80', + blockHash: + '0x00006a2e2b18a4e7697c54045d2d615fe1a2eaad9a698e803c15b847ad4a7f95', + blockNumber: '0x6a2e', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0xed2c6e452326f2ea126632830ebb8abca5bbfbed9da0780bf65efbbf555c8452', + blockHash: + '0x00006a423cfbab794f79328cbd0f29f08f0ed1466c076153445d10c3e0ac21b2', + blockNumber: '0x6a42', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + } + ] + }, + // To block not defined (latest block as default) + { + input: { + address: [ + '0x0000000000000000000000000000456e65726779', + '0x0000000000000000000000000000456e65726779' + ], + fromBlock: vechain_sdk_core_ethers.toQuantity(0), + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ] + }, + expectedSliced: [ + { + transactionHash: + '0x0ee8df3a9de6787ec0848ea8951ed8899bb053b6b4af167228dd7c0c012f5346', + blockHash: + '0x000060716a6decc7127d221e8a53cd7b33992db6236490f79d47585f9ae7ca14', + blockNumber: '0x6071', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e55fff280', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0x86b3364c0faf2df6365b975cf1bd8046264b1eeaa2f266fe15b2df27d7954f65', + blockHash: + '0x00006135c993e6cd1ed99aac34679caac80759764ecb01431c9bea0199f3bf4c', + blockNumber: '0x6135', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0x9fada14187c54ca93741c7b20483f52dc83b3f5a934082ea1d7a7d75216c1b80', + blockHash: + '0x00006a2e2b18a4e7697c54045d2d615fe1a2eaad9a698e803c15b847ad4a7f95', + blockNumber: '0x6a2e', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + }, + { + transactionHash: + '0xed2c6e452326f2ea126632830ebb8abca5bbfbed9da0780bf65efbbf555c8452', + blockHash: + '0x00006a423cfbab794f79328cbd0f29f08f0ed1466c076153445d10c3e0ac21b2', + blockNumber: '0x6a42', + address: '0x0000000000000000000000000000456e65726779', + data: '0x00000000000000000000000000000000000000000000124bc0ddd92e56000000', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ], + removed: false, + logIndex: '0x0', + transactionIndex: '0x0' + } + ] + }, + + // From block and to not defined (latest block as default) + { + input: { + address: [ + '0x0000000000000000000000000000456e65726779', + '0x0000000000000000000000000000456e65726779' + ], + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e', + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ] + }, + expectedSliced: [] + }, + + // No topics defined, only addresses + { + input: { + address: [ + '0x0000000000000000000000000000456e65726779', + '0x0000000000000000000000000000456e65726779' + ] + }, + expectedSliced: [] + }, + + // No addresses defined, only topics + { + input: { + topics: [ + '0x0000000000000000000000005034aa590125b64023a0262112b98d72e3c8e40e' + ] + }, + expectedSliced: [] + }, + + // No addresses and topics defined + { + input: {}, + expectedSliced: [] + }, + + // A single address + { + input: { + address: '0x0000000000000000000000000000456e65726779' + }, + expectedSliced: [] + } +]; + +export { logsFixture };