From c6952eb9ed208697aa839621a5f76b63826c2dab Mon Sep 17 00:00:00 2001 From: Scott Twiname Date: Tue, 7 Nov 2023 14:18:58 +1300 Subject: [PATCH] Fix receipts missing on transactions (#200) --- packages/node/CHANGELOG.md | 2 ++ .../node/src/ethereum/api.ethereum.test.ts | 10 +++++++++ packages/node/src/ethereum/api.ethereum.ts | 14 ++++-------- packages/node/src/ethereum/utils.ethereum.ts | 22 +++++++++++-------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/node/CHANGELOG.md b/packages/node/CHANGELOG.md index bb8929ee2f..ee6780a530 100644 --- a/packages/node/CHANGELOG.md +++ b/packages/node/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Getting transaction receipts when accessing via a log handler ## [3.1.2] - 2023-11-01 ### Fixed diff --git a/packages/node/src/ethereum/api.ethereum.test.ts b/packages/node/src/ethereum/api.ethereum.test.ts index 1326ab2005..a992c731d7 100644 --- a/packages/node/src/ethereum/api.ethereum.test.ts +++ b/packages/node/src/ethereum/api.ethereum.test.ts @@ -70,6 +70,14 @@ describe('Api.ethereum', () => { ); }); + it('should have the ability to get receipts via transactions from all types', () => { + expect(typeof blockData.transactions[0].receipt).toEqual('function'); + expect(typeof blockData.logs[0].transaction.receipt).toEqual('function'); + expect( + typeof blockData.transactions[81].logs[0].transaction.receipt, + ).toEqual('function'); + }); + it('Decode nested logs in transactions', async () => { // Erc721 const tx = blockData.transactions.find( @@ -92,6 +100,7 @@ describe('Api.ethereum', () => { expect(parsedLog).not.toHaveProperty('args'); expect(parsedLog).toBeTruthy(); }); + it('Null filter support', async () => { const beamEndpoint = 'https://rpc.api.moonbeam.network'; ethApi = new EthereumApi(beamEndpoint, BLOCK_CONFIRMATIONS, eventEmitter); @@ -211,6 +220,7 @@ describe('Api.ethereum', () => { }); expect(result.length).toBe(0); }); + it('If transaction is undefined, with null filter, should be supported', async () => { const beamEndpoint = 'https://rpc.api.moonbeam.network'; ethApi = new EthereumApi(beamEndpoint, BLOCK_CONFIRMATIONS, eventEmitter); diff --git a/packages/node/src/ethereum/api.ethereum.ts b/packages/node/src/ethereum/api.ethereum.ts index 355d76e61e..bc3a09bc7c 100644 --- a/packages/node/src/ethereum/api.ethereum.ts +++ b/packages/node/src/ethereum/api.ethereum.ts @@ -282,24 +282,18 @@ export class EthereumApi implements ApiWrapper { const block = await this.getBlockPromise(blockNumber, true); const logsRaw = await this.client.getLogs({ blockHash: block.hash }); - const logs = logsRaw.map((l) => formatLog(l, block)); - const transactions = block.transactions.map((tx) => ({ + block.logs = logsRaw.map((l) => formatLog(l, block)); + block.transactions = block.transactions.map((tx) => ({ ...formatTransaction(tx, block), receipt: () => this.getTransactionReceipt(tx.hash).then((r) => formatReceipt(r, block), ), - logs: logs.filter((l) => l.transactionHash === tx.hash), + logs: block.logs.filter((l) => l.transactionHash === tx.hash), })); - const ret = { - ...block, - transactions, - logs, - }; - this.eventEmitter.emit('fetchBlock'); - return ret; + return block; } catch (e) { throw this.handleError(e); } diff --git a/packages/node/src/ethereum/utils.ethereum.ts b/packages/node/src/ethereum/utils.ethereum.ts index 05792ee32d..2e9d38f1ad 100644 --- a/packages/node/src/ethereum/utils.ethereum.ts +++ b/packages/node/src/ethereum/utils.ethereum.ts @@ -65,25 +65,29 @@ export function formatLog( >, block: EthereumBlock, ): EthereumLog | EthereumLog { - return { + const formattedLog = { ...log, address: handleAddress(log.address), blockNumber: handleNumber(log.blockNumber).toNumber(), transactionIndex: handleNumber(log.transactionIndex).toNumber(), logIndex: handleNumber(log.logIndex).toNumber(), block, - get transaction() { + toJSON(): string { + return JSON.stringify(omit(this, ['transaction', 'block', 'toJSON'])); + }, + }; + + // Define this afterwards as the spread on `...log` breaks defining a getter + Object.defineProperty(formattedLog, 'transaction', { + get: () => { const rawTransaction = block.transactions?.find( (tx) => tx.hash === log.transactionHash, ); - return rawTransaction - ? formatTransaction(rawTransaction, block) - : undefined; - }, - toJSON(): string { - return JSON.stringify(omit(this, ['transaction', 'block', 'toJSON'])); + + return rawTransaction; }, - } as EthereumLog; + }); + return formattedLog as unknown as EthereumLog; } export function formatTransaction(