1+ import { grpcUserAccountSubscriber } from '../src/accounts/grpcUserAccountSubscriber' ;
2+ import { grpcMultiUserAccountSubscriber } from '../src/accounts/grpcMultiUserAccountSubscriber' ;
3+ import { Connection , Keypair , PublicKey } from '@solana/web3.js' ;
4+ import { DRIFT_PROGRAM_ID } from '../src' ;
5+ import { CommitmentLevel } from '@triton-one/yellowstone-grpc' ;
6+ import { AnchorProvider , Idl , Program } from '@coral-xyz/anchor' ;
7+ import driftIDL from '../src/idl/drift.json' ;
8+ import assert from 'assert' ;
9+ import { Wallet } from '../src' ;
10+
11+ const GRPC_ENDPOINT = process . env . GRPC_ENDPOINT ;
12+ const TOKEN = process . env . TOKEN ;
13+ const RPC_ENDPOINT = process . env . RPC_ENDPOINT ;
14+
15+ const USER_ACCOUNT_PUBKEYS = [
16+ // Add user account public keys here, e.g.:
17+ // new PublicKey('...')
18+ ] ;
19+
20+ async function testGrpcUserAccountSubscriberV1VsV2 ( ) {
21+ console . log ( '🚀 Initializing User Account Subscriber V1 vs V2 Test...' ) ;
22+
23+ if ( USER_ACCOUNT_PUBKEYS . length === 0 ) {
24+ console . error ( '❌ No user account public keys provided. Please add some to USER_ACCOUNT_PUBKEYS array.' ) ;
25+ process . exit ( 1 ) ;
26+ }
27+
28+ const connection = new Connection ( RPC_ENDPOINT ) ;
29+ const wallet = new Wallet ( new Keypair ( ) ) ;
30+
31+ const programId = new PublicKey ( DRIFT_PROGRAM_ID ) ;
32+ const provider = new AnchorProvider (
33+ connection ,
34+ // @ts -ignore
35+ wallet ,
36+ {
37+ commitment : 'processed' ,
38+ }
39+ ) ;
40+
41+ const program = new Program ( driftIDL as Idl , programId , provider ) ;
42+
43+ const grpcConfigs = {
44+ endpoint : GRPC_ENDPOINT ,
45+ token : TOKEN ,
46+ commitmentLevel : CommitmentLevel . PROCESSED ,
47+ channelOptions : {
48+ 'grpc.keepalive_time_ms' : 10_000 ,
49+ 'grpc.keepalive_timeout_ms' : 1_000 ,
50+ 'grpc.keepalive_permit_without_calls' : 1 ,
51+ } ,
52+ } ;
53+
54+ console . log ( `📊 Testing ${ USER_ACCOUNT_PUBKEYS . length } user accounts...` ) ;
55+
56+ // V1: Create individual subscribers for each user account
57+ const v1Subscribers = USER_ACCOUNT_PUBKEYS . map (
58+ ( pubkey ) =>
59+ new grpcUserAccountSubscriber (
60+ grpcConfigs ,
61+ program ,
62+ pubkey ,
63+ { logResubMessages : true }
64+ )
65+ ) ;
66+
67+ // V2: Create a single multi-subscriber and get per-user interfaces
68+ const v2MultiSubscriber = new grpcMultiUserAccountSubscriber (
69+ program ,
70+ grpcConfigs ,
71+ { logResubMessages : true }
72+ ) ;
73+ const v2Subscribers = USER_ACCOUNT_PUBKEYS . map ( ( pubkey ) =>
74+ v2MultiSubscriber . forUser ( pubkey )
75+ ) ;
76+
77+ // Subscribe all V1 subscribers
78+ console . log ( '🔗 Subscribing V1 subscribers...' ) ;
79+ await Promise . all ( v1Subscribers . map ( ( sub ) => sub . subscribe ( ) ) ) ;
80+ console . log ( '✅ V1 subscribers ready' ) ;
81+
82+ // Subscribe all V2 subscribers
83+ console . log ( '🔗 Subscribing V2 subscribers...' ) ;
84+ await v2MultiSubscriber . subscribe ( ) ;
85+ console . log ( '✅ V2 subscribers ready' ) ;
86+
87+ const compare = ( ) => {
88+ try {
89+ let passedTests = 0 ;
90+ let totalTests = 0 ;
91+
92+ // Test each user account
93+ for ( let i = 0 ; i < USER_ACCOUNT_PUBKEYS . length ; i ++ ) {
94+ const pubkey = USER_ACCOUNT_PUBKEYS [ i ] ;
95+ const v1Sub = v1Subscribers [ i ] ;
96+ const v2Sub = v2Subscribers [ i ] ;
97+
98+ totalTests ++ ;
99+
100+ // 1. Test isSubscribed
101+ assert . strictEqual (
102+ v1Sub . isSubscribed ,
103+ v2Sub . isSubscribed ,
104+ `User ${ pubkey . toBase58 ( ) } : isSubscribed should match`
105+ ) ;
106+
107+ // 2. Test getUserAccountAndSlot
108+ const v1Data = v1Sub . getUserAccountAndSlot ( ) ;
109+ const v2Data = v2Sub . getUserAccountAndSlot ( ) ;
110+
111+ // Compare the user account data
112+ assert . deepStrictEqual (
113+ v1Data . data ,
114+ v2Data . data ,
115+ `User ${ pubkey . toBase58 ( ) } : account data should match`
116+ ) ;
117+
118+ // Slots might differ slightly due to timing, but let's check if they're close
119+ const slotDiff = Math . abs ( v1Data . slot - v2Data . slot ) ;
120+ if ( slotDiff > 10 ) {
121+ console . warn (
122+ `⚠️ User ${ pubkey . toBase58 ( ) } : slot difference is ${ slotDiff } (v1: ${ v1Data . slot } , v2: ${ v2Data . slot } )`
123+ ) ;
124+ }
125+
126+ passedTests ++ ;
127+ }
128+
129+ console . log ( `✅ All comparisons passed (${ passedTests } /${ totalTests } user accounts)` ) ;
130+ } catch ( error ) {
131+ console . error ( '❌ Comparison failed:' , error ) ;
132+ }
133+ } ;
134+
135+ // Run initial comparison
136+ compare ( ) ;
137+
138+ // Run comparison every second to verify live updates
139+ const interval = setInterval ( compare , 1000 ) ;
140+
141+ const cleanup = async ( ) => {
142+ clearInterval ( interval ) ;
143+ console . log ( '🧹 Cleaning up...' ) ;
144+ await Promise . all ( [
145+ ...v1Subscribers . map ( ( sub ) => sub . unsubscribe ( ) ) ,
146+ ...v2Subscribers . map ( ( sub ) => sub . unsubscribe ( ) ) ,
147+ ] ) ;
148+ console . log ( '✅ Cleanup complete' ) ;
149+ process . exit ( 0 ) ;
150+ } ;
151+
152+ process . on ( 'SIGINT' , cleanup ) ;
153+ process . on ( 'SIGTERM' , cleanup ) ;
154+ }
155+
156+ testGrpcUserAccountSubscriberV1VsV2 ( ) . catch ( console . error ) ;
0 commit comments