@@ -11,7 +11,10 @@ import type {
1111 ExtractAbiEvent ,
1212 ExtractAbiEventNames ,
1313} from "abitype" ;
14- import { formatLog } from "viem" ;
14+ import { type Log , formatLog } from "viem" ;
15+ import type { Chain } from "../../chains/types.js" ;
16+ import { getChainServices } from "../../chains/utils.js" ;
17+ import type { ThirdwebClient } from "../../client/client.js" ;
1518import { resolveContractAbi } from "../../contract/actions/resolve-abi.js" ;
1619import type { ThirdwebContract } from "../../contract/contract.js" ;
1720import { eth_blockNumber } from "../../rpc/actions/eth_blockNumber.js" ;
@@ -22,7 +25,7 @@ import {
2225} from "../../rpc/actions/eth_getLogs.js" ;
2326import { getRpcClient } from "../../rpc/rpc.js" ;
2427import { getAddress } from "../../utils/address.js" ;
25- import { getThirdwebDomains } from "../../utils/domains .js" ;
28+ import { type Hex , numberToHex } from "../../utils/encoding/hex .js" ;
2629import { getClientFetch } from "../../utils/fetch.js" ;
2730import type { Prettify } from "../../utils/type-utils.js" ;
2831import { type PreparedEvent , prepareEvent } from "../prepare-event.js" ;
@@ -52,13 +55,9 @@ export type GetContractEventsResult<
5255 TStrict extends boolean ,
5356> = ParseEventLogsResult < abiEvents , TStrict > ;
5457
55- type InsightEvent = {
56- data : {
57- address : string ;
58- data : `0x${string } `;
59- topics : [ `0x${string } `, ...`0x${string } `[ ] ] | [ ] ;
60- } [ ] ;
61- } ;
58+ export type GetLogsParamsExtra = {
59+ signature ?: string ;
60+ } & GetLogsParams ;
6261
6362/**
6463 * Retrieves events from a contract based on the provided options.
@@ -121,29 +120,6 @@ export async function getContractEvents<
121120
122121 const rpcRequest = getRpcClient ( contract ) ;
123122
124- try {
125- if ( events ) {
126- const sig = `${ events [ 0 ] ?. abiEvent . name } (${ events [ 0 ] ?. abiEvent . inputs . map ( ( i ) => i . type ) . join ( "," ) } )` ;
127- const url = new URL (
128- `https://${ getThirdwebDomains ( ) . insight } /v1/events/${ contract . address } /${ sig } ` ,
129- ) ;
130- url . searchParams . set ( "limit" , "10" ) ;
131- url . searchParams . set ( "chain" , contract . chain . id . toString ( ) ) ;
132- const clientFetch = getClientFetch ( contract . client ) ;
133- const result = await clientFetch ( url . toString ( ) ) ;
134- const eventInfo = ( await result . json ( ) ) as InsightEvent ;
135- const cleanedEventInfo = eventInfo . data . map ( ( e ) => formatLog ( e ) ) ;
136-
137- return parseEventLogs ( {
138- logs : cleanedEventInfo ,
139- events,
140- } ) ;
141- }
142- } catch ( error ) {
143- //biome-ignore lint/suspicious/noConsole: Todo
144- console . debug ( error ) ;
145- }
146-
147123 if (
148124 restParams . blockHash &&
149125 ( blockRange || restParams . fromBlock || restParams . toBlock )
@@ -198,20 +174,38 @@ export async function getContractEvents<
198174 }
199175 }
200176
201- const logsParams : GetLogsParams [ ] =
177+ const logsParams : GetLogsParamsExtra [ ] =
202178 events && events . length > 0
203179 ? // if we have events passed in then we use those
204180 events . map ( ( e ) => ( {
205181 ...restParams ,
206182 address : getAddress ( contract . address ) ,
207183 topics : e . topics ,
184+ signature : `${ e ?. abiEvent . name } (${ e ?. abiEvent . inputs . map ( ( i ) => i . type ) . join ( "," ) } )` ,
208185 } ) )
209186 : // otherwise we want "all" events (aka not pass any topics at all)
210187 [ { ...restParams , address : getAddress ( contract . address ) } ] ;
211188
212- const logs = await Promise . all (
213- logsParams . map ( ( ethLogParams ) => eth_getLogs ( rpcRequest , ethLogParams ) ) ,
214- ) ;
189+ let logs : Log [ ] [ ] = [ ] ;
190+
191+ // try fetching from insight if available
192+ try {
193+ logs = await Promise . all (
194+ logsParams . map ( ( p ) =>
195+ getLogsFromInsight ( {
196+ params : p ,
197+ chain : contract . chain ,
198+ client : contract . client ,
199+ } ) ,
200+ ) ,
201+ ) ;
202+ } catch {
203+ // fetch from rpc
204+ logs = await Promise . all (
205+ logsParams . map ( ( ethLogParams ) => eth_getLogs ( rpcRequest , ethLogParams ) ) ,
206+ ) ;
207+ }
208+
215209 const flattenLogs = logs
216210 . flat ( )
217211 . sort ( ( a , b ) => Number ( ( a . blockNumber ?? 0n ) - ( b . blockNumber ?? 0n ) ) ) ;
@@ -220,3 +214,90 @@ export async function getContractEvents<
220214 events : resolvedEvents ,
221215 } ) ;
222216}
217+
218+ async function getLogsFromInsight ( options : {
219+ params : GetLogsParamsExtra ;
220+ chain : Chain ;
221+ client : ThirdwebClient ;
222+ signature ?: string ;
223+ } ) : Promise < Log [ ] > {
224+ const { params, chain, client } = options ;
225+
226+ const chainServices = await getChainServices ( chain ) ;
227+ const insightEnabled = chainServices . some (
228+ ( c ) => c . service === "insight" && c . enabled ,
229+ ) ;
230+
231+ if ( ! insightEnabled ) {
232+ throw new Error ( `Insight is not available for chainId ${ chain . id } ` ) ;
233+ }
234+
235+ try {
236+ const baseUrl = new URL ( "https://insight.thirdweb-dev.com/v1/events" ) ; // TODO: change to prod
237+ let path = "" ;
238+ if ( params . address ) {
239+ path += `/${ params . address } ` ;
240+ if ( params . signature ) {
241+ path += `/${ params . signature } ` ;
242+ }
243+ }
244+ const url = new URL ( path , baseUrl ) ;
245+
246+ url . searchParams . set ( "chain" , chain . id . toString ( ) ) ;
247+ url . searchParams . set ( "limit" , "500" ) ; // this is max limit on insight
248+
249+ if ( params . blockHash ) {
250+ url . searchParams . set ( "filter_block_hash" , params . blockHash ) ;
251+ } else {
252+ if ( params . fromBlock ) {
253+ const fromBlock =
254+ typeof params . fromBlock === "bigint"
255+ ? numberToHex ( params . fromBlock )
256+ : params . fromBlock ;
257+
258+ url . searchParams . set ( "filter_block_number_gte" , fromBlock ) ;
259+ }
260+ if ( params . toBlock ) {
261+ const toBlock =
262+ typeof params . toBlock === "bigint"
263+ ? numberToHex ( params . toBlock )
264+ : params . toBlock ;
265+
266+ url . searchParams . set ( "filter_block_number_lte" , toBlock ) ;
267+ }
268+ }
269+
270+ const clientFetch = getClientFetch ( client ) ;
271+ const result = await clientFetch ( url . toString ( ) ) ;
272+ const fetchedEventData = ( await result . json ( ) ) as {
273+ data : {
274+ chain_id : number ;
275+ block_number : number ;
276+ block_hash : string ;
277+ block_timestamp : string ;
278+ transaction_hash : string ;
279+ transaction_index : number ;
280+ log_index : number ;
281+ address : string ;
282+ data : string ;
283+ topics : string [ ] ;
284+ } [ ] ;
285+ } ;
286+ const cleanedEventData = fetchedEventData . data . map ( ( tx ) => ( {
287+ chainId : tx . chain_id ,
288+ blockNumber : numberToHex ( tx . block_number ) ,
289+ blockHash : tx . block_hash as Hex ,
290+ blockTimestamp : tx . block_timestamp ,
291+ transactionHash : tx . transaction_hash as Hex ,
292+ transactionIndex : numberToHex ( tx . transaction_index ) ,
293+ logIndex : numberToHex ( tx . log_index ) ,
294+ address : tx . address ,
295+ data : tx . data as Hex ,
296+ topics : tx . topics as [ `0x${string } `, ...`0x${string } `[ ] ] | [ ] | undefined ,
297+ } ) ) ;
298+
299+ return cleanedEventData . map ( ( e ) => formatLog ( e ) ) ;
300+ } catch {
301+ throw new Error ( "Error fetching events from insight" ) ;
302+ }
303+ }
0 commit comments