Skip to content

Commit 3c5b298

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

File tree

4 files changed

+71
-40
lines changed

4 files changed

+71
-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: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
import { type AbiEvent, formatAbiItem } from "abitype";
21
import { useMemo } from "react";
3-
import {
4-
type PreparedEvent,
5-
type ThirdwebContract,
6-
prepareEvent,
7-
} from "thirdweb";
2+
import type { ThirdwebContract } from "thirdweb";
83
import { useContractEvents } from "thirdweb/react";
9-
import { useResolveContractAbi } from "./useResolveContractAbi";
104

115
export interface InternalTransaction {
126
transactionHash: string;
@@ -20,20 +14,8 @@ export interface InternalTransaction {
2014
}
2115

2216
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-
3417
const eventsQuery = useContractEvents({
3518
contract,
36-
events,
3719
blockRange: 20000,
3820
watch: autoUpdate,
3921
});
@@ -42,26 +24,29 @@ export function useActivity(contract: ThirdwebContract, autoUpdate?: boolean) {
4224
if (!eventsQuery.data) {
4325
return [];
4426
}
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;
27+
const obj = eventsQuery.data
28+
.toReversed()
29+
.slice(0, 100)
30+
.reduce(
31+
(acc, curr) => {
32+
const internalTx = acc[curr.transactionHash];
33+
if (internalTx) {
34+
internalTx.events.push(curr);
35+
internalTx.events.sort((a, b) => b.logIndex - a.logIndex);
36+
if (internalTx.blockNumber > curr.blockNumber) {
37+
internalTx.blockNumber = curr.blockNumber;
38+
}
39+
} else {
40+
acc[curr.transactionHash] = {
41+
transactionHash: curr.transactionHash,
42+
blockNumber: curr.blockNumber,
43+
events: [curr],
44+
};
5345
}
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-
);
46+
return acc;
47+
},
48+
{} as Record<string, InternalTransaction>,
49+
);
6550
return Object.values(obj).sort((a, b) =>
6651
a.blockNumber > b.blockNumber ? -1 : 1,
6752
);

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

Lines changed: 42 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,28 @@ 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+
}).catch(() => {
176+
// chain might not support indexer
177+
return null;
178+
});
179+
if (events) {
180+
return toLog(events) as GetContractEventsResult<abiEvents, TStrict>;
181+
}
182+
}
183+
159184
// if we have a contract *WITH* an abi we can use that
160185
if (contract.abi?.length) {
161186
// @ts-expect-error - we can't make typescript happy here, but we know this is an abi event
@@ -246,6 +271,10 @@ async function getLogsFromInsight(options: {
246271
},
247272
});
248273

274+
return toLog(r);
275+
}
276+
277+
function toLog(r: ContractEvent[]) {
249278
const cleanedEventData = r.map((tx) => ({
250279
chainId: tx.chain_id,
251280
blockNumber: numberToHex(Number(tx.block_number)),
@@ -257,7 +286,18 @@ async function getLogsFromInsight(options: {
257286
address: tx.address,
258287
data: tx.data as Hex,
259288
topics: tx.topics as [`0x${string}`, ...`0x${string}`[]] | [] | undefined,
289+
...(tx.decoded
290+
? {
291+
eventName: tx.decoded.name,
292+
args: {
293+
...tx.decoded.indexed_params,
294+
...tx.decoded.non_indexed_params,
295+
},
296+
}
297+
: {}),
260298
}));
261299

262-
return cleanedEventData.map((e) => formatLog(e));
300+
return cleanedEventData
301+
.map((e) => formatLog(e))
302+
.sort((a, b) => Number((a.blockNumber ?? 0n) - (b.blockNumber ?? 0n)));
263303
}

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)