northstar-eva-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2473 @@
1
+ /* eslint-disable */
2
+ // ============================================================================
3
+ // northstar-eva-sdk — SINGLE-FILE BUILD (generated; do not edit by hand)
4
+ // Drop this file in, then: npm i @solana/web3.js @coral-xyz/anchor @solana/spl-token
5
+ // Usage: import { NorthstarEva } from "./northstar-eva-sdk.single.ts";
6
+ // Source of truth: northstar-eva-sdk/src/* — regenerate with: npm run bundle
7
+ // ============================================================================
8
+ import * as anchor from "@coral-xyz/anchor";
9
+ import { readFileSync } from "node:fs";
10
+ import { Connection, Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction, sendAndConfirmTransaction } from "@solana/web3.js";
11
+ import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountIdempotentInstruction } from "@solana/spl-token";
12
+ // --- embedded eva IDL (CQru6…) ---
13
+ const __EVA_IDL__ = {
14
+ "address": "CQru6EauVg2UwepFCvY5qWuqCPEWYC4ta43wBbkFYtmo",
15
+ "metadata": {
16
+ "name": "eva_arena",
17
+ "version": "0.1.4",
18
+ "spec": "0.1.0",
19
+ "description": "Created with Anchor"
20
+ },
21
+ "instructions": [
22
+ {
23
+ "name": "buy",
24
+ "discriminator": [
25
+ 102,
26
+ 6,
27
+ 61,
28
+ 18,
29
+ 1,
30
+ 218,
31
+ 235,
32
+ 234
33
+ ],
34
+ "accounts": [
35
+ {
36
+ "name": "trench",
37
+ "writable": true
38
+ },
39
+ {
40
+ "name": "global_state",
41
+ "writable": true
42
+ },
43
+ {
44
+ "name": "fee_recipient",
45
+ "writable": true
46
+ },
47
+ {
48
+ "name": "user",
49
+ "writable": true,
50
+ "signer": true
51
+ },
52
+ {
53
+ "name": "trench_token_vault",
54
+ "docs": [
55
+ "Vault holding trench's tokens (ATA owned by trench)"
56
+ ],
57
+ "writable": true,
58
+ "pda": {
59
+ "seeds": [
60
+ {
61
+ "kind": "account",
62
+ "path": "trench"
63
+ },
64
+ {
65
+ "kind": "const",
66
+ "value": [
67
+ 6,
68
+ 221,
69
+ 246,
70
+ 225,
71
+ 215,
72
+ 101,
73
+ 161,
74
+ 147,
75
+ 217,
76
+ 203,
77
+ 225,
78
+ 70,
79
+ 206,
80
+ 235,
81
+ 121,
82
+ 172,
83
+ 28,
84
+ 180,
85
+ 133,
86
+ 237,
87
+ 95,
88
+ 91,
89
+ 55,
90
+ 145,
91
+ 58,
92
+ 140,
93
+ 245,
94
+ 133,
95
+ 126,
96
+ 255,
97
+ 0,
98
+ 169
99
+ ]
100
+ },
101
+ {
102
+ "kind": "account",
103
+ "path": "trench.token_mint",
104
+ "account": "Trench"
105
+ }
106
+ ],
107
+ "program": {
108
+ "kind": "const",
109
+ "value": [
110
+ 140,
111
+ 151,
112
+ 37,
113
+ 143,
114
+ 78,
115
+ 36,
116
+ 137,
117
+ 241,
118
+ 187,
119
+ 61,
120
+ 16,
121
+ 41,
122
+ 20,
123
+ 142,
124
+ 13,
125
+ 131,
126
+ 11,
127
+ 90,
128
+ 19,
129
+ 153,
130
+ 218,
131
+ 255,
132
+ 16,
133
+ 132,
134
+ 4,
135
+ 142,
136
+ 123,
137
+ 216,
138
+ 219,
139
+ 233,
140
+ 248,
141
+ 89
142
+ ]
143
+ }
144
+ }
145
+ },
146
+ {
147
+ "name": "user_token_account",
148
+ "docs": [
149
+ "User's token account (must match trench's token mint)"
150
+ ],
151
+ "writable": true
152
+ },
153
+ {
154
+ "name": "system_program",
155
+ "address": "11111111111111111111111111111111"
156
+ },
157
+ {
158
+ "name": "token_program",
159
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
160
+ }
161
+ ],
162
+ "args": [
163
+ {
164
+ "name": "sol_pay_with_fee",
165
+ "type": "u64"
166
+ },
167
+ {
168
+ "name": "think_id",
169
+ "type": "u64"
170
+ }
171
+ ]
172
+ },
173
+ {
174
+ "name": "claim_tokens",
175
+ "discriminator": [
176
+ 108,
177
+ 216,
178
+ 210,
179
+ 231,
180
+ 0,
181
+ 212,
182
+ 42,
183
+ 64
184
+ ],
185
+ "accounts": [
186
+ {
187
+ "name": "global_state",
188
+ "pda": {
189
+ "seeds": [
190
+ {
191
+ "kind": "const",
192
+ "value": [
193
+ 103,
194
+ 108,
195
+ 111,
196
+ 98,
197
+ 97,
198
+ 108
199
+ ]
200
+ }
201
+ ]
202
+ }
203
+ },
204
+ {
205
+ "name": "trench",
206
+ "writable": true
207
+ },
208
+ {
209
+ "name": "agent",
210
+ "writable": true,
211
+ "pda": {
212
+ "seeds": [
213
+ {
214
+ "kind": "const",
215
+ "value": [
216
+ 97,
217
+ 103,
218
+ 101,
219
+ 110,
220
+ 116
221
+ ]
222
+ },
223
+ {
224
+ "kind": "account",
225
+ "path": "trench"
226
+ },
227
+ {
228
+ "kind": "account",
229
+ "path": "user"
230
+ }
231
+ ]
232
+ }
233
+ },
234
+ {
235
+ "name": "user"
236
+ },
237
+ {
238
+ "name": "admin",
239
+ "docs": [
240
+ "Admin who can claim tokens for user"
241
+ ],
242
+ "writable": true,
243
+ "signer": true
244
+ },
245
+ {
246
+ "name": "trench_token_vault",
247
+ "writable": true,
248
+ "pda": {
249
+ "seeds": [
250
+ {
251
+ "kind": "account",
252
+ "path": "trench"
253
+ },
254
+ {
255
+ "kind": "const",
256
+ "value": [
257
+ 6,
258
+ 221,
259
+ 246,
260
+ 225,
261
+ 215,
262
+ 101,
263
+ 161,
264
+ 147,
265
+ 217,
266
+ 203,
267
+ 225,
268
+ 70,
269
+ 206,
270
+ 235,
271
+ 121,
272
+ 172,
273
+ 28,
274
+ 180,
275
+ 133,
276
+ 237,
277
+ 95,
278
+ 91,
279
+ 55,
280
+ 145,
281
+ 58,
282
+ 140,
283
+ 245,
284
+ 133,
285
+ 126,
286
+ 255,
287
+ 0,
288
+ 169
289
+ ]
290
+ },
291
+ {
292
+ "kind": "account",
293
+ "path": "trench.token_mint",
294
+ "account": "Trench"
295
+ }
296
+ ],
297
+ "program": {
298
+ "kind": "const",
299
+ "value": [
300
+ 140,
301
+ 151,
302
+ 37,
303
+ 143,
304
+ 78,
305
+ 36,
306
+ 137,
307
+ 241,
308
+ 187,
309
+ 61,
310
+ 16,
311
+ 41,
312
+ 20,
313
+ 142,
314
+ 13,
315
+ 131,
316
+ 11,
317
+ 90,
318
+ 19,
319
+ 153,
320
+ 218,
321
+ 255,
322
+ 16,
323
+ 132,
324
+ 4,
325
+ 142,
326
+ 123,
327
+ 216,
328
+ 219,
329
+ 233,
330
+ 248,
331
+ 89
332
+ ]
333
+ }
334
+ }
335
+ },
336
+ {
337
+ "name": "user_token_account",
338
+ "writable": true
339
+ },
340
+ {
341
+ "name": "token_program",
342
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
343
+ }
344
+ ],
345
+ "args": []
346
+ },
347
+ {
348
+ "name": "close_pool",
349
+ "discriminator": [
350
+ 140,
351
+ 189,
352
+ 209,
353
+ 23,
354
+ 239,
355
+ 62,
356
+ 239,
357
+ 11
358
+ ],
359
+ "accounts": [
360
+ {
361
+ "name": "trench",
362
+ "writable": true
363
+ },
364
+ {
365
+ "name": "global_state",
366
+ "writable": true
367
+ },
368
+ {
369
+ "name": "fee_recipient",
370
+ "writable": true
371
+ },
372
+ {
373
+ "name": "admin",
374
+ "writable": true,
375
+ "signer": true
376
+ },
377
+ {
378
+ "name": "system_program",
379
+ "address": "11111111111111111111111111111111"
380
+ }
381
+ ],
382
+ "args": []
383
+ },
384
+ {
385
+ "name": "create_trench",
386
+ "discriminator": [
387
+ 66,
388
+ 74,
389
+ 73,
390
+ 171,
391
+ 206,
392
+ 39,
393
+ 116,
394
+ 230
395
+ ],
396
+ "accounts": [
397
+ {
398
+ "name": "global_state",
399
+ "writable": true
400
+ },
401
+ {
402
+ "name": "trench",
403
+ "writable": true,
404
+ "pda": {
405
+ "seeds": [
406
+ {
407
+ "kind": "const",
408
+ "value": [
409
+ 116,
410
+ 114,
411
+ 101,
412
+ 110,
413
+ 99,
414
+ 104
415
+ ]
416
+ },
417
+ {
418
+ "kind": "arg",
419
+ "path": "id"
420
+ }
421
+ ]
422
+ }
423
+ },
424
+ {
425
+ "name": "token_mint",
426
+ "writable": true,
427
+ "pda": {
428
+ "seeds": [
429
+ {
430
+ "kind": "const",
431
+ "value": [
432
+ 109,
433
+ 105,
434
+ 110,
435
+ 116
436
+ ]
437
+ },
438
+ {
439
+ "kind": "account",
440
+ "path": "trench"
441
+ }
442
+ ]
443
+ }
444
+ },
445
+ {
446
+ "name": "token_vault",
447
+ "writable": true,
448
+ "pda": {
449
+ "seeds": [
450
+ {
451
+ "kind": "account",
452
+ "path": "trench"
453
+ },
454
+ {
455
+ "kind": "const",
456
+ "value": [
457
+ 6,
458
+ 221,
459
+ 246,
460
+ 225,
461
+ 215,
462
+ 101,
463
+ 161,
464
+ 147,
465
+ 217,
466
+ 203,
467
+ 225,
468
+ 70,
469
+ 206,
470
+ 235,
471
+ 121,
472
+ 172,
473
+ 28,
474
+ 180,
475
+ 133,
476
+ 237,
477
+ 95,
478
+ 91,
479
+ 55,
480
+ 145,
481
+ 58,
482
+ 140,
483
+ 245,
484
+ 133,
485
+ 126,
486
+ 255,
487
+ 0,
488
+ 169
489
+ ]
490
+ },
491
+ {
492
+ "kind": "account",
493
+ "path": "token_mint"
494
+ }
495
+ ],
496
+ "program": {
497
+ "kind": "const",
498
+ "value": [
499
+ 140,
500
+ 151,
501
+ 37,
502
+ 143,
503
+ 78,
504
+ 36,
505
+ 137,
506
+ 241,
507
+ 187,
508
+ 61,
509
+ 16,
510
+ 41,
511
+ 20,
512
+ 142,
513
+ 13,
514
+ 131,
515
+ 11,
516
+ 90,
517
+ 19,
518
+ 153,
519
+ 218,
520
+ 255,
521
+ 16,
522
+ 132,
523
+ 4,
524
+ 142,
525
+ 123,
526
+ 216,
527
+ 219,
528
+ 233,
529
+ 248,
530
+ 89
531
+ ]
532
+ }
533
+ }
534
+ },
535
+ {
536
+ "name": "creator",
537
+ "writable": true,
538
+ "signer": true
539
+ },
540
+ {
541
+ "name": "system_program",
542
+ "address": "11111111111111111111111111111111"
543
+ },
544
+ {
545
+ "name": "token_program",
546
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
547
+ },
548
+ {
549
+ "name": "associated_token_program",
550
+ "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
551
+ },
552
+ {
553
+ "name": "rent",
554
+ "address": "SysvarRent111111111111111111111111111111111"
555
+ }
556
+ ],
557
+ "args": [
558
+ {
559
+ "name": "id",
560
+ "type": "u64"
561
+ },
562
+ {
563
+ "name": "initial_virtual_token_reserves",
564
+ "type": "u64"
565
+ }
566
+ ]
567
+ },
568
+ {
569
+ "name": "deposit",
570
+ "discriminator": [
571
+ 242,
572
+ 35,
573
+ 198,
574
+ 137,
575
+ 82,
576
+ 225,
577
+ 242,
578
+ 182
579
+ ],
580
+ "accounts": [
581
+ {
582
+ "name": "trench",
583
+ "writable": true
584
+ },
585
+ {
586
+ "name": "agent",
587
+ "writable": true,
588
+ "pda": {
589
+ "seeds": [
590
+ {
591
+ "kind": "const",
592
+ "value": [
593
+ 97,
594
+ 103,
595
+ 101,
596
+ 110,
597
+ 116
598
+ ]
599
+ },
600
+ {
601
+ "kind": "account",
602
+ "path": "trench"
603
+ },
604
+ {
605
+ "kind": "account",
606
+ "path": "user"
607
+ }
608
+ ]
609
+ }
610
+ },
611
+ {
612
+ "name": "user",
613
+ "writable": true,
614
+ "signer": true
615
+ },
616
+ {
617
+ "name": "system_program",
618
+ "address": "11111111111111111111111111111111"
619
+ }
620
+ ],
621
+ "args": [
622
+ {
623
+ "name": "amount",
624
+ "type": "u64"
625
+ },
626
+ {
627
+ "name": "think_id",
628
+ "type": "u64"
629
+ }
630
+ ]
631
+ },
632
+ {
633
+ "name": "distribute_prize",
634
+ "discriminator": [
635
+ 153,
636
+ 175,
637
+ 67,
638
+ 111,
639
+ 205,
640
+ 207,
641
+ 106,
642
+ 15
643
+ ],
644
+ "accounts": [
645
+ {
646
+ "name": "trench",
647
+ "writable": true
648
+ },
649
+ {
650
+ "name": "global_state",
651
+ "writable": true
652
+ },
653
+ {
654
+ "name": "fee_recipient",
655
+ "writable": true
656
+ },
657
+ {
658
+ "name": "admin",
659
+ "writable": true,
660
+ "signer": true
661
+ },
662
+ {
663
+ "name": "system_program",
664
+ "address": "11111111111111111111111111111111"
665
+ }
666
+ ],
667
+ "args": [
668
+ {
669
+ "name": "winners",
670
+ "type": {
671
+ "vec": "pubkey"
672
+ }
673
+ },
674
+ {
675
+ "name": "amounts",
676
+ "type": {
677
+ "vec": "u64"
678
+ }
679
+ }
680
+ ]
681
+ },
682
+ {
683
+ "name": "finalize",
684
+ "discriminator": [
685
+ 171,
686
+ 61,
687
+ 218,
688
+ 56,
689
+ 127,
690
+ 115,
691
+ 12,
692
+ 217
693
+ ],
694
+ "accounts": [
695
+ {
696
+ "name": "trench",
697
+ "writable": true
698
+ },
699
+ {
700
+ "name": "global_state",
701
+ "writable": true
702
+ },
703
+ {
704
+ "name": "fee_recipient",
705
+ "writable": true
706
+ },
707
+ {
708
+ "name": "admin",
709
+ "writable": true,
710
+ "signer": true
711
+ },
712
+ {
713
+ "name": "system_program",
714
+ "address": "11111111111111111111111111111111"
715
+ },
716
+ {
717
+ "name": "token_program",
718
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
719
+ },
720
+ {
721
+ "name": "rent",
722
+ "address": "SysvarRent111111111111111111111111111111111"
723
+ }
724
+ ],
725
+ "args": []
726
+ },
727
+ {
728
+ "name": "initialize",
729
+ "discriminator": [
730
+ 175,
731
+ 175,
732
+ 109,
733
+ 31,
734
+ 13,
735
+ 152,
736
+ 155,
737
+ 237
738
+ ],
739
+ "accounts": [
740
+ {
741
+ "name": "global_state",
742
+ "writable": true,
743
+ "pda": {
744
+ "seeds": [
745
+ {
746
+ "kind": "const",
747
+ "value": [
748
+ 103,
749
+ 108,
750
+ 111,
751
+ 98,
752
+ 97,
753
+ 108
754
+ ]
755
+ }
756
+ ]
757
+ }
758
+ },
759
+ {
760
+ "name": "admin",
761
+ "writable": true,
762
+ "signer": true
763
+ },
764
+ {
765
+ "name": "system_program",
766
+ "address": "11111111111111111111111111111111"
767
+ }
768
+ ],
769
+ "args": [
770
+ {
771
+ "name": "bidding_duration",
772
+ "type": "u64"
773
+ },
774
+ {
775
+ "name": "trading_duration",
776
+ "type": "u64"
777
+ }
778
+ ]
779
+ },
780
+ {
781
+ "name": "sell",
782
+ "discriminator": [
783
+ 51,
784
+ 230,
785
+ 133,
786
+ 164,
787
+ 1,
788
+ 127,
789
+ 131,
790
+ 173
791
+ ],
792
+ "accounts": [
793
+ {
794
+ "name": "trench",
795
+ "writable": true
796
+ },
797
+ {
798
+ "name": "global_state",
799
+ "writable": true
800
+ },
801
+ {
802
+ "name": "fee_recipient",
803
+ "writable": true
804
+ },
805
+ {
806
+ "name": "user",
807
+ "writable": true,
808
+ "signer": true
809
+ },
810
+ {
811
+ "name": "trench_token_vault",
812
+ "docs": [
813
+ "Vault holding trench's tokens (ATA owned by trench)"
814
+ ],
815
+ "writable": true,
816
+ "pda": {
817
+ "seeds": [
818
+ {
819
+ "kind": "account",
820
+ "path": "trench"
821
+ },
822
+ {
823
+ "kind": "const",
824
+ "value": [
825
+ 6,
826
+ 221,
827
+ 246,
828
+ 225,
829
+ 215,
830
+ 101,
831
+ 161,
832
+ 147,
833
+ 217,
834
+ 203,
835
+ 225,
836
+ 70,
837
+ 206,
838
+ 235,
839
+ 121,
840
+ 172,
841
+ 28,
842
+ 180,
843
+ 133,
844
+ 237,
845
+ 95,
846
+ 91,
847
+ 55,
848
+ 145,
849
+ 58,
850
+ 140,
851
+ 245,
852
+ 133,
853
+ 126,
854
+ 255,
855
+ 0,
856
+ 169
857
+ ]
858
+ },
859
+ {
860
+ "kind": "account",
861
+ "path": "trench.token_mint",
862
+ "account": "Trench"
863
+ }
864
+ ],
865
+ "program": {
866
+ "kind": "const",
867
+ "value": [
868
+ 140,
869
+ 151,
870
+ 37,
871
+ 143,
872
+ 78,
873
+ 36,
874
+ 137,
875
+ 241,
876
+ 187,
877
+ 61,
878
+ 16,
879
+ 41,
880
+ 20,
881
+ 142,
882
+ 13,
883
+ 131,
884
+ 11,
885
+ 90,
886
+ 19,
887
+ 153,
888
+ 218,
889
+ 255,
890
+ 16,
891
+ 132,
892
+ 4,
893
+ 142,
894
+ 123,
895
+ 216,
896
+ 219,
897
+ 233,
898
+ 248,
899
+ 89
900
+ ]
901
+ }
902
+ }
903
+ },
904
+ {
905
+ "name": "user_token_account",
906
+ "docs": [
907
+ "User's token account (must match trench's token mint)"
908
+ ],
909
+ "writable": true
910
+ },
911
+ {
912
+ "name": "token_program",
913
+ "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
914
+ }
915
+ ],
916
+ "args": [
917
+ {
918
+ "name": "amount_in",
919
+ "type": "u64"
920
+ },
921
+ {
922
+ "name": "min_sol_output",
923
+ "type": "u64"
924
+ },
925
+ {
926
+ "name": "think_id",
927
+ "type": "u64"
928
+ }
929
+ ]
930
+ },
931
+ {
932
+ "name": "update_config",
933
+ "discriminator": [
934
+ 29,
935
+ 158,
936
+ 252,
937
+ 191,
938
+ 10,
939
+ 83,
940
+ 219,
941
+ 99
942
+ ],
943
+ "accounts": [
944
+ {
945
+ "name": "global_state",
946
+ "writable": true,
947
+ "pda": {
948
+ "seeds": [
949
+ {
950
+ "kind": "const",
951
+ "value": [
952
+ 103,
953
+ 108,
954
+ 111,
955
+ 98,
956
+ 97,
957
+ 108
958
+ ]
959
+ }
960
+ ]
961
+ }
962
+ },
963
+ {
964
+ "name": "admin",
965
+ "writable": true,
966
+ "signer": true
967
+ }
968
+ ],
969
+ "args": [
970
+ {
971
+ "name": "bidding_duration",
972
+ "type": "u64"
973
+ },
974
+ {
975
+ "name": "trading_duration",
976
+ "type": "u64"
977
+ },
978
+ {
979
+ "name": "fee_recipient",
980
+ "type": "pubkey"
981
+ }
982
+ ]
983
+ },
984
+ {
985
+ "name": "withdraw",
986
+ "discriminator": [
987
+ 183,
988
+ 18,
989
+ 70,
990
+ 156,
991
+ 148,
992
+ 109,
993
+ 161,
994
+ 34
995
+ ],
996
+ "accounts": [
997
+ {
998
+ "name": "trench",
999
+ "writable": true
1000
+ },
1001
+ {
1002
+ "name": "agent",
1003
+ "writable": true,
1004
+ "pda": {
1005
+ "seeds": [
1006
+ {
1007
+ "kind": "const",
1008
+ "value": [
1009
+ 97,
1010
+ 103,
1011
+ 101,
1012
+ 110,
1013
+ 116
1014
+ ]
1015
+ },
1016
+ {
1017
+ "kind": "account",
1018
+ "path": "trench"
1019
+ },
1020
+ {
1021
+ "kind": "account",
1022
+ "path": "user"
1023
+ }
1024
+ ]
1025
+ }
1026
+ },
1027
+ {
1028
+ "name": "user",
1029
+ "writable": true,
1030
+ "signer": true
1031
+ },
1032
+ {
1033
+ "name": "system_program",
1034
+ "address": "11111111111111111111111111111111"
1035
+ }
1036
+ ],
1037
+ "args": [
1038
+ {
1039
+ "name": "amount",
1040
+ "type": "u64"
1041
+ },
1042
+ {
1043
+ "name": "think_id",
1044
+ "type": "u64"
1045
+ }
1046
+ ]
1047
+ }
1048
+ ],
1049
+ "accounts": [
1050
+ {
1051
+ "name": "Agent",
1052
+ "discriminator": [
1053
+ 47,
1054
+ 166,
1055
+ 112,
1056
+ 147,
1057
+ 155,
1058
+ 197,
1059
+ 86,
1060
+ 7
1061
+ ]
1062
+ },
1063
+ {
1064
+ "name": "GlobalState",
1065
+ "discriminator": [
1066
+ 163,
1067
+ 46,
1068
+ 74,
1069
+ 168,
1070
+ 216,
1071
+ 123,
1072
+ 133,
1073
+ 98
1074
+ ]
1075
+ },
1076
+ {
1077
+ "name": "Trench",
1078
+ "discriminator": [
1079
+ 70,
1080
+ 8,
1081
+ 211,
1082
+ 194,
1083
+ 255,
1084
+ 64,
1085
+ 8,
1086
+ 102
1087
+ ]
1088
+ }
1089
+ ],
1090
+ "events": [
1091
+ {
1092
+ "name": "BuyEvent",
1093
+ "discriminator": [
1094
+ 103,
1095
+ 244,
1096
+ 82,
1097
+ 31,
1098
+ 44,
1099
+ 245,
1100
+ 119,
1101
+ 119
1102
+ ]
1103
+ },
1104
+ {
1105
+ "name": "ClaimTokensEvent",
1106
+ "discriminator": [
1107
+ 71,
1108
+ 156,
1109
+ 103,
1110
+ 32,
1111
+ 16,
1112
+ 211,
1113
+ 150,
1114
+ 191
1115
+ ]
1116
+ },
1117
+ {
1118
+ "name": "ClosePoolEvent",
1119
+ "discriminator": [
1120
+ 242,
1121
+ 151,
1122
+ 109,
1123
+ 158,
1124
+ 250,
1125
+ 231,
1126
+ 235,
1127
+ 140
1128
+ ]
1129
+ },
1130
+ {
1131
+ "name": "CreateTrenchEvent",
1132
+ "discriminator": [
1133
+ 24,
1134
+ 172,
1135
+ 85,
1136
+ 31,
1137
+ 101,
1138
+ 75,
1139
+ 32,
1140
+ 122
1141
+ ]
1142
+ },
1143
+ {
1144
+ "name": "DepositEvent",
1145
+ "discriminator": [
1146
+ 120,
1147
+ 248,
1148
+ 61,
1149
+ 83,
1150
+ 31,
1151
+ 142,
1152
+ 107,
1153
+ 144
1154
+ ]
1155
+ },
1156
+ {
1157
+ "name": "DistributePrizeEvent",
1158
+ "discriminator": [
1159
+ 10,
1160
+ 83,
1161
+ 171,
1162
+ 140,
1163
+ 12,
1164
+ 201,
1165
+ 34,
1166
+ 128
1167
+ ]
1168
+ },
1169
+ {
1170
+ "name": "FinalizeEvent",
1171
+ "discriminator": [
1172
+ 115,
1173
+ 140,
1174
+ 131,
1175
+ 4,
1176
+ 181,
1177
+ 52,
1178
+ 170,
1179
+ 148
1180
+ ]
1181
+ },
1182
+ {
1183
+ "name": "InitializeEvent",
1184
+ "discriminator": [
1185
+ 206,
1186
+ 175,
1187
+ 169,
1188
+ 208,
1189
+ 241,
1190
+ 210,
1191
+ 35,
1192
+ 221
1193
+ ]
1194
+ },
1195
+ {
1196
+ "name": "SellEvent",
1197
+ "discriminator": [
1198
+ 62,
1199
+ 47,
1200
+ 55,
1201
+ 10,
1202
+ 165,
1203
+ 3,
1204
+ 220,
1205
+ 42
1206
+ ]
1207
+ },
1208
+ {
1209
+ "name": "WithdrawEvent",
1210
+ "discriminator": [
1211
+ 22,
1212
+ 9,
1213
+ 133,
1214
+ 26,
1215
+ 160,
1216
+ 44,
1217
+ 71,
1218
+ 192
1219
+ ]
1220
+ }
1221
+ ],
1222
+ "errors": [
1223
+ {
1224
+ "code": 6000,
1225
+ "name": "NotBiddingPhase",
1226
+ "msg": "Trench is not in bidding phase"
1227
+ },
1228
+ {
1229
+ "code": 6001,
1230
+ "name": "NotTradingPhase",
1231
+ "msg": "Trench is not in trading phase"
1232
+ },
1233
+ {
1234
+ "code": 6002,
1235
+ "name": "InsufficientFunds",
1236
+ "msg": "Insufficient funds"
1237
+ },
1238
+ {
1239
+ "code": 6003,
1240
+ "name": "SlippageExceeded",
1241
+ "msg": "Slippage tolerance exceeded"
1242
+ },
1243
+ {
1244
+ "code": 6004,
1245
+ "name": "Overflow",
1246
+ "msg": "Calculation overflow"
1247
+ },
1248
+ {
1249
+ "code": 6005,
1250
+ "name": "InvalidAmount",
1251
+ "msg": "Invalid amount"
1252
+ },
1253
+ {
1254
+ "code": 6006,
1255
+ "name": "Unauthorized",
1256
+ "msg": "Unauthorized access"
1257
+ },
1258
+ {
1259
+ "code": 6007,
1260
+ "name": "MathOverflow",
1261
+ "msg": "Math operation overflow"
1262
+ },
1263
+ {
1264
+ "code": 6008,
1265
+ "name": "InvalidStatus",
1266
+ "msg": "Invalid status"
1267
+ },
1268
+ {
1269
+ "code": 6009,
1270
+ "name": "AlreadyClaimed",
1271
+ "msg": "Tokens already claimed"
1272
+ },
1273
+ {
1274
+ "code": 6010,
1275
+ "name": "TradingPhaseNotEnded",
1276
+ "msg": "Trading phase not ended"
1277
+ },
1278
+ {
1279
+ "code": 6011,
1280
+ "name": "NoLiquidity",
1281
+ "msg": "No liquidity available"
1282
+ },
1283
+ {
1284
+ "code": 6012,
1285
+ "name": "InvalidTrenchId",
1286
+ "msg": "Invalid trench id"
1287
+ }
1288
+ ],
1289
+ "types": [
1290
+ {
1291
+ "name": "Agent",
1292
+ "type": {
1293
+ "kind": "struct",
1294
+ "fields": [
1295
+ {
1296
+ "name": "authority",
1297
+ "type": "pubkey"
1298
+ },
1299
+ {
1300
+ "name": "trench",
1301
+ "type": "pubkey"
1302
+ },
1303
+ {
1304
+ "name": "deposited_sol",
1305
+ "type": "u64"
1306
+ },
1307
+ {
1308
+ "name": "token_balance",
1309
+ "type": "u64"
1310
+ },
1311
+ {
1312
+ "name": "is_claimed",
1313
+ "type": "bool"
1314
+ },
1315
+ {
1316
+ "name": "bump",
1317
+ "type": "u8"
1318
+ }
1319
+ ]
1320
+ }
1321
+ },
1322
+ {
1323
+ "name": "BuyEvent",
1324
+ "type": {
1325
+ "kind": "struct",
1326
+ "fields": [
1327
+ {
1328
+ "name": "trench",
1329
+ "type": "pubkey"
1330
+ },
1331
+ {
1332
+ "name": "user",
1333
+ "type": "pubkey"
1334
+ },
1335
+ {
1336
+ "name": "sol_amount",
1337
+ "type": "u64"
1338
+ },
1339
+ {
1340
+ "name": "token_amount",
1341
+ "type": "u64"
1342
+ },
1343
+ {
1344
+ "name": "trench_balance",
1345
+ "type": "u64"
1346
+ },
1347
+ {
1348
+ "name": "think_id",
1349
+ "type": "u64"
1350
+ },
1351
+ {
1352
+ "name": "timestamp",
1353
+ "type": "i64"
1354
+ },
1355
+ {
1356
+ "name": "pre_virtual_sol_reserves",
1357
+ "type": "u64"
1358
+ },
1359
+ {
1360
+ "name": "pre_virtual_token_reserves",
1361
+ "type": "u64"
1362
+ },
1363
+ {
1364
+ "name": "pre_real_sol_reserves",
1365
+ "type": "u64"
1366
+ },
1367
+ {
1368
+ "name": "pre_real_token_reserves",
1369
+ "type": "u64"
1370
+ }
1371
+ ]
1372
+ }
1373
+ },
1374
+ {
1375
+ "name": "ClaimTokensEvent",
1376
+ "type": {
1377
+ "kind": "struct",
1378
+ "fields": [
1379
+ {
1380
+ "name": "trench",
1381
+ "type": "pubkey"
1382
+ },
1383
+ {
1384
+ "name": "user",
1385
+ "type": "pubkey"
1386
+ },
1387
+ {
1388
+ "name": "amount",
1389
+ "type": "u64"
1390
+ },
1391
+ {
1392
+ "name": "timestamp",
1393
+ "type": "i64"
1394
+ }
1395
+ ]
1396
+ }
1397
+ },
1398
+ {
1399
+ "name": "ClosePoolEvent",
1400
+ "type": {
1401
+ "kind": "struct",
1402
+ "fields": [
1403
+ {
1404
+ "name": "trench",
1405
+ "type": "pubkey"
1406
+ },
1407
+ {
1408
+ "name": "sol_removed",
1409
+ "type": "u64"
1410
+ },
1411
+ {
1412
+ "name": "timestamp",
1413
+ "type": "i64"
1414
+ }
1415
+ ]
1416
+ }
1417
+ },
1418
+ {
1419
+ "name": "CreateTrenchEvent",
1420
+ "type": {
1421
+ "kind": "struct",
1422
+ "fields": [
1423
+ {
1424
+ "name": "trench",
1425
+ "type": "pubkey"
1426
+ },
1427
+ {
1428
+ "name": "creator",
1429
+ "type": "pubkey"
1430
+ },
1431
+ {
1432
+ "name": "id",
1433
+ "type": "u64"
1434
+ },
1435
+ {
1436
+ "name": "timestamp",
1437
+ "type": "i64"
1438
+ }
1439
+ ]
1440
+ }
1441
+ },
1442
+ {
1443
+ "name": "DepositEvent",
1444
+ "type": {
1445
+ "kind": "struct",
1446
+ "fields": [
1447
+ {
1448
+ "name": "trench",
1449
+ "type": "pubkey"
1450
+ },
1451
+ {
1452
+ "name": "user",
1453
+ "type": "pubkey"
1454
+ },
1455
+ {
1456
+ "name": "amount",
1457
+ "type": "u64"
1458
+ },
1459
+ {
1460
+ "name": "user_deposited",
1461
+ "type": "u64"
1462
+ },
1463
+ {
1464
+ "name": "total_deposited",
1465
+ "type": "u64"
1466
+ },
1467
+ {
1468
+ "name": "trench_balance",
1469
+ "type": "u64"
1470
+ },
1471
+ {
1472
+ "name": "timestamp",
1473
+ "type": "i64"
1474
+ },
1475
+ {
1476
+ "name": "think_id",
1477
+ "type": "u64"
1478
+ }
1479
+ ]
1480
+ }
1481
+ },
1482
+ {
1483
+ "name": "DistributePrizeEvent",
1484
+ "type": {
1485
+ "kind": "struct",
1486
+ "fields": [
1487
+ {
1488
+ "name": "trench",
1489
+ "type": "pubkey"
1490
+ },
1491
+ {
1492
+ "name": "winners",
1493
+ "type": {
1494
+ "vec": "pubkey"
1495
+ }
1496
+ },
1497
+ {
1498
+ "name": "amounts",
1499
+ "type": {
1500
+ "vec": "u64"
1501
+ }
1502
+ },
1503
+ {
1504
+ "name": "total_winners",
1505
+ "type": "u64"
1506
+ },
1507
+ {
1508
+ "name": "timestamp",
1509
+ "type": "i64"
1510
+ }
1511
+ ]
1512
+ }
1513
+ },
1514
+ {
1515
+ "name": "FinalizeEvent",
1516
+ "type": {
1517
+ "kind": "struct",
1518
+ "fields": [
1519
+ {
1520
+ "name": "trench",
1521
+ "type": "pubkey"
1522
+ },
1523
+ {
1524
+ "name": "sol_for_lp",
1525
+ "type": "u64"
1526
+ },
1527
+ {
1528
+ "name": "tokens_for_lp",
1529
+ "type": "u64"
1530
+ },
1531
+ {
1532
+ "name": "timestamp",
1533
+ "type": "i64"
1534
+ }
1535
+ ]
1536
+ }
1537
+ },
1538
+ {
1539
+ "name": "GlobalState",
1540
+ "type": {
1541
+ "kind": "struct",
1542
+ "fields": [
1543
+ {
1544
+ "name": "admin",
1545
+ "type": "pubkey"
1546
+ },
1547
+ {
1548
+ "name": "fee_recipient",
1549
+ "type": "pubkey"
1550
+ },
1551
+ {
1552
+ "name": "total_trenches",
1553
+ "type": "u64"
1554
+ },
1555
+ {
1556
+ "name": "bidding_duration",
1557
+ "type": "u64"
1558
+ },
1559
+ {
1560
+ "name": "trading_duration",
1561
+ "type": "u64"
1562
+ }
1563
+ ]
1564
+ }
1565
+ },
1566
+ {
1567
+ "name": "InitializeEvent",
1568
+ "type": {
1569
+ "kind": "struct",
1570
+ "fields": [
1571
+ {
1572
+ "name": "admin",
1573
+ "type": "pubkey"
1574
+ },
1575
+ {
1576
+ "name": "timestamp",
1577
+ "type": "i64"
1578
+ }
1579
+ ]
1580
+ }
1581
+ },
1582
+ {
1583
+ "name": "SellEvent",
1584
+ "type": {
1585
+ "kind": "struct",
1586
+ "fields": [
1587
+ {
1588
+ "name": "trench",
1589
+ "type": "pubkey"
1590
+ },
1591
+ {
1592
+ "name": "user",
1593
+ "type": "pubkey"
1594
+ },
1595
+ {
1596
+ "name": "sol_amount",
1597
+ "type": "u64"
1598
+ },
1599
+ {
1600
+ "name": "token_amount",
1601
+ "type": "u64"
1602
+ },
1603
+ {
1604
+ "name": "trench_balance",
1605
+ "type": "u64"
1606
+ },
1607
+ {
1608
+ "name": "think_id",
1609
+ "type": "u64"
1610
+ },
1611
+ {
1612
+ "name": "timestamp",
1613
+ "type": "i64"
1614
+ },
1615
+ {
1616
+ "name": "pre_virtual_sol_reserves",
1617
+ "type": "u64"
1618
+ },
1619
+ {
1620
+ "name": "pre_virtual_token_reserves",
1621
+ "type": "u64"
1622
+ },
1623
+ {
1624
+ "name": "pre_real_sol_reserves",
1625
+ "type": "u64"
1626
+ },
1627
+ {
1628
+ "name": "pre_real_token_reserves",
1629
+ "type": "u64"
1630
+ }
1631
+ ]
1632
+ }
1633
+ },
1634
+ {
1635
+ "name": "Trench",
1636
+ "type": {
1637
+ "kind": "struct",
1638
+ "fields": [
1639
+ {
1640
+ "name": "id",
1641
+ "type": "u64"
1642
+ },
1643
+ {
1644
+ "name": "creator",
1645
+ "type": "pubkey"
1646
+ },
1647
+ {
1648
+ "name": "authority",
1649
+ "type": "pubkey"
1650
+ },
1651
+ {
1652
+ "name": "status",
1653
+ "type": {
1654
+ "defined": {
1655
+ "name": "TrenchStatus"
1656
+ }
1657
+ }
1658
+ },
1659
+ {
1660
+ "name": "total_deposited_sol",
1661
+ "type": "u64"
1662
+ },
1663
+ {
1664
+ "name": "virtual_sol_reserves",
1665
+ "type": "u128"
1666
+ },
1667
+ {
1668
+ "name": "virtual_token_reserves",
1669
+ "type": "u128"
1670
+ },
1671
+ {
1672
+ "name": "real_sol_reserves",
1673
+ "type": "u128"
1674
+ },
1675
+ {
1676
+ "name": "real_token_reserves",
1677
+ "type": "u128"
1678
+ },
1679
+ {
1680
+ "name": "initial_virtual_token_reserves",
1681
+ "type": "u128"
1682
+ },
1683
+ {
1684
+ "name": "bidding_start_block",
1685
+ "type": "u64"
1686
+ },
1687
+ {
1688
+ "name": "bidding_end_block",
1689
+ "type": "u64"
1690
+ },
1691
+ {
1692
+ "name": "trading_end_block",
1693
+ "type": "u64"
1694
+ },
1695
+ {
1696
+ "name": "token_mint",
1697
+ "type": "pubkey"
1698
+ },
1699
+ {
1700
+ "name": "start_time",
1701
+ "type": "i64"
1702
+ },
1703
+ {
1704
+ "name": "prize_pool_reserves",
1705
+ "type": "u64"
1706
+ },
1707
+ {
1708
+ "name": "bump",
1709
+ "type": "u8"
1710
+ }
1711
+ ]
1712
+ }
1713
+ },
1714
+ {
1715
+ "name": "TrenchStatus",
1716
+ "type": {
1717
+ "kind": "enum",
1718
+ "variants": [
1719
+ {
1720
+ "name": "Bidding"
1721
+ },
1722
+ {
1723
+ "name": "Trading"
1724
+ },
1725
+ {
1726
+ "name": "Ended"
1727
+ }
1728
+ ]
1729
+ }
1730
+ },
1731
+ {
1732
+ "name": "WithdrawEvent",
1733
+ "type": {
1734
+ "kind": "struct",
1735
+ "fields": [
1736
+ {
1737
+ "name": "trench",
1738
+ "type": "pubkey"
1739
+ },
1740
+ {
1741
+ "name": "user",
1742
+ "type": "pubkey"
1743
+ },
1744
+ {
1745
+ "name": "amount",
1746
+ "type": "u64"
1747
+ },
1748
+ {
1749
+ "name": "user_deposited",
1750
+ "type": "u64"
1751
+ },
1752
+ {
1753
+ "name": "total_deposited",
1754
+ "type": "u64"
1755
+ },
1756
+ {
1757
+ "name": "trench_balance",
1758
+ "type": "u64"
1759
+ },
1760
+ {
1761
+ "name": "timestamp",
1762
+ "type": "i64"
1763
+ },
1764
+ {
1765
+ "name": "think_id",
1766
+ "type": "u64"
1767
+ }
1768
+ ]
1769
+ }
1770
+ }
1771
+ ]
1772
+ };
1773
+ /** tokens out for `solAmount` lamports in (ceil division — favors the pool). */
1774
+ export function getBuyPrice(amm, solAmount) {
1775
+ if (amm.virtualSolReserves === 0n || amm.virtualTokenReserves === 0n)
1776
+ return null;
1777
+ const k = amm.virtualSolReserves * amm.virtualTokenReserves;
1778
+ const newVSol = amm.virtualSolReserves + solAmount;
1779
+ if (newVSol === 0n)
1780
+ return null;
1781
+ const quotient = k / newVSol;
1782
+ const remainder = k % newVSol;
1783
+ const newVToken = remainder > 0n ? quotient + 1n : quotient;
1784
+ const tokensOut = amm.virtualTokenReserves - newVToken;
1785
+ if (tokensOut <= 0n)
1786
+ return null;
1787
+ return tokensOut;
1788
+ }
1789
+ export function applyBuy(amm, solAmount) {
1790
+ const tokenAmount = getBuyPrice(amm, solAmount);
1791
+ if (tokenAmount === null)
1792
+ return null;
1793
+ if (amm.realTokenReserves - tokenAmount < 0n)
1794
+ return null;
1795
+ return {
1796
+ result: { tokenAmount, solAmount },
1797
+ reserves: {
1798
+ virtualSolReserves: amm.virtualSolReserves + solAmount,
1799
+ virtualTokenReserves: amm.virtualTokenReserves - tokenAmount,
1800
+ realSolReserves: amm.realSolReserves + solAmount,
1801
+ realTokenReserves: amm.realTokenReserves - tokenAmount,
1802
+ initialVirtualTokenReserves: amm.initialVirtualTokenReserves,
1803
+ },
1804
+ };
1805
+ }
1806
+ /** SOL out for `tokens` in (floor division, capped by real SOL). */
1807
+ export function getSellPrice(amm, tokens) {
1808
+ if (tokens === 0n || amm.realSolReserves === 0n)
1809
+ return null;
1810
+ const k = amm.virtualSolReserves * amm.virtualTokenReserves;
1811
+ const newVToken = amm.virtualTokenReserves + tokens;
1812
+ if (newVToken === 0n)
1813
+ return null;
1814
+ const newVSol = k / newVToken;
1815
+ const solReceived = amm.virtualSolReserves - newVSol;
1816
+ if (solReceived < 0n)
1817
+ return null;
1818
+ const capped = solReceived < amm.realSolReserves ? solReceived : amm.realSolReserves;
1819
+ if (capped === 0n)
1820
+ return null;
1821
+ return capped;
1822
+ }
1823
+ export function applySell(amm, tokenAmount) {
1824
+ if (tokenAmount === 0n || amm.realSolReserves === 0n)
1825
+ return null;
1826
+ const k = amm.virtualSolReserves * amm.virtualTokenReserves;
1827
+ const newVToken = amm.virtualTokenReserves + tokenAmount;
1828
+ const newVSol = k / newVToken;
1829
+ const uncappedSol = amm.virtualSolReserves - newVSol;
1830
+ if (uncappedSol < 0n)
1831
+ return null;
1832
+ const solAmount = uncappedSol < amm.realSolReserves ? uncappedSol : amm.realSolReserves;
1833
+ if (solAmount === 0n)
1834
+ return null;
1835
+ return {
1836
+ result: { tokenAmount, solAmount },
1837
+ reserves: {
1838
+ virtualSolReserves: newVSol,
1839
+ virtualTokenReserves: newVToken,
1840
+ realSolReserves: amm.realSolReserves - solAmount,
1841
+ realTokenReserves: amm.realTokenReserves + tokenAmount,
1842
+ initialVirtualTokenReserves: amm.initialVirtualTokenReserves,
1843
+ },
1844
+ };
1845
+ }
1846
+ // ======================== src/quote.ts ========================
1847
+ /**
1848
+ * Quote / preview engine (pure). Mirrors on-chain fee handling:
1849
+ * buy (buy.rs): fee = solPayWithFee * 1%; AMM applied to (solPayWithFee - fee).
1850
+ * sell (sell.rs): solOut = curve output; fee = solOut * 1%; user gets (solOut - fee).
1851
+ */
1852
+ export const FEE_RATE_BPS = 100n; // 1%
1853
+ export const BASIS_POINTS = 10000n;
1854
+ const feeOf = (amount) => (amount * FEE_RATE_BPS) / BASIS_POINTS;
1855
+ export function previewBuy(reserves, solPayWithFee) {
1856
+ if (solPayWithFee <= 0n)
1857
+ return null;
1858
+ const fee = feeOf(solPayWithFee);
1859
+ const solIntoCurve = solPayWithFee - fee;
1860
+ const applied = applyBuy(reserves, solIntoCurve);
1861
+ if (!applied)
1862
+ return null;
1863
+ return { solPayWithFee, fee, solIntoCurve, tokensOut: applied.result.tokenAmount, reservesAfter: applied.reserves };
1864
+ }
1865
+ export function previewSell(reserves, tokensIn) {
1866
+ if (tokensIn <= 0n)
1867
+ return null;
1868
+ const applied = applySell(reserves, tokensIn);
1869
+ if (!applied)
1870
+ return null;
1871
+ const solOutGross = applied.result.solAmount;
1872
+ const fee = feeOf(solOutGross);
1873
+ return { tokensIn, solOutGross, fee, netSolToUser: solOutGross - fee, reservesAfter: applied.reserves };
1874
+ }
1875
+ // ======================== src/decode.ts ========================
1876
+ /**
1877
+ * Dependency-free decoders for eva account bytes (works for L1 OR ER reads).
1878
+ * Layouts from eva-contract/programs/program/src/state.rs (Anchor = 8-byte
1879
+ * discriminator + Borsh fields). SPL token amount @ offset 64.
1880
+ */
1881
+ // ---- Trench (state.rs struct Trench) ----
1882
+ export const TRENCH_OFFSETS = {
1883
+ id: 8, creator: 16, authority: 48, status: 80, totalDepositedSol: 81,
1884
+ virtualSolReserves: 89, virtualTokenReserves: 105, realSolReserves: 121,
1885
+ realTokenReserves: 137, initialVirtualTokenReserves: 153,
1886
+ biddingStartBlock: 169, biddingEndBlock: 177, tradingEndBlock: 185,
1887
+ tokenMint: 193, startTime: 225, prizePoolReserves: 233, bump: 241,
1888
+ };
1889
+ export const TRENCH_LEN = 242;
1890
+ function uLE(data, off, len) {
1891
+ let v = 0n;
1892
+ for (let i = 0; i < len; i++)
1893
+ v |= BigInt(data[off + i]) << (8n * BigInt(i));
1894
+ return v;
1895
+ }
1896
+ function iLE(data, off, len) {
1897
+ const u = uLE(data, off, len);
1898
+ const bits = BigInt(len) * 8n;
1899
+ return u >= 1n << (bits - 1n) ? u - (1n << bits) : u;
1900
+ }
1901
+ const STATUS = ["Bidding", "Trading", "Ended"];
1902
+ export function decodeTrenchReserves(data) {
1903
+ if (data.length < TRENCH_LEN)
1904
+ throw new Error(`Trench data too short: ${data.length} < ${TRENCH_LEN}`);
1905
+ return {
1906
+ virtualSolReserves: uLE(data, TRENCH_OFFSETS.virtualSolReserves, 16),
1907
+ virtualTokenReserves: uLE(data, TRENCH_OFFSETS.virtualTokenReserves, 16),
1908
+ realSolReserves: uLE(data, TRENCH_OFFSETS.realSolReserves, 16),
1909
+ realTokenReserves: uLE(data, TRENCH_OFFSETS.realTokenReserves, 16),
1910
+ initialVirtualTokenReserves: uLE(data, TRENCH_OFFSETS.initialVirtualTokenReserves, 16),
1911
+ };
1912
+ }
1913
+ export function decodeTrench(data) {
1914
+ if (data.length < TRENCH_LEN)
1915
+ throw new Error(`Trench data too short: ${data.length} < ${TRENCH_LEN}`);
1916
+ return {
1917
+ id: uLE(data, TRENCH_OFFSETS.id, 8),
1918
+ status: STATUS[data[TRENCH_OFFSETS.status]] ?? "Unknown",
1919
+ totalDepositedSol: uLE(data, TRENCH_OFFSETS.totalDepositedSol, 8),
1920
+ reserves: decodeTrenchReserves(data),
1921
+ biddingStartBlock: uLE(data, TRENCH_OFFSETS.biddingStartBlock, 8),
1922
+ biddingEndBlock: uLE(data, TRENCH_OFFSETS.biddingEndBlock, 8),
1923
+ tradingEndBlock: uLE(data, TRENCH_OFFSETS.tradingEndBlock, 8),
1924
+ tokenMint: data.slice(TRENCH_OFFSETS.tokenMint, TRENCH_OFFSETS.tokenMint + 32),
1925
+ startTime: iLE(data, TRENCH_OFFSETS.startTime, 8),
1926
+ prizePoolReserves: uLE(data, TRENCH_OFFSETS.prizePoolReserves, 8),
1927
+ bump: data[TRENCH_OFFSETS.bump],
1928
+ };
1929
+ }
1930
+ export function decodeGlobalState(data) {
1931
+ if (data.length < 88)
1932
+ throw new Error(`GlobalState data too short: ${data.length} < 88`);
1933
+ return {
1934
+ admin: data.slice(8, 40),
1935
+ feeRecipient: data.slice(40, 72),
1936
+ totalTrenches: uLE(data, 72, 8),
1937
+ biddingDuration: uLE(data, 80, 8),
1938
+ tradingDuration: data.length >= 96 ? uLE(data, 88, 8) : 0n,
1939
+ };
1940
+ }
1941
+ // ---- SPL token account amount (u64 @ 64) ----
1942
+ export function decodeTokenAmount(data) {
1943
+ if (data.length < 72)
1944
+ throw new Error(`token account data too short: ${data.length} < 72`);
1945
+ return uLE(data, 64, 8);
1946
+ }
1947
+ // ======================== src/config.ts ========================
1948
+ /**
1949
+ * Network presets + resolved config. Works for localnet now and devnet later —
1950
+ * the only difference is the endpoints + (possibly) program ids you pass in.
1951
+ *
1952
+ * IMPORTANT (devnet): public Solana devnet has NO NorthStar ER/Portal. "devnet"
1953
+ * here means a NorthStar validator running in a devnet-style deployment — you MUST
1954
+ * point l1Rpc/erRpc at THAT node's endpoints. There is no hosted default yet.
1955
+ */
1956
+ export const DEFAULT_PORTAL_PROGRAM_ID = "5TeWSsjg2gbxCyWVniXeCmwM7UtHTCK7svzJr5xYJzHf";
1957
+ export const DEFAULT_EVA_PROGRAM_ID = "CQru6EauVg2UwepFCvY5qWuqCPEWYC4ta43wBbkFYtmo";
1958
+ export const INITIAL_TOKEN_SUPPLY = 1000000000n * 1000000n; // 1B @ 6 decimals
1959
+ export const TOKEN_DECIMALS = 6;
1960
+ export const NETWORKS = {
1961
+ localnet: {
1962
+ l1Rpc: "http://127.0.0.1:8899",
1963
+ erRpc: "http://127.0.0.1:8910",
1964
+ erWs: "ws://127.0.0.1:8911",
1965
+ portalProgramId: DEFAULT_PORTAL_PROGRAM_ID,
1966
+ evaProgramId: DEFAULT_EVA_PROGRAM_ID,
1967
+ },
1968
+ devnet: {
1969
+ // No public NorthStar devnet endpoint exists yet — override l1Rpc/erRpc with
1970
+ // your NorthStar devnet node's URLs. These sentinels fail fast if you forget.
1971
+ l1Rpc: "",
1972
+ erRpc: "",
1973
+ erWs: "",
1974
+ portalProgramId: DEFAULT_PORTAL_PROGRAM_ID,
1975
+ evaProgramId: DEFAULT_EVA_PROGRAM_ID,
1976
+ },
1977
+ };
1978
+ const pk = (v) => (typeof v === "string" ? new PublicKey(v) : v);
1979
+ const bn = (v, d) => (v === undefined ? d : BigInt(v));
1980
+ export function resolveConfig(input) {
1981
+ const preset = NETWORKS[input.network ?? "localnet"];
1982
+ const l1Rpc = input.l1Rpc ?? preset.l1Rpc;
1983
+ const erRpc = input.erRpc ?? preset.erRpc;
1984
+ if (!l1Rpc || !erRpc) {
1985
+ throw new Error(`Missing RPC endpoints for network "${input.network}". For devnet, pass l1Rpc + erRpc ` +
1986
+ `pointing at your NorthStar node (public Solana devnet has no ER/Portal).`);
1987
+ }
1988
+ return {
1989
+ l1Rpc,
1990
+ erRpc,
1991
+ erWs: input.erWs ?? preset.erWs,
1992
+ portalProgramId: pk(input.portalProgramId ?? preset.portalProgramId),
1993
+ evaProgramId: pk(input.evaProgramId ?? preset.evaProgramId),
1994
+ gridId: bn(input.gridId, 1n),
1995
+ ttlSlots: bn(input.ttlSlots, 1000000n),
1996
+ feeCap: bn(input.feeCap, 1000000000n),
1997
+ settlementIntervalSlots: bn(input.settlementIntervalSlots, 50n),
1998
+ };
1999
+ }
2000
+ // ======================== src/portal.ts ========================
2001
+ /**
2002
+ * NorthStar Portal program client — CORRECTED encoders + account layouts that
2003
+ * match the deployed program (northstar/.../programs/portal). These differ from
2004
+ * the published @sonicsvm/northstar-sdk (see ../README + LIMITATIONS):
2005
+ * - OpenSession data includes `validator` + `settlement_interval_slots`.
2006
+ * - Delegate uses the multi-delegation layout: [payer, system_program, session,
2007
+ * (delegated_account, owner_program, delegation_record, buffer)…] — session @ index 2.
2008
+ * - Undelegate keeps the legacy order.
2009
+ */
2010
+ // Portal instruction enum tags (first byte of instruction data). WithdrawFee was
2011
+ // removed upstream; tail variants renumbered. We only use 0–4.
2012
+ const TAG = {
2013
+ OpenSession: 0, CloseSession: 1, DepositFee: 2, Delegate: 3, Undelegate: 4,
2014
+ };
2015
+ const SEED = {
2016
+ session: "session", feeVault: "fee_vault", delegation: "delegation",
2017
+ depositReceipt: "deposit_receipt", withdrawalSink: "withdrawal_sink",
2018
+ };
2019
+ class W {
2020
+ b = [];
2021
+ u8(v) { this.b.push(v & 0xff); return this; }
2022
+ u64(v) { let x = BigInt(v); for (let i = 0; i < 8; i++) {
2023
+ this.b.push(Number(x & 0xffn));
2024
+ x >>= 8n;
2025
+ } return this; }
2026
+ bytes32(x) { if (x.length !== 32)
2027
+ throw new Error(`expected 32 bytes, got ${x.length}`); for (const v of x)
2028
+ this.b.push(v); return this; }
2029
+ out() { return Uint8Array.from(this.b); }
2030
+ }
2031
+ export const encodeOpenSession = (a) => new W().u8(TAG.OpenSession).u64(a.gridId).u64(a.ttlSlots).u64(a.feeCap).bytes32(a.validator).u64(a.settlementIntervalSlots).out();
2032
+ export const encodeCloseSession = () => new W().u8(TAG.CloseSession).out();
2033
+ export const encodeDepositFee = (lamports) => new W().u8(TAG.DepositFee).u64(lamports).out();
2034
+ export const encodeDelegate = (gridId) => new W().u8(TAG.Delegate).u64(gridId).out();
2035
+ export const encodeUndelegate = () => new W().u8(TAG.Undelegate).out();
2036
+ // ---- PDAs ----
2037
+ export const sessionPda = (programId) => PublicKey.findProgramAddressSync([Buffer.from(SEED.session)], programId)[0];
2038
+ export const feeVaultPda = (programId) => PublicKey.findProgramAddressSync([Buffer.from(SEED.feeVault)], programId)[0];
2039
+ export const delegationRecordPda = (programId, delegated) => PublicKey.findProgramAddressSync([Buffer.from(SEED.delegation), delegated.toBuffer()], programId)[0];
2040
+ export const depositReceiptPda = (programId, session, recipient) => PublicKey.findProgramAddressSync([Buffer.from(SEED.depositReceipt), session.toBuffer(), recipient.toBuffer()], programId)[0];
2041
+ export const withdrawalSinkPda = (programId, session, recipient) => PublicKey.findProgramAddressSync([Buffer.from(SEED.withdrawalSink), session.toBuffer(), recipient.toBuffer()], programId)[0];
2042
+ const SYS = SystemProgram.programId;
2043
+ // ---- instruction builders ----
2044
+ export function openSessionIx(p) {
2045
+ return new TransactionInstruction({
2046
+ programId: p.programId,
2047
+ keys: [
2048
+ { pubkey: p.payer, isSigner: true, isWritable: true },
2049
+ { pubkey: sessionPda(p.programId), isSigner: false, isWritable: true },
2050
+ { pubkey: feeVaultPda(p.programId), isSigner: false, isWritable: true },
2051
+ { pubkey: SYS, isSigner: false, isWritable: false },
2052
+ ],
2053
+ data: Buffer.from(encodeOpenSession({ gridId: p.gridId, ttlSlots: p.ttlSlots, feeCap: p.feeCap, validator: p.validator.toBytes(), settlementIntervalSlots: p.settlementIntervalSlots })),
2054
+ });
2055
+ }
2056
+ export function closeSessionIx(p) {
2057
+ return new TransactionInstruction({
2058
+ programId: p.programId,
2059
+ keys: [
2060
+ { pubkey: p.closer, isSigner: true, isWritable: true },
2061
+ { pubkey: sessionPda(p.programId), isSigner: false, isWritable: true },
2062
+ { pubkey: feeVaultPda(p.programId), isSigner: false, isWritable: true },
2063
+ { pubkey: SYS, isSigner: false, isWritable: false },
2064
+ ],
2065
+ data: Buffer.from(encodeCloseSession()),
2066
+ });
2067
+ }
2068
+ export function depositFeeIx(p) {
2069
+ const session = sessionPda(p.programId);
2070
+ return new TransactionInstruction({
2071
+ programId: p.programId,
2072
+ keys: [
2073
+ { pubkey: p.depositor, isSigner: true, isWritable: true },
2074
+ { pubkey: session, isSigner: false, isWritable: false },
2075
+ { pubkey: depositReceiptPda(p.programId, session, p.recipient), isSigner: false, isWritable: true },
2076
+ { pubkey: p.recipient, isSigner: false, isWritable: false },
2077
+ { pubkey: SYS, isSigner: false, isWritable: false },
2078
+ ],
2079
+ data: Buffer.from(encodeDepositFee(p.lamports)),
2080
+ });
2081
+ }
2082
+ /** Multi-delegation layout: prefix [payer, system_program, session] + one group. */
2083
+ export function delegateIx(p) {
2084
+ return new TransactionInstruction({
2085
+ programId: p.programId,
2086
+ keys: [
2087
+ { pubkey: p.payer, isSigner: true, isWritable: true },
2088
+ { pubkey: SYS, isSigner: false, isWritable: false },
2089
+ { pubkey: sessionPda(p.programId), isSigner: false, isWritable: false },
2090
+ { pubkey: p.delegatedAccount, isSigner: true, isWritable: true },
2091
+ { pubkey: p.ownerProgram, isSigner: false, isWritable: false },
2092
+ { pubkey: delegationRecordPda(p.programId, p.delegatedAccount), isSigner: false, isWritable: true },
2093
+ { pubkey: p.buffer, isSigner: false, isWritable: false },
2094
+ ],
2095
+ data: Buffer.from(encodeDelegate(p.gridId)),
2096
+ });
2097
+ }
2098
+ /** Legacy order (undelegate was not refactored). */
2099
+ export function undelegateIx(p) {
2100
+ return new TransactionInstruction({
2101
+ programId: p.programId,
2102
+ keys: [
2103
+ { pubkey: p.authority, isSigner: true, isWritable: true },
2104
+ { pubkey: p.delegatedAccount, isSigner: false, isWritable: true },
2105
+ { pubkey: p.ownerProgram, isSigner: false, isWritable: false },
2106
+ { pubkey: delegationRecordPda(p.programId, p.delegatedAccount), isSigner: false, isWritable: true },
2107
+ { pubkey: SYS, isSigner: false, isWritable: false },
2108
+ { pubkey: sessionPda(p.programId), isSigner: false, isWritable: false },
2109
+ ],
2110
+ data: Buffer.from(encodeUndelegate()),
2111
+ });
2112
+ }
2113
+ // namespace shim so client code can call portal.*
2114
+ const portal = { encodeOpenSession, encodeCloseSession, encodeDepositFee, encodeDelegate, encodeUndelegate, sessionPda, feeVaultPda, delegationRecordPda, depositReceiptPda, withdrawalSinkPda, openSessionIx, closeSessionIx, depositFeeIx, delegateIx, undelegateIx };
2115
+ // ======================== src/evaPdas.ts ========================
2116
+ /** eva-contract PDA + ATA derivations (mirrors eva-contract/sdk.ts + create_trench.rs). */
2117
+ const u64le = (n) => { const b = Buffer.alloc(8); b.writeBigUInt64LE(n); return b; };
2118
+ export const globalStatePda = (programId) => PublicKey.findProgramAddressSync([Buffer.from("global")], programId)[0];
2119
+ export const trenchPda = (programId, id) => PublicKey.findProgramAddressSync([Buffer.from("trench"), u64le(id)], programId)[0];
2120
+ export const agentPda = (programId, trench, user) => PublicKey.findProgramAddressSync([Buffer.from("agent"), trench.toBuffer(), user.toBuffer()], programId)[0];
2121
+ export const tokenMintPda = (programId, trench) => PublicKey.findProgramAddressSync([Buffer.from("mint"), trench.toBuffer()], programId)[0];
2122
+ export const trenchTokenVault = (mint, trench) => getAssociatedTokenAddressSync(mint, trench, true);
2123
+ export const userTokenAccount = (mint, user) => getAssociatedTokenAddressSync(mint, user);
2124
+ // namespace shim so client code can call evaPdas.*
2125
+ const evaPdas = { globalStatePda, trenchPda, agentPda, tokenMintPda, trenchTokenVault, userTokenAccount };
2126
+ // ======================== src/client.ts ========================
2127
+ /**
2128
+ * NorthstarEva — the team-facing SDK class.
2129
+ *
2130
+ * Encapsulates everything needed to run the eva program on a NorthStar ephemeral
2131
+ * rollup and cut fees: lane routing (control/custody → L1, hot-path eva → ER),
2132
+ * the corrected Portal encoders, dev-mode execution, `processed`-commitment reads
2133
+ * (so read-after-write is fresh), and transient-error retries.
2134
+ *
2135
+ * Works for localnet and devnet — only the endpoints/program-ids change (config).
2136
+ */
2137
+ // @coral-xyz/anchor is CommonJS — runtime values live on the default export.
2138
+ const A = anchor.default ?? anchor;
2139
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
2140
+ function loadBundledIdl() {
2141
+ return __EVA_IDL__;
2142
+ }
2143
+ export class NorthstarEva {
2144
+ cfg;
2145
+ l1;
2146
+ er;
2147
+ wallet;
2148
+ validatorIdentity;
2149
+ program; // eva, bound to the ER connection
2150
+ pollMs;
2151
+ constructor(opts) {
2152
+ this.cfg = resolveConfig(opts);
2153
+ this.wallet = opts.wallet;
2154
+ this.validatorIdentity = opts.validatorIdentity
2155
+ ? (typeof opts.validatorIdentity === "string" ? new PublicKey(opts.validatorIdentity) : opts.validatorIdentity)
2156
+ : opts.wallet.publicKey;
2157
+ this.pollMs = opts.pollIntervalMs ?? 500;
2158
+ this.l1 = new Connection(this.cfg.l1Rpc, "confirmed");
2159
+ // ER provider reads at "processed" so account resolution / reads are fresh.
2160
+ this.er = new Connection(this.cfg.erRpc, "processed");
2161
+ const idl = opts.evaIdl ?? (opts.evaIdlPath ? JSON.parse(readFileSync(opts.evaIdlPath, "utf8")) : loadBundledIdl());
2162
+ idl.address = this.cfg.evaProgramId.toBase58(); // honor config / devnet override
2163
+ const provider = new A.AnchorProvider(this.er, new A.Wallet(this.wallet), { commitment: "processed" });
2164
+ this.program = new A.Program(idl, provider);
2165
+ }
2166
+ static create(opts) { return new NorthstarEva(opts); }
2167
+ // ───────────────────────── ER transport (raw RPC, retries, processed) ─────────────────────────
2168
+ async erRpc(method, params = []) {
2169
+ let lastErr;
2170
+ for (let attempt = 0; attempt < 3; attempt++) {
2171
+ try {
2172
+ const res = await fetch(this.cfg.erRpc, {
2173
+ method: "POST", headers: { "content-type": "application/json" },
2174
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
2175
+ });
2176
+ const json = (await res.json());
2177
+ if (json.error)
2178
+ throw new Error(`${method}: ${JSON.stringify(json.error)}`);
2179
+ return json.result;
2180
+ }
2181
+ catch (e) {
2182
+ lastErr = e;
2183
+ const msg = String(e?.message ?? e);
2184
+ if (msg.startsWith(`${method}:`) || attempt === 2)
2185
+ throw e;
2186
+ await sleep(this.pollMs);
2187
+ }
2188
+ }
2189
+ throw lastErr;
2190
+ }
2191
+ /** Read an account from the ER at `processed` (fresh) — null on not-found. */
2192
+ async erGetAccount(address) {
2193
+ const r = await this.erRpc("getAccountInfo", [address.toBase58(), { encoding: "base64", commitment: "processed" }]);
2194
+ const v = r?.value;
2195
+ return v ? { data: Uint8Array.from(Buffer.from(v.data[0], "base64")), lamports: BigInt(v.lamports), owner: v.owner } : null;
2196
+ }
2197
+ async l1GetAccount(address) {
2198
+ const info = await this.l1.getAccountInfo(address, "confirmed");
2199
+ return info ? { data: new Uint8Array(info.data), lamports: BigInt(info.lamports), owner: info.owner.toBase58() } : null;
2200
+ }
2201
+ async erBalance(address) {
2202
+ const r = await this.erRpc("getBalance", [address.toBase58(), { commitment: "processed" }]);
2203
+ return BigInt(r.value);
2204
+ }
2205
+ // ───────────────────────── health / session reads ─────────────────────────
2206
+ async health() {
2207
+ let l1 = false, er = false;
2208
+ try {
2209
+ await this.l1.getSlot();
2210
+ l1 = true;
2211
+ }
2212
+ catch { /* */ }
2213
+ try {
2214
+ er = (await this.erRpc("getHealth")) === "ok";
2215
+ }
2216
+ catch { /* */ }
2217
+ return { l1, er };
2218
+ }
2219
+ syncStatus() { return this.erRpc("northstarSysGetSyncStatus"); }
2220
+ getSessionPdaFromEr() { return this.erRpc("getSessionPda"); }
2221
+ getDelegatedAccounts() { return this.erRpc("getDelegatedAccounts"); }
2222
+ sessionPda() { return portal.sessionPda(this.cfg.portalProgramId); }
2223
+ // ───────────────────────── L1 send + ER send ─────────────────────────
2224
+ async sendOnL1(instructions, signers) {
2225
+ const tx = new Transaction().add(...instructions);
2226
+ return sendAndConfirmTransaction(this.l1, tx, signers, { commitment: "confirmed", skipPreflight: false });
2227
+ }
2228
+ /** Send a tx to the ER and confirm by polling (the ER returns Ok on acceptance). */
2229
+ async sendOnEr(instructions, signers) {
2230
+ let signature = "", lastErr;
2231
+ for (let attempt = 0; attempt < 3; attempt++) {
2232
+ try {
2233
+ const { blockhash } = await this.er.getLatestBlockhash("processed");
2234
+ const tx = new Transaction({ feePayer: signers[0].publicKey, blockhash, lastValidBlockHeight: 0 });
2235
+ tx.add(...instructions);
2236
+ tx.sign(...signers);
2237
+ signature = await this.er.sendRawTransaction(tx.serialize(), { skipPreflight: false, preflightCommitment: "processed" });
2238
+ break;
2239
+ }
2240
+ catch (e) {
2241
+ lastErr = e;
2242
+ const msg = String(e?.message ?? e);
2243
+ if (!/fetch failed|socket|UND_ERR|ECONNRESET|other side closed|terminated|network/i.test(msg) || attempt === 2)
2244
+ throw e;
2245
+ await sleep(800);
2246
+ }
2247
+ }
2248
+ if (!signature)
2249
+ throw lastErr;
2250
+ let err = null, confirmed = false;
2251
+ for (let i = 0; i < 40; i++) {
2252
+ const r = await this.erRpc("getSignatureStatuses", [[signature], { searchTransactionHistory: true }]);
2253
+ const st = r?.value?.[0];
2254
+ if (st) {
2255
+ err = st.err ?? null;
2256
+ if (st.err || st.confirmationStatus) {
2257
+ confirmed = !st.err;
2258
+ break;
2259
+ }
2260
+ }
2261
+ await sleep(this.pollMs);
2262
+ }
2263
+ return { signature, err, confirmed };
2264
+ }
2265
+ async sendEva(ix, label) {
2266
+ const res = await this.sendOnEr([ix], [this.wallet]);
2267
+ if (res.err)
2268
+ throw new Error(`${label} failed on ER: ${JSON.stringify(res.err)}`);
2269
+ if (!res.confirmed) {
2270
+ throw new Error(`${label}: ER tx not confirmed within the poll budget (sig ${res.signature}). It may have been silently dropped — check validator logs.`);
2271
+ }
2272
+ return res.signature;
2273
+ }
2274
+ /** Fetch eva GlobalState from the ER or throw a clear "not initialized" error. */
2275
+ async requireGlobal() {
2276
+ const g = await this.getGlobal("er");
2277
+ if (!g)
2278
+ throw new Error("eva global state not initialized on the ER — call initialize() first");
2279
+ return g;
2280
+ }
2281
+ get methods() { return this.program.methods; }
2282
+ bn(v) { return new A.BN(v.toString()); }
2283
+ // ───────────────────────── Portal control (L1) ─────────────────────────
2284
+ async openSession() {
2285
+ const pda = this.sessionPda();
2286
+ if (await this.l1GetAccount(pda))
2287
+ return { signature: null, sessionPda: pda, alreadyOpen: true };
2288
+ const ix = portal.openSessionIx({
2289
+ programId: this.cfg.portalProgramId, payer: this.wallet.publicKey,
2290
+ gridId: this.cfg.gridId, ttlSlots: this.cfg.ttlSlots, feeCap: this.cfg.feeCap,
2291
+ validator: this.validatorIdentity, settlementIntervalSlots: this.cfg.settlementIntervalSlots,
2292
+ });
2293
+ const signature = await this.sendOnL1([ix], [this.wallet]);
2294
+ return { signature, sessionPda: pda, alreadyOpen: false };
2295
+ }
2296
+ async closeSession() {
2297
+ return this.sendOnL1([portal.closeSessionIx({ programId: this.cfg.portalProgramId, closer: this.wallet.publicKey })], [this.wallet]);
2298
+ }
2299
+ depositReceiptPda(recipient = this.wallet.publicKey) {
2300
+ return portal.depositReceiptPda(this.cfg.portalProgramId, this.sessionPda(), recipient);
2301
+ }
2302
+ /** DepositFee on L1 — funds an ER fee payer (its ER balance = these credits). */
2303
+ async fundErFeePayer(lamports, recipient = this.wallet.publicKey) {
2304
+ return this.sendOnL1([portal.depositFeeIx({ programId: this.cfg.portalProgramId, depositor: this.wallet.publicKey, recipient, lamports })], [this.wallet]);
2305
+ }
2306
+ /** Ensure the ER fee payer has >= `lamports`; tops up via DepositFee + waits for the credit. */
2307
+ async ensureErFunds(lamports, recipient = this.wallet.publicKey) {
2308
+ let bal = await this.erBalance(recipient).catch(() => 0n);
2309
+ if (bal >= lamports)
2310
+ return bal;
2311
+ await this.fundErFeePayer(lamports, recipient);
2312
+ for (let i = 0; i < 25; i++) {
2313
+ await sleep(800);
2314
+ bal = await this.erBalance(recipient).catch(() => 0n);
2315
+ if (bal >= lamports)
2316
+ break;
2317
+ }
2318
+ return bal;
2319
+ }
2320
+ /** Delegate a plain keypair account (System-owned) into the ER (the "proper" path). */
2321
+ async delegateKeypairAccount(target) {
2322
+ const buffer = Keypair.generate();
2323
+ const rent = await this.l1.getMinimumBalanceForRentExemption(0);
2324
+ const createBuffer = SystemProgram.createAccount({ fromPubkey: this.wallet.publicKey, newAccountPubkey: buffer.publicKey, lamports: rent, space: 0, programId: SystemProgram.programId });
2325
+ const ix = portal.delegateIx({ programId: this.cfg.portalProgramId, payer: this.wallet.publicKey, delegatedAccount: target.publicKey, ownerProgram: SystemProgram.programId, buffer: buffer.publicKey, gridId: this.cfg.gridId });
2326
+ return this.sendOnL1([createBuffer, ix], [this.wallet, target, buffer]);
2327
+ }
2328
+ /** Create a fresh Portal-owned account on L1 (delegation target helper). */
2329
+ async createPortalOwnedAccount(space = 0) {
2330
+ const acct = Keypair.generate();
2331
+ const rent = await this.l1.getMinimumBalanceForRentExemption(space);
2332
+ const ix = SystemProgram.createAccount({ fromPubkey: this.wallet.publicKey, newAccountPubkey: acct.publicKey, lamports: rent + 10_000, space, programId: this.cfg.portalProgramId });
2333
+ await this.sendOnL1([ix], [this.wallet, acct]);
2334
+ return acct;
2335
+ }
2336
+ // ───────────────────────── eva PDAs ─────────────────────────
2337
+ globalStatePda() { return evaPdas.globalStatePda(this.cfg.evaProgramId); }
2338
+ trenchPda(id) { return evaPdas.trenchPda(this.cfg.evaProgramId, id); }
2339
+ tokenMintPda(id) { return evaPdas.tokenMintPda(this.cfg.evaProgramId, this.trenchPda(id)); }
2340
+ trenchVault(id) { return evaPdas.trenchTokenVault(this.tokenMintPda(id), this.trenchPda(id)); }
2341
+ userAta(id, user = this.wallet.publicKey) { return evaPdas.userTokenAccount(this.tokenMintPda(id), user); }
2342
+ // ───────────────────────── eva reads (processed by default) ─────────────────────────
2343
+ async getGlobal(source = "er") {
2344
+ const info = source === "er" ? await this.erGetAccount(this.globalStatePda()) : await this.l1GetAccount(this.globalStatePda());
2345
+ return info ? decodeGlobalState(info.data) : null;
2346
+ }
2347
+ async getTrench(id, source = "er", retries = 1) {
2348
+ const pda = this.trenchPda(id);
2349
+ for (let i = 0; i < retries; i++) {
2350
+ const info = source === "er" ? await this.erGetAccount(pda) : await this.l1GetAccount(pda);
2351
+ if (info?.data?.length)
2352
+ return decodeTrench(info.data);
2353
+ if (i < retries - 1)
2354
+ await sleep(this.pollMs);
2355
+ }
2356
+ return null;
2357
+ }
2358
+ async getUserTokenBalance(id, user = this.wallet.publicKey, source = "er") {
2359
+ const ata = this.userAta(id, user);
2360
+ const info = source === "er" ? await this.erGetAccount(ata) : await this.l1GetAccount(ata);
2361
+ return info?.data?.length ? decodeTokenAmount(info.data) : 0n;
2362
+ }
2363
+ // pure quote helpers
2364
+ previewBuy(reserves, solPayWithFee) { return previewBuy(reserves, solPayWithFee); }
2365
+ previewSell(reserves, tokensIn) { return previewSell(reserves, tokensIn); }
2366
+ decodeReserves(data) { return decodeTrenchReserves(data); }
2367
+ // ───────────────────────── User Deposit & Withdraw SOL API ─────────────────────────
2368
+ // (the "green box" — fund L1→ER, query balance, withdraw ER→L1)
2369
+ /** Query an account's SOL balance on BOTH lanes (lamports). No program call, no fee. */
2370
+ async querySolBalance(account = this.wallet.publicKey) {
2371
+ const er = await this.erBalance(account).catch(() => 0n);
2372
+ const l1 = (await this.l1GetAccount(account))?.lamports ?? 0n;
2373
+ return { er, l1 };
2374
+ }
2375
+ /** "Fund fee to ER payer" — deposit SOL from L1 so `recipient` is credited & spendable on the ER. Alias of fundErFeePayer. */
2376
+ async fundFeeToErPayer(lamports, recipient = this.wallet.publicKey) {
2377
+ return this.fundErFeePayer(lamports, recipient);
2378
+ }
2379
+ /** The ER WithdrawalSink PDA for a recipient (where ER withdrawal requests are sent). */
2380
+ getWithdrawalSink(recipient = this.wallet.publicKey) {
2381
+ return portal.withdrawalSinkPda(this.cfg.portalProgramId, this.sessionPda(), recipient);
2382
+ }
2383
+ /**
2384
+ * "Withdraw fee from ER" (path 2): an ER `system_transfer` from `recipient` → its
2385
+ * WithdrawalSink. The validator pays the L1 SOL ASYNCHRONOUSLY at the next settlement
2386
+ * (use {@link waitForL1Settlement} to await it). `recipient` is a Keypair (it signs the
2387
+ * ER transfer; the L1 receiver never signs).
2388
+ *
2389
+ * NOTE: the L1 payout currently goes to the SAME account that deposited — an arbitrary
2390
+ * `toL1` destination is not supported by the Portal program yet (pending protocol change).
2391
+ */
2392
+ async requestWithdraw(p) {
2393
+ if (p.toL1 && !p.toL1.equals(p.recipient.publicKey)) {
2394
+ throw new Error("Arbitrary L1 withdrawal destination is not supported yet (Portal pays the deposit recipient). Omit `toL1` or set it equal to recipient.");
2395
+ }
2396
+ const sink = this.getWithdrawalSink(p.recipient.publicKey);
2397
+ const ix = SystemProgram.transfer({ fromPubkey: p.recipient.publicKey, toPubkey: sink, lamports: Number(p.lamports) });
2398
+ return this.sendOnEr([ix], [p.recipient]);
2399
+ }
2400
+ /** Poll an account's L1 balance until it rises by >= `expectedDelta` (settlement is async). Returns the final L1 balance. */
2401
+ async waitForL1Settlement(account, expectedDelta, timeoutMs = 60_000) {
2402
+ const start = (await this.l1GetAccount(account))?.lamports ?? 0n;
2403
+ const attempts = Math.max(1, Math.ceil(timeoutMs / 1000));
2404
+ let cur = start;
2405
+ for (let i = 0; i < attempts; i++) {
2406
+ await sleep(1000);
2407
+ cur = (await this.l1GetAccount(account))?.lamports ?? 0n;
2408
+ if (cur - start >= expectedDelta)
2409
+ break;
2410
+ }
2411
+ return cur;
2412
+ }
2413
+ // ───────────────────────── eva game (executed on the ER, dev-mode) ─────────────────────────
2414
+ async initialize(p) {
2415
+ if (await this.getGlobal("er"))
2416
+ return null; // already initialized
2417
+ const ix = await this.methods.initialize(this.bn(p.biddingDuration), this.bn(p.tradingDuration))
2418
+ .accounts({ admin: this.wallet.publicKey }).instruction();
2419
+ return this.sendEva(ix, "initialize");
2420
+ }
2421
+ /** createTrench with the next sequential id (id == total_trenches + 1). */
2422
+ async createTrench(p = {}) {
2423
+ const g = await this.getGlobal("er");
2424
+ if (!g)
2425
+ throw new Error("global state not initialized — call initialize() first");
2426
+ const trenchId = g.totalTrenches + 1n;
2427
+ const ivtr = p.initialVirtualTokenReserves ?? INITIAL_TOKEN_SUPPLY / 2n;
2428
+ const ix = await this.methods.createTrench(this.bn(trenchId), this.bn(ivtr))
2429
+ .accounts({ globalState: this.globalStatePda(), creator: this.wallet.publicKey }).instruction();
2430
+ const signature = await this.sendEva(ix, "createTrench");
2431
+ return { trenchId, signature };
2432
+ }
2433
+ async deposit(p) {
2434
+ const ix = await this.methods.deposit(this.bn(p.lamports), this.bn(p.thinkId ?? 0n))
2435
+ .accounts({ trench: this.trenchPda(p.trenchId), user: this.wallet.publicKey }).instruction();
2436
+ return this.sendEva(ix, "deposit");
2437
+ }
2438
+ /** finalize — waits for the ER slot to pass biddingEndBlock, then seeds the AMM. */
2439
+ async finalize(p) {
2440
+ const g = await this.requireGlobal();
2441
+ const t = await this.getTrench(p.trenchId, "er", 10);
2442
+ if (t)
2443
+ for (let i = 0; i < 80; i++) {
2444
+ const s = BigInt(await this.erRpc("getSlot"));
2445
+ if (s >= t.biddingEndBlock)
2446
+ break;
2447
+ await sleep(this.pollMs);
2448
+ }
2449
+ const ix = await this.methods.finalize()
2450
+ .accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), admin: this.wallet.publicKey }).instruction();
2451
+ return this.sendEva(ix, "finalize");
2452
+ }
2453
+ /** Create the user's token ATA on the ER (buy/sell require it to pre-exist). */
2454
+ async ensureUserAta(p) {
2455
+ const user = p.user ?? this.wallet.publicKey;
2456
+ const ix = createAssociatedTokenAccountIdempotentInstruction(this.wallet.publicKey, this.userAta(p.trenchId, user), user, this.tokenMintPda(p.trenchId), TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID);
2457
+ return this.sendEva(ix, "ensureUserAta");
2458
+ }
2459
+ async buy(p) {
2460
+ const g = await this.requireGlobal();
2461
+ const ix = await this.methods.buy(this.bn(p.solPayWithFee), this.bn(p.thinkId ?? 0n))
2462
+ .accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user: this.wallet.publicKey, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId), systemProgram: SystemProgram.programId, tokenProgram: TOKEN_PROGRAM_ID }).instruction();
2463
+ const signature = await this.sendEva(ix, "buy");
2464
+ return { signature, trench: (await this.getTrench(p.trenchId, "er", 5)), userTokens: await this.getUserTokenBalance(p.trenchId) };
2465
+ }
2466
+ async sell(p) {
2467
+ const g = await this.requireGlobal();
2468
+ const ix = await this.methods.sell(this.bn(p.tokenAmount), this.bn(p.minSolOutput ?? 0n), this.bn(p.thinkId ?? 0n))
2469
+ .accounts({ trench: this.trenchPda(p.trenchId), globalState: this.globalStatePda(), feeRecipient: new PublicKey(g.feeRecipient), user: this.wallet.publicKey, trenchTokenVault: this.trenchVault(p.trenchId), userTokenAccount: this.userAta(p.trenchId), tokenProgram: TOKEN_PROGRAM_ID }).instruction();
2470
+ const signature = await this.sendEva(ix, "sell");
2471
+ return { signature, trench: (await this.getTrench(p.trenchId, "er", 5)), userTokens: await this.getUserTokenBalance(p.trenchId) };
2472
+ }
2473
+ }