diff --git a/src/blockscoutApi/index.ts b/src/blockscoutApi/index.ts index ee98570..68ba062 100644 --- a/src/blockscoutApi/index.ts +++ b/src/blockscoutApi/index.ts @@ -11,6 +11,7 @@ import { fromApiToInternalTransaction, fromApiToNft, fromApiToNftOwner, fromApiToRtbcBalance, fromApiToTEvents, fromApiToTokenWithBalance, fromApiToTokens, fromApiToTransaction } from './utils' +import { GetEventLogsByAddressAndTopic0 } from '../service/address/AddressService' export class BlockscoutAPI extends DataSource { private chainId: number @@ -118,4 +119,30 @@ export class BlockscoutAPI extends DataSource { } return fromApiToNftOwner(address, [...(response?.items || []), ...items]) } + + async getEventLogsByAddressAndTopic0 ({ + address, topic0, toBlock = 'latest', fromBlock + }: Omit) { + let fromBlockToUse = fromBlock + if (!fromBlock) { + const tx = await this.getTransactionsByAddress(address) + // @ts-ignore ignored because it's using never as type + const lastTx = tx.data.pop() // The last tx is the first transaction + + if (lastTx) fromBlockToUse = lastTx.blockNumber + } + + if (!fromBlockToUse) return [] + const params = { + module: 'logs', + action: 'getLogs', + address: address.toLowerCase(), + toBlock, + fromBlock: fromBlockToUse, + topic0 + } + return this.axios?.get>(`${this.url}`, { params }) + .then(({ data }) => data.result) + .catch(() => []) + } } diff --git a/src/blockscoutApi/utils.ts b/src/blockscoutApi/utils.ts index f26a813..6ffe718 100644 --- a/src/blockscoutApi/utils.ts +++ b/src/blockscoutApi/utils.ts @@ -147,7 +147,7 @@ export const fromApiToTransaction = (transaction: TransactionServerResponse): IT blockNumber: transaction.block, transactionIndex: 0, from: transaction.from.hash, - to: transaction.to.hash, + to: transaction.to?.hash, gas: Number(transaction.gas_used), gasPrice: transaction.gas_price, value: transaction.value, @@ -167,7 +167,7 @@ export const fromApiToTransaction = (transaction: TransactionServerResponse): IT contractAddress: null, logs: [], from: transaction.from.hash, - to: transaction.to.hash, + to: transaction.to?.hash, status: transaction.status === 'ok' ? '0x1' : '0x0', logsBloom: '', type: String(transaction.type) diff --git a/src/controller/httpsAPI.ts b/src/controller/httpsAPI.ts index 94d3d26..2d7ef6c 100644 --- a/src/controller/httpsAPI.ts +++ b/src/controller/httpsAPI.ts @@ -173,6 +173,27 @@ export class HttpsAPI { } }) + this.app.get('/address/:address/eventsByTopic0', + async ({ params: { address }, query: { chainId = '31', topic0, fromBlock, toBlock } } : Request, res: Response, + nextFunction: NextFunction) => { + try { + chainIdSchema.validateSync({ chainId }) + addressSchema.validateSync({ address }) + const result = await this.addressService + .getEventLogsByAddressAndTopic0({ + chainId: chainId as string, + address: address as string, + topic0: topic0 as string, + fromBlock: fromBlock as string, + toBlock: toBlock as string + }) + .catch(nextFunction) + return this.responseJsonOk(res)(result) + } catch (e) { + this.handleValidationError(e, res) + } + }) + this.app.get( '/price', async (req: Request<{}, {}, {}, PricesQueryParams>, res: Response) => { diff --git a/src/repository/DataSource.ts b/src/repository/DataSource.ts index ac5e8ea..650f635 100644 --- a/src/repository/DataSource.ts +++ b/src/repository/DataSource.ts @@ -1,6 +1,7 @@ import _axios from 'axios' import { ethers } from 'ethers' import BitcoinCore from '../service/bitcoin/BitcoinCore' +import { GetEventLogsByAddressAndTopic0 } from '../service/address/AddressService' export abstract class DataSource { readonly url: string @@ -27,6 +28,8 @@ export abstract class DataSource { abstract getNft(address: string); abstract getNftOwnedByAddress(address: string, nft: string); + abstract getEventLogsByAddressAndTopic0({ address, topic0, toBlock, fromBlock } : + Omit); } export type RSKDatasource = { diff --git a/src/rskExplorerApi/index.ts b/src/rskExplorerApi/index.ts index eaf19b9..b42b32a 100644 --- a/src/rskExplorerApi/index.ts +++ b/src/rskExplorerApi/index.ts @@ -139,4 +139,8 @@ export class RSKExplorerAPI extends DataSource { getNftOwnedByAddress () { throw new Error('Feature not supported') } + + getEventLogsByAddressAndTopic0 () { + throw new Error('Feature not supported') + } } diff --git a/src/service/address/AddressService.ts b/src/service/address/AddressService.ts index 71f50e4..e278cff 100644 --- a/src/service/address/AddressService.ts +++ b/src/service/address/AddressService.ts @@ -33,6 +33,14 @@ interface GetNftsByAddress extends GetTokensByAddress { nftAddress: string } +export interface GetEventLogsByAddressAndTopic0 { + address: string + topic0: string + toBlock: string + chainId: string + fromBlock?: string +} + type GetBalancesTransactionsPricesByAddress = { chainId: string address: string @@ -139,4 +147,9 @@ export class AddressService { const dataSource = this.dataSourceMapping[chainId] return dataSource.getNftOwnedByAddress(address, nftAddress) } + + async getEventLogsByAddressAndTopic0 ({ chainId, ...rest }: GetEventLogsByAddressAndTopic0) { + const dataSource = this.dataSourceMapping[chainId] + return dataSource.getEventLogsByAddressAndTopic0(rest) + } }