11import assert from "node:assert" ;
2- import { type EvmRpcFilter , createEvmRpcClient } from "@apibara/rpc-evm" ;
2+ import { EvmRpcStream , type Filter } from "@apibara/evm-rpc" ;
3+ import { createRpcClient } from "@apibara/protocol/rpc" ;
34import { defineCommand , runMain } from "citty" ;
45import consola from "consola" ;
5- import type { Chain } from "viem" ;
6+ import { http , type Chain , createPublicClient } from "viem" ;
67import { mainnet , sepolia } from "viem/chains" ;
78
89const command = defineCommand ( {
@@ -19,7 +20,7 @@ const command = defineCommand({
1920 } ,
2021 network : {
2122 type : "string" ,
22- default : "sepolia " ,
23+ default : "mainnet " ,
2324 description : "Network name (mainnet, sepolia)" ,
2425 } ,
2526 contract : {
@@ -29,13 +30,13 @@ const command = defineCommand({
2930 } ,
3031 startBlock : {
3132 type : "string" ,
32- default : "23857000 " ,
33+ default : "23911400 " ,
3334 description : "Starting block number" ,
3435 } ,
3536 finality : {
3637 type : "string" ,
3738 default : "finalized" ,
38- description : "Block finality (finalized, accepted, pending )" ,
39+ description : "Block finality (finalized, accepted)" ,
3940 } ,
4041 } ,
4142 async run ( { args } ) {
@@ -44,42 +45,40 @@ const command = defineCommand({
4445
4546 const chain = ( args . network === "mainnet" ? mainnet : sepolia ) as Chain ;
4647
47- const client = createEvmRpcClient ( args . rpcUrl , chain , {
48- clientConfig : {
49- retryDelay : 10000 ,
50- onFetchRequest ( request ) {
51- request
52- . clone ( )
53- . json ( )
54- . then ( ( body ) => {
55- if ( Array . isArray ( body ) ) {
56- consola . debug ( `----->>> Batched ${ body . length } requests` ) ;
57- } else {
58- consola . debug ( "----->>> Single request" ) ;
59- }
60- // console.dir(body, { depth: null });
61- } ) ;
48+ const viemClient = createPublicClient ( {
49+ chain,
50+ transport : http ( args . rpcUrl , {
51+ batch : {
52+ wait : 10 ,
6253 } ,
63- } ,
54+ } ) ,
6455 } ) ;
6556
66- try {
67- const status = await client . status ( ) ;
68- consola . success ( "Connected to RPC endpoint" ) ;
69- consola . info ( "Current head:" , status . currentHead ?. orderKey ) ;
70- consola . info ( "Finalized:" , status . finalized ?. orderKey ) ;
71- } catch ( error ) {
72- consola . error ( "Failed to connect:" , error ) ;
73- process . exit ( 1 ) ;
74- }
57+ const client = createRpcClient (
58+ new EvmRpcStream ( viemClient , {
59+ getLogsRangeSize : 10n ,
60+ } ) ,
61+ ) ;
62+
63+ const status = await client . status ( ) ;
64+ consola . success ( "Connected to RPC endpoint" ) ;
65+ consola . info ( "Current head:" , status . currentHead ?. orderKey ) ;
66+ consola . info ( "Finalized:" , status . finalized ?. orderKey ) ;
7567
76- const filter : EvmRpcFilter = {
68+ const filter : Filter = {
69+ header : "always" ,
7770 logs : [
7871 {
79- address : args . contract as `0x${string } `,
80- topics : [
81- "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" as `0x${string } `,
82- ] ,
72+ id : 1 ,
73+ address : "0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444" ,
74+ } ,
75+ {
76+ id : 2 ,
77+ address : "0xA37cc341634AFD9E0919D334606E676dbAb63E17" ,
78+ } ,
79+ {
80+ id : 3 ,
81+ address : "0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444" ,
8382 } ,
8483 ] ,
8584 } ;
@@ -88,74 +87,70 @@ const command = defineCommand({
8887 consola . info ( "Monitoring contract:" , args . contract ) ;
8988 consola . info ( "Finality:" , args . finality ) ;
9089
91- try {
92- for await ( const message of client . streamData ( {
93- filter : [ filter ] ,
94- finality : args . finality as "finalized" | "accepted" | "pending" ,
95- startingCursor : {
96- orderKey : BigInt ( args . startBlock ) ,
97- } ,
98- } ) ) {
99- switch ( message . _tag ) {
100- case "data" : {
101- const { data, endCursor, finality, production } = message . data ;
102-
103- for ( const block of data ) {
104- assert ( block !== null ) ;
105- const logs = block . logs ;
106-
107- if ( logs . length > 0 ) {
108- consola . info (
109- `📦 Block ${ block . header ?. blockNumber } [${ finality } /${ production } ]` ,
110- ) ;
111- consola . info ( " Logs:" , logs . length ) ;
112-
113- for ( const log of logs ) {
114- consola . info ( " 🔔 Log" ) ;
115- consola . info ( " Tx:" , log . transactionHash ) ;
116- consola . info ( " Address:" , log . address ) ;
117- consola . info ( " Topics:" , log . topics . join ( ", " ) ) ;
118- consola . info ( " Log Index:" , log . logIndex ) ;
119- }
120- }
121- }
90+ for await ( const message of client . streamData ( {
91+ filter : [ filter ] ,
92+ finality : args . finality as "finalized" | "accepted" | "pending" ,
93+ startingCursor : {
94+ orderKey : BigInt ( args . startBlock ) ,
95+ } ,
96+ } ) ) {
97+ switch ( message . _tag ) {
98+ case "data" : {
99+ const { data, endCursor, finality, production } = message . data ;
122100
123- break ;
124- }
101+ for ( const block of data ) {
102+ assert ( block !== null ) ;
103+ const logs = block . logs ;
125104
126- case "invalidate" : {
127- consola . warn (
128- "⚠️ Reorg detected! Invalidating to block" ,
129- message . invalidate . cursor ?. orderKey ,
105+ consola . info (
106+ `block ${ block . header ?. blockNumber } [${ finality } /${ production } ]` ,
130107 ) ;
131- break ;
108+ consola . info ( " logs:" , logs . length ) ;
109+
110+ for ( const log of logs ) {
111+ // consola.info(log);
112+ // consola.info(" 🔔 Log");
113+ // consola.info(" Tx:", log.transactionHash);
114+ // consola.info(" Address:", log.address);
115+ // consola.info(" Topics:", log.topics.join(", "));
116+ // consola.info(" Log Index:", log.logIndex);
117+ }
132118 }
133119
134- case "finalize" : {
135- consola . success (
136- "✅ Finalized up to block" ,
137- message . finalize . cursor ?. orderKey ,
138- ) ;
139- break ;
140- }
120+ break ;
121+ }
141122
142- case "heartbeat" : {
143- consola . info ( "💓 Heartbeat" ) ;
144- break ;
145- }
123+ case "invalidate" : {
124+ consola . warn (
125+ "invalidating to block" ,
126+ message . invalidate . cursor ?. orderKey ,
127+ ) ;
128+ break ;
129+ }
146130
147- case "systemMessage" : {
148- const output = message . systemMessage . output ;
149- if ( output . _tag === "stderr" ) {
150- consola . error ( "System error:" , output . stderr ) ;
151- }
152- break ;
131+ case "finalize" : {
132+ consola . success (
133+ "finalized up to block" ,
134+ message . finalize . cursor ?. orderKey ,
135+ ) ;
136+ break ;
137+ }
138+
139+ case "heartbeat" : {
140+ consola . info ( "heartbeat" ) ;
141+ break ;
142+ }
143+
144+ case "systemMessage" : {
145+ const output = message . systemMessage . output ;
146+ if ( output . _tag === "stderr" ) {
147+ consola . error ( output . stderr ) ;
148+ } else {
149+ consola . info ( output . stdout ) ;
153150 }
151+ break ;
154152 }
155153 }
156- } catch ( error ) {
157- consola . error ( "Stream error:" , error ) ;
158- process . exit ( 1 ) ;
159154 }
160155 } ,
161156} ) ;
0 commit comments