-
Notifications
You must be signed in to change notification settings - Fork 590
Description
Problem Statement
Problem
The current getDecodedPublicEvents only accepts (node, eventMetadata, fromBlock, limit), forcing callers to filter by block range alone. The underlying node.getPublicLogs already supports richer filtering via LogFilter (txHash, contractAddress, fromBlock, toBlock, afterLog), but none of those fields are passed through.
This means common patterns like "get Transfer events from this tx on this contract" require callers to drop down to raw log parsing, defeating the purpose of the helper.
On the private side, wallet.getPrivateEvents already accepts a rich filter with contractAddress, txHash, fromBlock, toBlock. This proposal brings public events to parity.
Proposed Solution
Proposed Signature
Overloaded to preserve backward compatibility with existing callers:
// New: accepts the full LogFilter
function getDecodedPublicEvents<T>(
node: AztecNode,
eventMetadata: EventMetadataDefinition,
filter: LogFilter,
): Promise<T[]>
// Legacy (unchanged): convenience wrapper that builds { fromBlock, toBlock }
function getDecodedPublicEvents<T>(
node: AztecNode,
eventMetadata: EventMetadataDefinition,
from: number,
limit: number,
): Promise<T[]>No new types -- LogFilter from @aztec/stdlib is reused directly, since the fields and semantics are identical.
Behaviour
- Pass the
LogFiltertonode.getPublicLogs(filter)as-is. - For each returned log, match the event selector (last emitted field) against
eventMetadata.eventSelector. Skip non-matching logs silently. - For matching logs, assert
log.fields.length === eventMetadata.fieldNames.length + 1. Throw on mismatch -- a matching selector with wrong payload length indicates ABI drift, not a benign skip. - Decode via
decodeFromAbi([eventMetadata.abiType], log.fields). - Return the decoded array typed as
T[].
Pagination
The function returns one page of results. When node.getPublicLogs signals maxLogsHit, the caller is responsible for paginating using afterLog set to the last returned log's LogId. This keeps the function simple and predictable -- callers that need exhaustive iteration can wrap it in a loop.
Example Use Case
Usage Examples
By transaction + contract (most common in tests):
const events = await getDecodedPublicEvents<Transfer>(
node,
TokenContract.events.Transfer,
{ txHash: receipt.txHash, contractAddress: token.address },
);By block range (indexer-style):
const events = await getDecodedPublicEvents<Transfer>(
node,
TokenContract.events.Transfer,
{ fromBlock: 100, toBlock: 110 },
);Legacy call sites (no changes needed):
const events = await getDecodedPublicEvents<Transfer>(
node,
TokenContract.events.Transfer,
receipt.blockNumber!,
1,
);Alternative Solutions
No response
Additional Context
Current vs Proposed
| Capability | Current | Proposed |
|---|---|---|
| Filter by block range | yes | yes |
| Filter by txHash | no | yes |
| Filter by contractAddress | no | yes |
Pagination (afterLog) |
no | yes |
| Silent skip on selector mismatch | yes | yes |
| Throw on field length mismatch | yes | yes |
| Backward compatible | n/a | yes (overload) |
Scope
This spec covers the standalone getDecodedPublicEvents function only. A follow-up could add wallet.getPublicEvents(metadata, filter) for symmetry with wallet.getPrivateEvents, so callers don't need to reach for the raw node reference.