diff --git a/yarn-project/aztec-sandbox/docker-compose.yml b/yarn-project/aztec-sandbox/docker-compose.yml index 608c7db3d034..5e66423bb295 100644 --- a/yarn-project/aztec-sandbox/docker-compose.yml +++ b/yarn-project/aztec-sandbox/docker-compose.yml @@ -29,9 +29,9 @@ services: image: otterscan/otterscan:develop # platform: linux/amd64 ports: - - "5100:80" + - '5100:80' container_name: otterscan environment: - # otterscan env var is hardcoded to support erigon client - # but it also works for anvil - - ERIGON_URL=http://127.0.0.1:${SANDBOX_ANVIL_PORT:-8545} \ No newline at end of file + # otterscan env var is hardcoded to support erigon client + # but it also works for anvil + - ERIGON_URL=http://127.0.0.1:${SANDBOX_ANVIL_PORT:-8545} diff --git a/yarn-project/cli/src/index.ts b/yarn-project/cli/src/index.ts index 8e8cd994a9e2..381fd2b2b73b 100644 --- a/yarn-project/cli/src/index.ts +++ b/yarn-project/cli/src/index.ts @@ -11,6 +11,7 @@ import { import { StructType, decodeFunctionSignatureWithParameterNames } from '@aztec/foundation/abi'; import { JsonStringify } from '@aztec/foundation/json-rpc'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; +import { RunningPromise } from '@aztec/foundation/running-promise'; import { fileURLToPath } from '@aztec/foundation/url'; import { compileContract, generateNoirInterface, generateTypescriptInterface } from '@aztec/noir-compiler/cli'; import { CompleteAddress, ContractData, LogFilter } from '@aztec/types'; @@ -292,21 +293,39 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { .option('-c, --contractAddress ', 'Contract address to filter logs by.', parseOptionalAztecAddress) .option('-s, --selector ', 'Event selector to filter logs by.', parseOptionalSelector) .addOption(pxeOption) - .action(async ({ txHash, fromBlock, toBlock, contractAddress, selector, rpcUrl }) => { + .option('--follow', 'If set, will keep polling for new logs until interrupted.') + .action(async ({ txHash, fromBlock, toBlock, contractAddress, selector, rpcUrl, follow }) => { const client = await createCompatibleClient(rpcUrl, debugLogger); + if (follow) { + if (txHash) throw Error('Cannot use --follow with --txHash'); + if (toBlock) throw Error('Cannot use --follow with --toBlock'); + } + const filter: LogFilter = { txHash, fromBlock, toBlock, contractAddress, selector }; - const logs = await client.getUnencryptedLogs(filter); - - if (!logs.length) { - const filterOptions = Object.entries(filter) - .filter(([, value]) => value !== undefined) - .map(([key, value]) => `${key}: ${value}`) - .join(', '); - log(`No logs found for filter: {${filterOptions}}`); + + const fetchLogs = async () => { + const logs = await client.getUnencryptedLogs(filter); + + if (!logs.length) { + const filterOptions = Object.entries(filter) + .filter(([, value]) => value !== undefined) + .map(([key, value]) => `${key}: ${value}`) + .join(', '); + if (!follow) log(`No logs found for filter: {${filterOptions}}`); + } else { + if (!follow) log('Logs found: \n'); + logs.forEach(unencryptedLog => log(unencryptedLog.toHumanReadable())); + // Set `fromBlock` to the block number of the next block after the block of last log we fetched. + filter.fromBlock = logs[logs.length - 1].blockNumber + 1; + } + }; + + if (follow) { + log('Fetching logs...'); + new RunningPromise(fetchLogs, 1000).start(); } else { - log('Logs found: \n'); - logs.forEach(unencryptedLog => log(unencryptedLog.toHumanReadable())); + await fetchLogs(); } });