@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
107 lines • 4.54 kB
JavaScript
import { z } from 'zod';
import { rootLogger } from '@hyperlane-xyz/utils';
import { getContractDeploymentTransaction, getLogsFromEtherscanLikeExplorerAPI, } from '../../block-explorer/etherscan.js';
import { assertIsContractAddress } from '../../contracts/contracts.js';
import { ZBytes32String, ZHash, ZUint } from '../../metadata/customZodTypes.js';
import { getContractCreationBlockFromRpc, getLogsFromRpc } from './utils.js';
export const GetLogByTopicOptionsSchema = z.object({
eventTopic: ZBytes32String,
contractAddress: ZHash,
fromBlock: ZUint.optional(),
toBlock: ZUint.optional(),
});
export const RequiredGetLogByTopicOptionsSchema = GetLogByTopicOptionsSchema.required();
export class EvmEtherscanLikeEventLogsReader {
chain;
config;
multiProvider;
constructor(chain, config, multiProvider) {
this.chain = chain;
this.config = config;
this.multiProvider = multiProvider;
}
async getContractDeploymentBlockNumber(address) {
const contractDeploymentTx = await getContractDeploymentTransaction({ apiUrl: this.config.apiUrl, apiKey: this.config.apiKey }, { contractAddress: address });
const deploymentTransactionReceipt = await this.multiProvider
.getProvider(this.chain)
.getTransactionReceipt(contractDeploymentTx.txHash);
return deploymentTransactionReceipt.blockNumber;
}
async getContractLogs(options) {
const parsedOptions = RequiredGetLogByTopicOptionsSchema.parse(options);
return getLogsFromEtherscanLikeExplorerAPI({
apiUrl: this.config.apiUrl,
apiKey: this.config.apiKey,
}, {
address: parsedOptions.contractAddress,
fromBlock: parsedOptions.fromBlock,
toBlock: parsedOptions.toBlock,
topic0: parsedOptions.eventTopic,
});
}
}
export class EvmRpcEventLogsReader {
chain;
config;
multiProvider;
constructor(chain, config, multiProvider) {
this.chain = chain;
this.config = config;
this.multiProvider = multiProvider;
}
getContractDeploymentBlockNumber(address) {
return getContractCreationBlockFromRpc(this.chain, address, this.multiProvider);
}
getContractLogs(options) {
const parsedOptions = RequiredGetLogByTopicOptionsSchema.parse(options);
return getLogsFromRpc({
chain: this.chain,
contractAddress: parsedOptions.contractAddress,
topic: parsedOptions.eventTopic,
fromBlock: parsedOptions.fromBlock,
toBlock: parsedOptions.toBlock,
multiProvider: this.multiProvider,
range: this.config.paginationBlockRange,
});
}
}
export class EvmEventLogsReader {
config;
multiProvider;
logReaderStrategy;
logger;
constructor(config, multiProvider, logReaderStrategy, logger) {
this.config = config;
this.multiProvider = multiProvider;
this.logReaderStrategy = logReaderStrategy;
this.logger = logger;
}
static fromConfig(config, multiProvider, logger = rootLogger.child({
module: EvmEventLogsReader.name,
})) {
const explorer = multiProvider.tryGetEvmExplorerMetadata(config.chain);
let logReaderStrategy;
if (explorer && !config.useRPC) {
logReaderStrategy = new EvmEtherscanLikeEventLogsReader(config.chain, explorer, multiProvider);
}
else {
logReaderStrategy = new EvmRpcEventLogsReader(config.chain, { paginationBlockRange: config.paginationBlockRange }, multiProvider);
}
return new EvmEventLogsReader(config, multiProvider, logReaderStrategy, logger);
}
async getLogsByTopic(options) {
const parsedOptions = GetLogByTopicOptionsSchema.parse(options);
const provider = this.multiProvider.getProvider(this.config.chain);
await assertIsContractAddress(this.multiProvider, this.config.chain, options.contractAddress);
const fromBlock = parsedOptions.fromBlock ??
(await this.logReaderStrategy.getContractDeploymentBlockNumber(parsedOptions.contractAddress));
const toBlock = parsedOptions.toBlock ?? (await provider.getBlockNumber());
return this.logReaderStrategy.getContractLogs({
contractAddress: parsedOptions.contractAddress,
eventTopic: parsedOptions.eventTopic,
fromBlock,
toBlock,
});
}
}
//# sourceMappingURL=EvmEventLogsReader.js.map