1
1
import { Prisma , Webhooks } from "@prisma/client" ;
2
+ import { AbiEvent } from "abitype" ;
2
3
import { Job , Processor , Worker } from "bullmq" ;
3
4
import superjson from "superjson" ;
4
5
import {
6
+ Chain ,
5
7
PreparedEvent ,
6
8
defineChain ,
7
9
eth_getBlockByHash ,
@@ -11,6 +13,7 @@ import {
11
13
prepareEvent ,
12
14
} from "thirdweb" ;
13
15
import { resolveContractAbi } from "thirdweb/contract" ;
16
+ import { Hash } from "viem" ;
14
17
import { bulkInsertContractEventLogs } from "../../db/contractEventLogs/createContractEventLogs" ;
15
18
import { getContractSubscriptionsByChainId } from "../../db/contractSubscriptions/getContractSubscriptions" ;
16
19
import { WebhooksEventTypes } from "../../schema/webhooks" ;
@@ -104,23 +107,19 @@ const getLogs = async (
104
107
params : GetLogsParams ,
105
108
) : Promise < Prisma . ContractEventLogsCreateInput [ ] > => {
106
109
const chain = defineChain ( params . chainId ) ;
107
- const rpcRequest = getRpcClient ( {
108
- client : thirdwebClient ,
109
- chain,
110
- } ) ;
111
110
112
111
// Get events for each contract address. Apply any filters.
113
112
const promises = params . filters . map ( async ( f ) => {
114
- const contract = await getContract ( {
113
+ const contract = getContract ( {
115
114
client : thirdwebClient ,
116
115
chain,
117
116
address : f . address ,
118
117
} ) ;
119
118
120
119
// Get events to filter by, if any.
121
- const events : PreparedEvent [ ] = [ ] ;
120
+ const events : PreparedEvent < AbiEvent > [ ] = [ ] ;
122
121
if ( f . events . length ) {
123
- const abi = await resolveContractAbi ( contract ) ;
122
+ const abi = await resolveContractAbi < AbiEvent [ ] > ( contract ) ;
124
123
for ( const event of f . events ) {
125
124
const signature = abi . find ( ( a ) => a . name === event ) ;
126
125
if ( signature ) {
@@ -141,13 +140,12 @@ const getLogs = async (
141
140
// Query and flatten all events.
142
141
const allEvents = ( await Promise . all ( promises ) ) . flat ( ) ;
143
142
144
- // Transform logs into the DB schema.
145
- const formattedLogs : Prisma . ContractEventLogsCreateInput [ ] = [ ] ;
146
- for ( const event of allEvents ) {
147
- // This makes an RPC call, but it should be cached in SDK when querying the same block hash.
148
- const timestamp = await getBlockTimestamp ( rpcRequest , event . blockHash ) ;
143
+ const blockHashes = allEvents . map ( ( e ) => e . blockHash ) ;
144
+ const blockTimestamps = await getBlockTimestamps ( chain , blockHashes ) ;
149
145
150
- formattedLogs . push ( {
146
+ // Transform logs into the DB schema.
147
+ return allEvents . map (
148
+ ( event ) : Prisma . ContractEventLogsCreateInput => ( {
151
149
chainId : params . chainId ,
152
150
blockNumber : Number ( event . blockNumber ) ,
153
151
contractAddress : event . address . toLowerCase ( ) ,
@@ -159,25 +157,41 @@ const getLogs = async (
159
157
data : event . data ,
160
158
eventName : event . eventName ,
161
159
decodedLog : event . args ,
162
- timestamp,
160
+ timestamp : blockTimestamps [ event . blockHash ] ,
163
161
transactionIndex : event . transactionIndex ,
164
162
logIndex : event . logIndex ,
165
- } ) ;
166
- }
167
-
168
- return formattedLogs ;
163
+ } ) ,
164
+ ) ;
169
165
} ;
170
166
171
- const getBlockTimestamp = async (
172
- rpcRequest : ReturnType < typeof getRpcClient > ,
173
- blockHash : `0x${string } `,
174
- ) : Promise < Date > => {
175
- try {
176
- const block = await eth_getBlockByHash ( rpcRequest , { blockHash } ) ;
177
- return new Date ( block . timestamp * 1000n ) ;
178
- } catch ( e ) {
179
- return new Date ( ) ;
167
+ export const getBlockTimestamps = async (
168
+ chain : Chain ,
169
+ blockHashes : Hash [ ] ,
170
+ ) : Promise < Record < Hash , Date > > => {
171
+ const rpcRequest = getRpcClient ( {
172
+ client : thirdwebClient ,
173
+ chain,
174
+ } ) ;
175
+
176
+ const now = new Date ( ) ;
177
+ const dedupe = Array . from ( new Set ( blockHashes ) ) ;
178
+
179
+ const blocks = await Promise . all (
180
+ dedupe . map ( async ( blockHash ) => {
181
+ try {
182
+ const block = await eth_getBlockByHash ( rpcRequest , { blockHash } ) ;
183
+ return new Date ( Number ( block . timestamp * 1000n ) ) ;
184
+ } catch ( e ) {
185
+ return now ;
186
+ }
187
+ } ) ,
188
+ ) ;
189
+
190
+ const res : Record < Hash , Date > = { } ;
191
+ for ( let i = 0 ; i < dedupe . length ; i ++ ) {
192
+ res [ dedupe [ i ] ] = blocks [ i ] ;
180
193
}
194
+ return res ;
181
195
} ;
182
196
183
197
// Worker
0 commit comments