Skip to content

Commit f6a287e

Browse files
[SDK] Optimize multi-event querying with indexer
1 parent 683e3b0 commit f6a287e

File tree

4 files changed

+67
-40
lines changed

4 files changed

+67
-40
lines changed

.changeset/great-chairs-find.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
More efficient multi event querying when using indexer

apps/dashboard/src/@3rdweb-sdk/react/hooks/useActivity.ts

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import { type AbiEvent, formatAbiItem } from "abitype";
1+
import {} from "abitype";
22
import { useMemo } from "react";
3-
import {
4-
type PreparedEvent,
5-
type ThirdwebContract,
6-
prepareEvent,
7-
} from "thirdweb";
3+
import type { ThirdwebContract } from "thirdweb";
84
import { useContractEvents } from "thirdweb/react";
9-
import { useResolveContractAbi } from "./useResolveContractAbi";
105

116
export interface InternalTransaction {
127
transactionHash: string;
@@ -20,20 +15,8 @@ export interface InternalTransaction {
2015
}
2116

2217
export function useActivity(contract: ThirdwebContract, autoUpdate?: boolean) {
23-
const abiQuery = useResolveContractAbi(contract);
24-
25-
// Get all the Prepare Events from the contract abis
26-
const events: PreparedEvent<AbiEvent>[] = useMemo(() => {
27-
const eventsItems = (abiQuery.data || []).filter((o) => o.type === "event");
28-
const eventSignatures = eventsItems.map((event) => formatAbiItem(event));
29-
return eventSignatures.map((signature) =>
30-
prepareEvent({ signature: signature as `event ${string}` }),
31-
);
32-
}, [abiQuery.data]);
33-
3418
const eventsQuery = useContractEvents({
3519
contract,
36-
events,
3720
blockRange: 20000,
3821
watch: autoUpdate,
3922
});
@@ -42,26 +25,29 @@ export function useActivity(contract: ThirdwebContract, autoUpdate?: boolean) {
4225
if (!eventsQuery.data) {
4326
return [];
4427
}
45-
const obj = eventsQuery.data.slice(0, 100).reduce(
46-
(acc, curr) => {
47-
const internalTx = acc[curr.transactionHash];
48-
if (internalTx) {
49-
internalTx.events.push(curr);
50-
internalTx.events.sort((a, b) => b.logIndex - a.logIndex);
51-
if (internalTx.blockNumber > curr.blockNumber) {
52-
internalTx.blockNumber = curr.blockNumber;
28+
const obj = eventsQuery.data
29+
.toReversed()
30+
.slice(0, 100)
31+
.reduce(
32+
(acc, curr) => {
33+
const internalTx = acc[curr.transactionHash];
34+
if (internalTx) {
35+
internalTx.events.push(curr);
36+
internalTx.events.sort((a, b) => b.logIndex - a.logIndex);
37+
if (internalTx.blockNumber > curr.blockNumber) {
38+
internalTx.blockNumber = curr.blockNumber;
39+
}
40+
} else {
41+
acc[curr.transactionHash] = {
42+
transactionHash: curr.transactionHash,
43+
blockNumber: curr.blockNumber,
44+
events: [curr],
45+
};
5346
}
54-
} else {
55-
acc[curr.transactionHash] = {
56-
transactionHash: curr.transactionHash,
57-
blockNumber: curr.blockNumber,
58-
events: [curr],
59-
};
60-
}
61-
return acc;
62-
},
63-
{} as Record<string, InternalTransaction>,
64-
);
47+
return acc;
48+
},
49+
{} as Record<string, InternalTransaction>,
50+
);
6551
return Object.values(obj).sort((a, b) =>
6652
a.blockNumber > b.blockNumber ? -1 : 1,
6753
);

packages/thirdweb/src/event/actions/get-events.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import type {
77
import { type Log, formatLog } from "viem";
88
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
99
import type { ThirdwebContract } from "../../contract/contract.js";
10-
import { getContractEvents as getContractEventsInsight } from "../../insight/get-events.js";
10+
import {
11+
type ContractEvent,
12+
getContractEvents as getContractEventsInsight,
13+
} from "../../insight/get-events.js";
1114
import { eth_blockNumber } from "../../rpc/actions/eth_blockNumber.js";
1215
import {
1316
type GetLogsBlockParams,
@@ -156,6 +159,23 @@ export async function getContractEvents<
156159

157160
// if we have an abi on the contract, we can encode the topics with it
158161
if (!events?.length && !!contract) {
162+
if (useIndexer) {
163+
// fetch all events from the indexer, no need to get events from ABI
164+
const events = await getContractEventsInsight({
165+
client: contract.client,
166+
chains: [contract.chain],
167+
contractAddress: contract.address,
168+
decodeLogs: true,
169+
queryOptions: {
170+
limit: 500,
171+
filter_block_hash: restParams.blockHash,
172+
filter_block_number_gte: restParams.fromBlock,
173+
filter_block_number_lte: restParams.toBlock,
174+
},
175+
});
176+
return toLog(events) as GetContractEventsResult<abiEvents, TStrict>;
177+
}
178+
159179
// if we have a contract *WITH* an abi we can use that
160180
if (contract.abi?.length) {
161181
// @ts-expect-error - we can't make typescript happy here, but we know this is an abi event
@@ -246,6 +266,10 @@ async function getLogsFromInsight(options: {
246266
},
247267
});
248268

269+
return toLog(r);
270+
}
271+
272+
function toLog(r: ContractEvent[]) {
249273
const cleanedEventData = r.map((tx) => ({
250274
chainId: tx.chain_id,
251275
blockNumber: numberToHex(Number(tx.block_number)),
@@ -257,7 +281,18 @@ async function getLogsFromInsight(options: {
257281
address: tx.address,
258282
data: tx.data as Hex,
259283
topics: tx.topics as [`0x${string}`, ...`0x${string}`[]] | [] | undefined,
284+
...(tx.decoded
285+
? {
286+
eventName: tx.decoded.name,
287+
args: {
288+
...tx.decoded.indexed_params,
289+
...tx.decoded.non_indexed_params,
290+
},
291+
}
292+
: {}),
260293
}));
261294

262-
return cleanedEventData.map((e) => formatLog(e));
295+
return cleanedEventData
296+
.map((e) => formatLog(e))
297+
.sort((a, b) => Number((a.blockNumber ?? 0n) - (b.blockNumber ?? 0n)));
263298
}

packages/thirdweb/src/event/actions/watch-events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export function watchContractEvents<
7777
fromBlock: blockNumber,
7878
// toBlock is inclusive
7979
toBlock: blockNumber,
80+
useIndexer: false,
8081
}),
8182
{
8283
retries: 3,

0 commit comments

Comments
 (0)