@jup-ag/lend 0.0.106 → 0.0.107-beta.1

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,2299 @@
1
+ import { PublicKey, Transaction, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_INSTRUCTIONS_PUBKEY } from '@solana/web3.js';
2
+ import BN from 'bn.js';
3
+ import { Program, AnchorProvider } from '@coral-xyz/anchor';
4
+ import { l as liquidity } from './lend.CioR9-te.mjs';
5
+ import { getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';
6
+ import { a as getTickHasDebt, v as vaultsIdl, c as getPosition, d as getTick, e as getTickIdLiquidation, f as getVaultConfig, h as getBranch, i as getVaultState, j as getVaultMetadata, k as getLiquidity, l as getRateModel, m as getUserBorrowPosition, n as getUserSupplyPosition, o as getLiquidityReserve, p as getPositionTokenAccount, q as getPositionMetadata, r as getPositionMint, g as getVaultAdmin, s as getClaimAccount } from './lend.C2-jCLFw.mjs';
7
+ import { e as getReserve } from './lend.BzG5ldOV.mjs';
8
+
9
+ const address = "jupnw4B6Eqs7ft6rxpzYLJZYSnrpRgPcr589n5Kv4oc";
10
+ const metadata = {
11
+ name: "oracle",
12
+ version: "0.1.0",
13
+ spec: "0.1.0",
14
+ description: "Created with Anchor"
15
+ };
16
+ const instructions = [
17
+ {
18
+ name: "get_both_exchange_rate",
19
+ discriminator: [
20
+ 92,
21
+ 88,
22
+ 161,
23
+ 46,
24
+ 230,
25
+ 193,
26
+ 46,
27
+ 237
28
+ ],
29
+ accounts: [
30
+ {
31
+ name: "oracle"
32
+ }
33
+ ],
34
+ args: [
35
+ {
36
+ name: "_nonce",
37
+ type: "u16"
38
+ }
39
+ ]
40
+ },
41
+ {
42
+ name: "get_exchange_rate",
43
+ discriminator: [
44
+ 153,
45
+ 76,
46
+ 17,
47
+ 194,
48
+ 170,
49
+ 215,
50
+ 89,
51
+ 142
52
+ ],
53
+ accounts: [
54
+ {
55
+ name: "oracle"
56
+ }
57
+ ],
58
+ args: [
59
+ {
60
+ name: "_nonce",
61
+ type: "u16"
62
+ }
63
+ ],
64
+ returns: "u128"
65
+ },
66
+ {
67
+ name: "get_exchange_rate_liquidate",
68
+ discriminator: [
69
+ 228,
70
+ 169,
71
+ 73,
72
+ 39,
73
+ 91,
74
+ 82,
75
+ 27,
76
+ 5
77
+ ],
78
+ accounts: [
79
+ {
80
+ name: "oracle"
81
+ }
82
+ ],
83
+ args: [
84
+ {
85
+ name: "_nonce",
86
+ type: "u16"
87
+ }
88
+ ],
89
+ returns: "u128"
90
+ },
91
+ {
92
+ name: "get_exchange_rate_operate",
93
+ discriminator: [
94
+ 174,
95
+ 166,
96
+ 126,
97
+ 10,
98
+ 122,
99
+ 153,
100
+ 94,
101
+ 203
102
+ ],
103
+ accounts: [
104
+ {
105
+ name: "oracle"
106
+ }
107
+ ],
108
+ args: [
109
+ {
110
+ name: "_nonce",
111
+ type: "u16"
112
+ }
113
+ ],
114
+ returns: "u128"
115
+ },
116
+ {
117
+ name: "init_admin",
118
+ discriminator: [
119
+ 97,
120
+ 65,
121
+ 97,
122
+ 27,
123
+ 200,
124
+ 206,
125
+ 72,
126
+ 219
127
+ ],
128
+ accounts: [
129
+ {
130
+ name: "signer",
131
+ writable: true,
132
+ signer: true
133
+ },
134
+ {
135
+ name: "oracle_admin",
136
+ writable: true,
137
+ pda: {
138
+ seeds: [
139
+ {
140
+ kind: "const",
141
+ value: [
142
+ 111,
143
+ 114,
144
+ 97,
145
+ 99,
146
+ 108,
147
+ 101,
148
+ 95,
149
+ 97,
150
+ 100,
151
+ 109,
152
+ 105,
153
+ 110
154
+ ]
155
+ }
156
+ ]
157
+ }
158
+ },
159
+ {
160
+ name: "system_program",
161
+ address: "11111111111111111111111111111111"
162
+ }
163
+ ],
164
+ args: [
165
+ {
166
+ name: "authority",
167
+ type: "pubkey"
168
+ }
169
+ ]
170
+ },
171
+ {
172
+ name: "init_oracle_config",
173
+ discriminator: [
174
+ 77,
175
+ 144,
176
+ 180,
177
+ 246,
178
+ 217,
179
+ 15,
180
+ 118,
181
+ 92
182
+ ],
183
+ accounts: [
184
+ {
185
+ name: "signer",
186
+ writable: true,
187
+ signer: true
188
+ },
189
+ {
190
+ name: "oracle_admin"
191
+ },
192
+ {
193
+ name: "oracle",
194
+ writable: true,
195
+ pda: {
196
+ seeds: [
197
+ {
198
+ kind: "const",
199
+ value: [
200
+ 111,
201
+ 114,
202
+ 97,
203
+ 99,
204
+ 108,
205
+ 101
206
+ ]
207
+ },
208
+ {
209
+ kind: "arg",
210
+ path: "nonce"
211
+ }
212
+ ]
213
+ }
214
+ },
215
+ {
216
+ name: "system_program",
217
+ address: "11111111111111111111111111111111"
218
+ }
219
+ ],
220
+ args: [
221
+ {
222
+ name: "sources",
223
+ type: {
224
+ vec: {
225
+ defined: {
226
+ name: "Sources"
227
+ }
228
+ }
229
+ }
230
+ },
231
+ {
232
+ name: "nonce",
233
+ type: "u16"
234
+ }
235
+ ]
236
+ },
237
+ {
238
+ name: "update_authority",
239
+ discriminator: [
240
+ 32,
241
+ 46,
242
+ 64,
243
+ 28,
244
+ 149,
245
+ 75,
246
+ 243,
247
+ 88
248
+ ],
249
+ accounts: [
250
+ {
251
+ name: "authority",
252
+ signer: true
253
+ },
254
+ {
255
+ name: "oracle_admin",
256
+ writable: true
257
+ }
258
+ ],
259
+ args: [
260
+ {
261
+ name: "new_authority",
262
+ type: "pubkey"
263
+ }
264
+ ]
265
+ },
266
+ {
267
+ name: "update_auths",
268
+ discriminator: [
269
+ 93,
270
+ 96,
271
+ 178,
272
+ 156,
273
+ 57,
274
+ 117,
275
+ 253,
276
+ 209
277
+ ],
278
+ accounts: [
279
+ {
280
+ name: "authority",
281
+ signer: true
282
+ },
283
+ {
284
+ name: "oracle_admin",
285
+ writable: true
286
+ }
287
+ ],
288
+ args: [
289
+ {
290
+ name: "auth_status",
291
+ type: {
292
+ vec: {
293
+ defined: {
294
+ name: "AddressBool"
295
+ }
296
+ }
297
+ }
298
+ }
299
+ ]
300
+ }
301
+ ];
302
+ const accounts = [
303
+ {
304
+ name: "Oracle",
305
+ discriminator: [
306
+ 139,
307
+ 194,
308
+ 131,
309
+ 179,
310
+ 140,
311
+ 179,
312
+ 229,
313
+ 244
314
+ ]
315
+ },
316
+ {
317
+ name: "OracleAdmin",
318
+ discriminator: [
319
+ 239,
320
+ 232,
321
+ 8,
322
+ 20,
323
+ 254,
324
+ 63,
325
+ 25,
326
+ 246
327
+ ]
328
+ }
329
+ ];
330
+ const events = [
331
+ {
332
+ name: "LogStakePoolHighFeeDetected",
333
+ discriminator: [
334
+ 198,
335
+ 106,
336
+ 149,
337
+ 7,
338
+ 25,
339
+ 83,
340
+ 39,
341
+ 155
342
+ ]
343
+ },
344
+ {
345
+ name: "LogUpdateAuthority",
346
+ discriminator: [
347
+ 150,
348
+ 152,
349
+ 157,
350
+ 143,
351
+ 6,
352
+ 135,
353
+ 193,
354
+ 101
355
+ ]
356
+ },
357
+ {
358
+ name: "LogUpdateAuths",
359
+ discriminator: [
360
+ 88,
361
+ 80,
362
+ 109,
363
+ 48,
364
+ 111,
365
+ 203,
366
+ 76,
367
+ 251
368
+ ]
369
+ }
370
+ ];
371
+ const errors = [
372
+ {
373
+ code: 6000,
374
+ name: "PriceNotValid",
375
+ msg: "PRICE_NOT_VALID"
376
+ },
377
+ {
378
+ code: 6001,
379
+ name: "PriceTooOld",
380
+ msg: "PRICE_TOO_OLD"
381
+ },
382
+ {
383
+ code: 6002,
384
+ name: "RateZero",
385
+ msg: "RATE_ZERO"
386
+ },
387
+ {
388
+ code: 6003,
389
+ name: "InvalidParams",
390
+ msg: "INVALID_PARAMS"
391
+ },
392
+ {
393
+ code: 6004,
394
+ name: "InvalidPythSourceMultiplierAndDivisor",
395
+ msg: "INVALID_PYTH_SOURCE_MULTIPLIER_AND_DIVISOR"
396
+ },
397
+ {
398
+ code: 6005,
399
+ name: "InvalidSource",
400
+ msg: "INVALID_SOURCE"
401
+ },
402
+ {
403
+ code: 6006,
404
+ name: "InvalidSourcesLength",
405
+ msg: "INVALID_SOURCES_LENGTH"
406
+ },
407
+ {
408
+ code: 6007,
409
+ name: "OracleAdminOnlyAuthority",
410
+ msg: "ORACLE_ADMIN_ONLY_AUTHORITY"
411
+ },
412
+ {
413
+ code: 6008,
414
+ name: "OracleAdminOnlyAuth",
415
+ msg: "ORACLE_ADMIN_ONLY_AUTH"
416
+ },
417
+ {
418
+ code: 6009,
419
+ name: "OracleAdminMaxAuthCountReached",
420
+ msg: "ORACLE_ADMIN_MAX_AUTH_COUNT_REACHED"
421
+ },
422
+ {
423
+ code: 6010,
424
+ name: "OracleAdminInvalidParams",
425
+ msg: "ORACLE_ADMIN_INVALID_PARAMS"
426
+ },
427
+ {
428
+ code: 6011,
429
+ name: "OracleNonceMismatch",
430
+ msg: "ORACLE_NONCE_MISMATCH"
431
+ },
432
+ {
433
+ code: 6012,
434
+ name: "PriceConfidenceNotSufficient",
435
+ msg: "PRICE_CONFIDENCE_NOT_SUFFICIENT"
436
+ },
437
+ {
438
+ code: 6013,
439
+ name: "StakePoolNotRefreshed",
440
+ msg: "STAKE_POOL_NOT_REFRESHED"
441
+ },
442
+ {
443
+ code: 6014,
444
+ name: "InvalidPrice",
445
+ msg: "INVALID_PRICE"
446
+ },
447
+ {
448
+ code: 6015,
449
+ name: "FeeTooHigh",
450
+ msg: "FEE_TOO_HIGH"
451
+ },
452
+ {
453
+ code: 6016,
454
+ name: "RedstonePriceOverflow",
455
+ msg: "REDSTONE_PRICE_OVERFLOW"
456
+ },
457
+ {
458
+ code: 6017,
459
+ name: "TimestampExpected",
460
+ msg: "TIMESTAMP_EXPECTED"
461
+ },
462
+ {
463
+ code: 6018,
464
+ name: "CpiToStakeProgramFailed",
465
+ msg: "CPI_TO_STAKE_PROGRAM_FAILED"
466
+ },
467
+ {
468
+ code: 6019,
469
+ name: "InvalidStakePoolReturnParams",
470
+ msg: "INVALID_STAKE_POOL_RETURN_PARAMS"
471
+ },
472
+ {
473
+ code: 6020,
474
+ name: "ChainlinkPriceReadError",
475
+ msg: "CHAINLINK_PRICE_READ_ERROR"
476
+ },
477
+ {
478
+ code: 6021,
479
+ name: "SinglePoolTokenSupplyZero",
480
+ msg: "SINGLE_POOL_TOKEN_SUPPLY_ZERO"
481
+ },
482
+ {
483
+ code: 6022,
484
+ name: "SinglePoolInvalidStakeAccount",
485
+ msg: "SINGLE_POOL_INVALID_STAKE_ACCOUNT"
486
+ },
487
+ {
488
+ code: 6023,
489
+ name: "SinglePoolInvalidMint",
490
+ msg: "SINGLE_POOL_INVALID_MINT"
491
+ }
492
+ ];
493
+ const types = [
494
+ {
495
+ name: "AddressBool",
496
+ type: {
497
+ kind: "struct",
498
+ fields: [
499
+ {
500
+ name: "addr",
501
+ type: "pubkey"
502
+ },
503
+ {
504
+ name: "value",
505
+ type: "bool"
506
+ }
507
+ ]
508
+ }
509
+ },
510
+ {
511
+ name: "LogStakePoolHighFeeDetected",
512
+ type: {
513
+ kind: "struct",
514
+ fields: [
515
+ {
516
+ name: "stake_pool",
517
+ type: "pubkey"
518
+ },
519
+ {
520
+ name: "epoch",
521
+ type: "u64"
522
+ }
523
+ ]
524
+ }
525
+ },
526
+ {
527
+ name: "LogUpdateAuthority",
528
+ type: {
529
+ kind: "struct",
530
+ fields: [
531
+ {
532
+ name: "new_authority",
533
+ type: "pubkey"
534
+ }
535
+ ]
536
+ }
537
+ },
538
+ {
539
+ name: "LogUpdateAuths",
540
+ type: {
541
+ kind: "struct",
542
+ fields: [
543
+ {
544
+ name: "auth_status",
545
+ type: {
546
+ vec: {
547
+ defined: {
548
+ name: "AddressBool"
549
+ }
550
+ }
551
+ }
552
+ }
553
+ ]
554
+ }
555
+ },
556
+ {
557
+ name: "Oracle",
558
+ type: {
559
+ kind: "struct",
560
+ fields: [
561
+ {
562
+ name: "nonce",
563
+ type: "u16"
564
+ },
565
+ {
566
+ name: "sources",
567
+ type: {
568
+ vec: {
569
+ defined: {
570
+ name: "Sources"
571
+ }
572
+ }
573
+ }
574
+ },
575
+ {
576
+ name: "bump",
577
+ type: "u8"
578
+ }
579
+ ]
580
+ }
581
+ },
582
+ {
583
+ name: "OracleAdmin",
584
+ type: {
585
+ kind: "struct",
586
+ fields: [
587
+ {
588
+ name: "authority",
589
+ type: "pubkey"
590
+ },
591
+ {
592
+ name: "auths",
593
+ type: {
594
+ vec: "pubkey"
595
+ }
596
+ }
597
+ ]
598
+ }
599
+ },
600
+ {
601
+ name: "SourceType",
602
+ type: {
603
+ kind: "enum",
604
+ variants: [
605
+ {
606
+ name: "Pyth"
607
+ },
608
+ {
609
+ name: "StakePool"
610
+ },
611
+ {
612
+ name: "MsolPool"
613
+ },
614
+ {
615
+ name: "Redstone"
616
+ },
617
+ {
618
+ name: "Chainlink"
619
+ },
620
+ {
621
+ name: "SinglePool"
622
+ }
623
+ ]
624
+ }
625
+ },
626
+ {
627
+ name: "Sources",
628
+ type: {
629
+ kind: "struct",
630
+ fields: [
631
+ {
632
+ name: "source",
633
+ type: "pubkey"
634
+ },
635
+ {
636
+ name: "invert",
637
+ type: "bool"
638
+ },
639
+ {
640
+ name: "multiplier",
641
+ type: "u128"
642
+ },
643
+ {
644
+ name: "divisor",
645
+ type: "u128"
646
+ },
647
+ {
648
+ name: "source_type",
649
+ type: {
650
+ defined: {
651
+ name: "SourceType"
652
+ }
653
+ }
654
+ }
655
+ ]
656
+ }
657
+ }
658
+ ];
659
+ const oracle = {
660
+ address: address,
661
+ metadata: metadata,
662
+ instructions: instructions,
663
+ accounts: accounts,
664
+ events: events,
665
+ errors: errors,
666
+ types: types
667
+ };
668
+
669
+ const MIN_TICK$1 = -16383;
670
+ const MAX_TICK$1 = 16383;
671
+ const ZERO_TICK_SCALED_RATIO$1 = new BN(281474976710656);
672
+ const TICK_HAS_DEBT_ARRAY_SIZE = 8;
673
+ const TICKS_PER_TICK_HAS_DEBT = TICK_HAS_DEBT_ARRAY_SIZE * 256;
674
+ const TICK_HAS_DEBT_CHILDREN_SIZE = 32;
675
+ const TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS = 256;
676
+ const TOTAL_INDICES_NEEDED = 16;
677
+ function getRatioAtTick(tick) {
678
+ if (tick < MIN_TICK$1 || tick > MAX_TICK$1) {
679
+ throw new Error(`Tick ${tick} out of range [${MIN_TICK$1}, ${MAX_TICK$1}]`);
680
+ }
681
+ const FACTOR00 = new BN("18446744073709551616");
682
+ const FACTOR01 = new BN("18419115400608638658");
683
+ const FACTOR02 = new BN("18391528108445969703");
684
+ const FACTOR03 = new BN("18336477419114433396");
685
+ const FACTOR04 = new BN("18226869890870665593");
686
+ const FACTOR05 = new BN("18009616477100071088");
687
+ const FACTOR06 = new BN("17582847377087825313");
688
+ const FACTOR07 = new BN("16759408633341240198");
689
+ const FACTOR08 = new BN("15226414841393184936");
690
+ const FACTOR09 = new BN("12568272644527235157");
691
+ const FACTOR10 = new BN("8563108841104354677");
692
+ const FACTOR11 = new BN("3975055583337633975");
693
+ const FACTOR12 = new BN("856577552520149366");
694
+ const FACTOR13 = new BN("39775317560084773");
695
+ const FACTOR14 = new BN("85764505686420");
696
+ const FACTOR15 = new BN("398745188");
697
+ const absTick = Math.abs(tick);
698
+ let factor = FACTOR00;
699
+ if (absTick & 1) factor = FACTOR01;
700
+ if (absTick & 2) factor = mulShift64(factor, FACTOR02);
701
+ if (absTick & 4) factor = mulShift64(factor, FACTOR03);
702
+ if (absTick & 8) factor = mulShift64(factor, FACTOR04);
703
+ if (absTick & 16) factor = mulShift64(factor, FACTOR05);
704
+ if (absTick & 32) factor = mulShift64(factor, FACTOR06);
705
+ if (absTick & 64) factor = mulShift64(factor, FACTOR07);
706
+ if (absTick & 128) factor = mulShift64(factor, FACTOR08);
707
+ if (absTick & 256) factor = mulShift64(factor, FACTOR09);
708
+ if (absTick & 512) factor = mulShift64(factor, FACTOR10);
709
+ if (absTick & 1024) factor = mulShift64(factor, FACTOR11);
710
+ if (absTick & 2048) factor = mulShift64(factor, FACTOR12);
711
+ if (absTick & 4096) factor = mulShift64(factor, FACTOR13);
712
+ if (absTick & 8192) factor = mulShift64(factor, FACTOR14);
713
+ if (absTick & 16384) factor = mulShift64(factor, FACTOR15);
714
+ let precision = new BN(0);
715
+ if (tick > 0) {
716
+ const maxU128 = new BN(2).pow(new BN(128)).sub(new BN(1));
717
+ factor = maxU128.div(factor);
718
+ if (!factor.mod(new BN(65536)).isZero()) {
719
+ precision = new BN(1);
720
+ }
721
+ }
722
+ const ratioX48 = factor.shrn(16).add(precision);
723
+ return ratioX48;
724
+ }
725
+ function mulShift64(n0, n1) {
726
+ try {
727
+ return n0.mul(n1).shrn(64);
728
+ } catch {
729
+ const product = n0.mul(n1);
730
+ return product.div(new BN(2).pow(new BN(64)));
731
+ }
732
+ }
733
+ function getTickAtRatio(ratioX48) {
734
+ const MIN_RATIOX48 = new BN(6093);
735
+ const MAX_RATIOX48 = new BN("13002088133096036565414295");
736
+ const _1E13 = new BN("10000000000000");
737
+ if (ratioX48.lt(MIN_RATIOX48) || ratioX48.gt(MAX_RATIOX48)) {
738
+ throw new Error(`Ratio ${ratioX48.toString()} out of bounds`);
739
+ }
740
+ const isNegative = ratioX48.lt(ZERO_TICK_SCALED_RATIO$1);
741
+ let factor;
742
+ factor = isNegative ? ZERO_TICK_SCALED_RATIO$1.mul(_1E13).div(ratioX48) : ratioX48.mul(_1E13).div(ZERO_TICK_SCALED_RATIO$1);
743
+ let tick = 0;
744
+ if (factor.gte(new BN("2150859953785115391"))) {
745
+ tick |= 8192;
746
+ factor = factor.mul(_1E13).div(new BN("2150859953785115391"));
747
+ }
748
+ if (factor.gte(new BN("4637736467054931"))) {
749
+ tick |= 4096;
750
+ factor = factor.mul(_1E13).div(new BN("4637736467054931"));
751
+ }
752
+ if (factor.gte(new BN("215354044936586"))) {
753
+ tick |= 2048;
754
+ factor = factor.mul(_1E13).div(new BN("215354044936586"));
755
+ }
756
+ if (factor.gte(new BN("46406254420777"))) {
757
+ tick |= 1024;
758
+ factor = factor.mul(_1E13).div(new BN("46406254420777"));
759
+ }
760
+ if (factor.gte(new BN("21542110950596"))) {
761
+ tick |= 512;
762
+ factor = factor.mul(_1E13).div(new BN("21542110950596"));
763
+ }
764
+ if (factor.gte(new BN("14677230989051"))) {
765
+ tick |= 256;
766
+ factor = factor.mul(_1E13).div(new BN("14677230989051"));
767
+ }
768
+ if (factor.gte(new BN("12114962232319"))) {
769
+ tick |= 128;
770
+ factor = factor.mul(_1E13).div(new BN("12114962232319"));
771
+ }
772
+ if (factor.gte(new BN("11006798913544"))) {
773
+ tick |= 64;
774
+ factor = factor.mul(_1E13).div(new BN("11006798913544"));
775
+ }
776
+ if (factor.gte(new BN("10491329235871"))) {
777
+ tick |= 32;
778
+ factor = factor.mul(_1E13).div(new BN("10491329235871"));
779
+ }
780
+ if (factor.gte(new BN("10242718992470"))) {
781
+ tick |= 16;
782
+ factor = factor.mul(_1E13).div(new BN("10242718992470"));
783
+ }
784
+ if (factor.gte(new BN("10120631893548"))) {
785
+ tick |= 8;
786
+ factor = factor.mul(_1E13).div(new BN("10120631893548"));
787
+ }
788
+ if (factor.gte(new BN("10060135135051"))) {
789
+ tick |= 4;
790
+ factor = factor.mul(_1E13).div(new BN("10060135135051"));
791
+ }
792
+ if (factor.gte(new BN("10030022500000"))) {
793
+ tick |= 2;
794
+ factor = factor.mul(_1E13).div(new BN("10030022500000"));
795
+ }
796
+ if (factor.gte(new BN("10015000000000"))) {
797
+ tick |= 1;
798
+ }
799
+ if (isNegative) {
800
+ tick = ~tick;
801
+ }
802
+ return tick;
803
+ }
804
+ function getFirstTickForIndex(index) {
805
+ if (index >= TOTAL_INDICES_NEEDED) {
806
+ throw new Error(
807
+ `Invalid index: ${index}. Must be between 0 and ${TOTAL_INDICES_NEEDED - 1}`
808
+ );
809
+ }
810
+ return MIN_TICK$1 + index * TICKS_PER_TICK_HAS_DEBT;
811
+ }
812
+ function getTickIndices(tick) {
813
+ if (tick < MIN_TICK$1 || tick > MAX_TICK$1) {
814
+ throw new Error("Tick out of range");
815
+ }
816
+ const tickOffset = tick - MIN_TICK$1;
817
+ const arrayIndex = Math.floor(tickOffset / TICKS_PER_TICK_HAS_DEBT);
818
+ const firstTickForIndex = getFirstTickForIndex(arrayIndex);
819
+ const tickWithinArray = tick - firstTickForIndex;
820
+ const mapIndex = Math.floor(
821
+ tickWithinArray / TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS
822
+ );
823
+ const tickWithinMap = tickWithinArray % TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS;
824
+ const byteIndex = Math.floor(tickWithinMap / 8);
825
+ const bitIndex = tickWithinMap % 8;
826
+ return { arrayIndex, mapIndex, byteIndex, bitIndex };
827
+ }
828
+ async function readTickHasDebtArray({
829
+ vaultId,
830
+ index,
831
+ program
832
+ }) {
833
+ const tickPda = getTickHasDebt(vaultId, index);
834
+ return await program.account.tickHasDebtArray.fetch(tickPda);
835
+ }
836
+ async function findNextTickWithDebt(vaultId, startTick, program) {
837
+ try {
838
+ const { arrayIndex, mapIndex, byteIndex, bitIndex } = getTickIndices(startTick);
839
+ let currentArrayIndex = arrayIndex;
840
+ let currentMapIndex = mapIndex;
841
+ let tickHasDebtData = await readTickHasDebtArray({
842
+ vaultId,
843
+ index: currentArrayIndex,
844
+ program
845
+ });
846
+ if (!tickHasDebtData) {
847
+ return MIN_TICK$1;
848
+ }
849
+ clearBitsInBitmap(tickHasDebtData, mapIndex, byteIndex, bitIndex);
850
+ while (true) {
851
+ const { nextTick, hasNextTick } = fetchNextTopTickFromBitmap(
852
+ tickHasDebtData,
853
+ currentMapIndex
854
+ );
855
+ if (hasNextTick && nextTick !== MIN_TICK$1) {
856
+ return nextTick;
857
+ }
858
+ if (currentArrayIndex === 0) {
859
+ return MIN_TICK$1;
860
+ }
861
+ currentArrayIndex -= 1;
862
+ currentMapIndex = TICK_HAS_DEBT_ARRAY_SIZE - 1;
863
+ tickHasDebtData = await readTickHasDebtArray({
864
+ vaultId,
865
+ index: currentArrayIndex,
866
+ program
867
+ });
868
+ if (!tickHasDebtData) {
869
+ return MIN_TICK$1;
870
+ }
871
+ }
872
+ } catch (error) {
873
+ console.warn(`Error finding next tick with debt:`, error);
874
+ return MIN_TICK$1;
875
+ }
876
+ }
877
+ function clearBitsInBitmap(tickHasDebtData, mapIndex, byteIndex, bitIndex) {
878
+ const bitmap = [...tickHasDebtData.tickHasDebt[mapIndex].childrenBits];
879
+ if (bitIndex > 0) {
880
+ const mask = (1 << bitIndex) - 1;
881
+ bitmap[byteIndex] &= mask;
882
+ } else {
883
+ bitmap[byteIndex] = 0;
884
+ }
885
+ for (let i = byteIndex + 1; i < TICK_HAS_DEBT_CHILDREN_SIZE; i++) {
886
+ bitmap[i] = 0;
887
+ }
888
+ tickHasDebtData.tickHasDebt[mapIndex].childrenBits = bitmap;
889
+ }
890
+ function fetchNextTopTickFromBitmap(tickHasDebtData, startMapIndex) {
891
+ let mapIndex = startMapIndex;
892
+ while (mapIndex >= 0) {
893
+ if (hasBitsInMap(tickHasDebtData, mapIndex)) {
894
+ const { nextTick, hasNextTick } = getNextTickFromMap(
895
+ tickHasDebtData,
896
+ mapIndex
897
+ );
898
+ if (hasNextTick) {
899
+ return { nextTick, hasNextTick: true };
900
+ }
901
+ }
902
+ mapIndex--;
903
+ }
904
+ return { nextTick: MIN_TICK$1, hasNextTick: false };
905
+ }
906
+ function hasBitsInMap(tickHasDebtData, mapIndex) {
907
+ const childrenBits = tickHasDebtData.tickHasDebt[mapIndex].childrenBits;
908
+ return childrenBits.some((byte) => byte !== 0);
909
+ }
910
+ function getNextTickFromMap(tickHasDebtData, mapIndex) {
911
+ const childrenBits = tickHasDebtData.tickHasDebt[mapIndex].childrenBits;
912
+ for (let byteIdx = TICK_HAS_DEBT_CHILDREN_SIZE - 1; byteIdx >= 0; byteIdx--) {
913
+ if (childrenBits[byteIdx] !== 0) {
914
+ const leadingZeros = getMostSignificantBit(childrenBits[byteIdx]);
915
+ const bitPos = 7 - leadingZeros;
916
+ const tickWithinMap = byteIdx * 8 + bitPos;
917
+ const mapFirstTick = getFirstTickForMapIndex(
918
+ tickHasDebtData.index,
919
+ mapIndex
920
+ );
921
+ return {
922
+ nextTick: mapFirstTick + tickWithinMap,
923
+ hasNextTick: true
924
+ };
925
+ }
926
+ }
927
+ return { nextTick: MIN_TICK$1, hasNextTick: false };
928
+ }
929
+ function getMostSignificantBit(byte) {
930
+ if (byte === 0) return 8;
931
+ let leadingZeros = 0;
932
+ let mask = 128;
933
+ while ((byte & mask) === 0 && leadingZeros < 8) {
934
+ leadingZeros++;
935
+ mask >>>= 1;
936
+ }
937
+ return leadingZeros;
938
+ }
939
+ function getFirstTickForMapIndex(arrayIndex, mapIndex) {
940
+ const arrayFirstTick = getFirstTickForIndex(arrayIndex);
941
+ return arrayFirstTick + mapIndex * TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS;
942
+ }
943
+
944
+ const COEFFICIENT_SIZE_DEBT_FACTOR = 35;
945
+ const EXPONENT_SIZE_DEBT_FACTOR = 15;
946
+ const EXPONENT_MAX_DEBT_FACTOR = new BN(1).shln(EXPONENT_SIZE_DEBT_FACTOR).subn(1);
947
+ const DECIMALS_DEBT_FACTOR = new BN(16384);
948
+ const MAX_MASK_DEBT_FACTOR$1 = new BN(1).shln(COEFFICIENT_SIZE_DEBT_FACTOR + EXPONENT_SIZE_DEBT_FACTOR).subn(1);
949
+ const PRECISION = 64;
950
+ const TWO_POWER_64 = new BN("18446744073709551615");
951
+ const TWO_POWER_69_MINUS_1 = new BN(1).shln(69).subn(1);
952
+ const COEFFICIENT_PLUS_PRECISION = COEFFICIENT_SIZE_DEBT_FACTOR + PRECISION;
953
+ const COEFFICIENT_PLUS_PRECISION_MINUS_1 = COEFFICIENT_PLUS_PRECISION - 1;
954
+ new BN(1).shln(COEFFICIENT_PLUS_PRECISION_MINUS_1).subn(1);
955
+ new BN(1).shln(COEFFICIENT_PLUS_PRECISION_MINUS_1 - 1).subn(1);
956
+ function mulDivNormal(normal, bigNumber1, bigNumber2) {
957
+ if (bigNumber1.isZero() || bigNumber2.isZero()) {
958
+ return new BN(0);
959
+ }
960
+ const exponent1 = bigNumber1.and(EXPONENT_MAX_DEBT_FACTOR);
961
+ const exponent2 = bigNumber2.and(EXPONENT_MAX_DEBT_FACTOR);
962
+ if (exponent2.lt(exponent1)) {
963
+ throw new Error("LibraryBnError: exponent2 should be >= exponent1");
964
+ }
965
+ const netExponent = exponent2.sub(exponent1);
966
+ if (netExponent.lt(new BN(129))) {
967
+ const coefficient1 = bigNumber1.shrn(EXPONENT_SIZE_DEBT_FACTOR);
968
+ const coefficient2 = bigNumber2.shrn(EXPONENT_SIZE_DEBT_FACTOR);
969
+ const numerator = normal.mul(coefficient1);
970
+ const denominator = coefficient2.shln(netExponent.toNumber());
971
+ if (denominator.isZero()) {
972
+ throw new Error("LibraryDivisionByZero");
973
+ }
974
+ const result = numerator.div(denominator);
975
+ if (result.gt(TWO_POWER_64)) {
976
+ throw new Error("LibraryBnError: result overflow");
977
+ }
978
+ return result;
979
+ } else {
980
+ return new BN(0);
981
+ }
982
+ }
983
+ function mulBigNumber(bigNumber1, bigNumber2) {
984
+ const coefficient1 = bigNumber1.shrn(EXPONENT_SIZE_DEBT_FACTOR);
985
+ const coefficient2 = bigNumber2.shrn(EXPONENT_SIZE_DEBT_FACTOR);
986
+ const exponent1 = bigNumber1.and(EXPONENT_MAX_DEBT_FACTOR);
987
+ const exponent2 = bigNumber2.and(EXPONENT_MAX_DEBT_FACTOR);
988
+ const resCoefficient = coefficient1.mul(coefficient2);
989
+ const overflowLen = resCoefficient.gt(TWO_POWER_69_MINUS_1) ? COEFFICIENT_SIZE_DEBT_FACTOR : COEFFICIENT_SIZE_DEBT_FACTOR - 1;
990
+ const adjustedCoefficient = resCoefficient.shrn(overflowLen);
991
+ const resExponent = exponent1.add(exponent2).add(new BN(overflowLen));
992
+ if (resExponent.lt(DECIMALS_DEBT_FACTOR)) {
993
+ throw new Error("LibraryBnError: exponent underflow");
994
+ }
995
+ const finalExponent = resExponent.sub(DECIMALS_DEBT_FACTOR);
996
+ if (finalExponent.gt(EXPONENT_MAX_DEBT_FACTOR)) {
997
+ return MAX_MASK_DEBT_FACTOR$1;
998
+ }
999
+ return adjustedCoefficient.shln(EXPONENT_SIZE_DEBT_FACTOR).or(finalExponent);
1000
+ }
1001
+
1002
+ const getVaultsProgram = ({
1003
+ connection,
1004
+ signer
1005
+ }) => new Program(vaultsIdl, {
1006
+ connection,
1007
+ publicKey: signer
1008
+ });
1009
+ const INIT_TICK = -2147483648;
1010
+ const MIN_TICK = -16383;
1011
+ const MAX_TICK = 16383;
1012
+ const MAX_MASK_DEBT_FACTOR = new BN("1125899906842623");
1013
+ const EXCHANGE_PRICES_PRECISION = new BN(10).pow(new BN(12));
1014
+ const ZERO_TICK_SCALED_RATIO = new BN(281474976710656);
1015
+ const TICK_SPACING = new BN(10015);
1016
+ const X30 = new BN(1073741823);
1017
+ const MIN_I128$1 = new BN("170141183460469231731687303715884105728").neg();
1018
+ const getAccountOwner = async (account, connection) => {
1019
+ const info = await connection.getAccountInfo(account);
1020
+ if (!info)
1021
+ throw new Error(`Account info not found for ${account.toString()}`);
1022
+ return info.owner;
1023
+ };
1024
+ const getCurrentPosition = async ({
1025
+ vaultId,
1026
+ positionId,
1027
+ connection
1028
+ }) => {
1029
+ const program = new Program(vaultsIdl, { connection });
1030
+ const position = await program.account.position.fetch(
1031
+ getPosition(vaultId, positionId)
1032
+ );
1033
+ return await getCurrentPositionState({
1034
+ vaultId,
1035
+ position,
1036
+ program
1037
+ });
1038
+ };
1039
+ const getCurrentPositionState = async ({
1040
+ vaultId,
1041
+ position,
1042
+ program
1043
+ }) => {
1044
+ let positionTick = position.tick;
1045
+ if (positionTick === INIT_TICK) {
1046
+ positionTick = MIN_TICK;
1047
+ }
1048
+ if (position.isSupplyOnlyPosition) {
1049
+ return {
1050
+ tick: MIN_TICK,
1051
+ tickId: 0,
1052
+ colRaw: new BN(position.supplyAmount.toString()),
1053
+ finalAmount: new BN(position.supplyAmount.toString()),
1054
+ debtRaw: new BN(0),
1055
+ dustDebtRaw: new BN(0),
1056
+ isSupplyOnlyPosition: true,
1057
+ userLiquidationStatus: false,
1058
+ postLiquidationBranchId: 0
1059
+ };
1060
+ }
1061
+ const colRaw = new BN(position.supplyAmount.toString());
1062
+ const dustDebtRaw = new BN(position.dustDebtAmount.toString());
1063
+ let debtRaw = new BN(0);
1064
+ if (positionTick > MIN_TICK) {
1065
+ const collateralForDebtCalc = colRaw.add(new BN(1));
1066
+ const ratio = getRatioAtTick(positionTick);
1067
+ debtRaw = ratio.mul(collateralForDebtCalc).shrn(48).add(new BN(1));
1068
+ } else {
1069
+ debtRaw = new BN(0);
1070
+ }
1071
+ let userLiquidationStatus = false;
1072
+ let postLiquidationBranchId = 0;
1073
+ if (positionTick > MIN_TICK) {
1074
+ const tickData = await program.account.tick.fetch(
1075
+ getTick(vaultId, positionTick)
1076
+ );
1077
+ if (tickData.isLiquidated || tickData.totalIds > position.tickId) {
1078
+ userLiquidationStatus = true;
1079
+ let [tickIdData, branches] = await Promise.all([
1080
+ program.account.tickIdLiquidation.fetch(
1081
+ getTickIdLiquidation(
1082
+ vaultId,
1083
+ positionTick,
1084
+ position.tickId
1085
+ )
1086
+ ).catch(() => null),
1087
+ getAllBranches({ vaultId, program })
1088
+ ]);
1089
+ if (!tickIdData) {
1090
+ tickIdData = {
1091
+ vaultId,
1092
+ tick: positionTick,
1093
+ tickMap: position.tickId,
1094
+ isFullyLiquidated1: 0,
1095
+ liquidationBranchId1: 0,
1096
+ debtFactor1: new BN(0),
1097
+ isFullyLiquidated2: 0,
1098
+ liquidationBranchId2: 0,
1099
+ debtFactor2: new BN(0),
1100
+ isFullyLiquidated3: 0,
1101
+ liquidationBranchId3: 0,
1102
+ debtFactor3: new BN(0)
1103
+ };
1104
+ }
1105
+ const { isFullyLiquidated, branchId, connectionFactor } = getLiquidationStatus(position.tickId, tickData, tickIdData);
1106
+ postLiquidationBranchId = branchId;
1107
+ if (isFullyLiquidated) {
1108
+ return {
1109
+ tick: MIN_TICK,
1110
+ tickId: 0,
1111
+ colRaw: new BN(0),
1112
+ debtRaw: new BN(0),
1113
+ dustDebtRaw: new BN(0),
1114
+ finalAmount: new BN(0),
1115
+ isSupplyOnlyPosition: true,
1116
+ userLiquidationStatus: true,
1117
+ postLiquidationBranchId: 0
1118
+ };
1119
+ }
1120
+ const { finalTick, finalColRaw, finalDebtRaw } = processLiquidatedPosition({
1121
+ branches,
1122
+ branchId: postLiquidationBranchId,
1123
+ initialConnectionFactor: connectionFactor,
1124
+ initialDebtRaw: debtRaw
1125
+ });
1126
+ const netDebtRaw2 = finalDebtRaw.gt(dustDebtRaw) ? finalDebtRaw.sub(dustDebtRaw) : new BN(0);
1127
+ return {
1128
+ tick: finalTick,
1129
+ tickId: position.tickId,
1130
+ colRaw: finalColRaw,
1131
+ debtRaw: finalDebtRaw,
1132
+ dustDebtRaw,
1133
+ finalAmount: netDebtRaw2.gt(new BN(0)) ? finalColRaw : new BN(0),
1134
+ isSupplyOnlyPosition: finalTick === MIN_TICK,
1135
+ userLiquidationStatus,
1136
+ postLiquidationBranchId
1137
+ };
1138
+ }
1139
+ }
1140
+ const netDebtRaw = debtRaw.gt(dustDebtRaw) ? debtRaw.sub(dustDebtRaw) : new BN(0);
1141
+ return {
1142
+ tick: positionTick,
1143
+ tickId: position.tickId,
1144
+ colRaw,
1145
+ debtRaw,
1146
+ dustDebtRaw,
1147
+ finalAmount: netDebtRaw.gt(new BN(0)) ? colRaw : new BN(0),
1148
+ isSupplyOnlyPosition: positionTick === MIN_TICK,
1149
+ userLiquidationStatus,
1150
+ postLiquidationBranchId
1151
+ };
1152
+ };
1153
+ async function getAllBranches({
1154
+ vaultId,
1155
+ program
1156
+ }) {
1157
+ const vaultState = await program.account.vaultState.fetch(
1158
+ getVaultState(vaultId)
1159
+ );
1160
+ const branchPromises = [];
1161
+ for (let i = 0; i <= vaultState.totalBranchId; i++) {
1162
+ branchPromises.push(
1163
+ program.account.branch.fetch(getBranch(vaultId, i)).catch(() => null)
1164
+ );
1165
+ }
1166
+ const branchResults = await Promise.all(branchPromises);
1167
+ const branches = branchResults.filter((branch) => branch !== null);
1168
+ return branches;
1169
+ }
1170
+ function getLiquidationStatus(positionTickId, tickData, tickIdData) {
1171
+ let isFullyLiquidated;
1172
+ let branchId;
1173
+ let connectionFactor;
1174
+ if (tickData.totalIds === positionTickId) {
1175
+ isFullyLiquidated = tickData.isFullyLiquidated === 1;
1176
+ branchId = tickData.liquidationBranchId;
1177
+ connectionFactor = tickData.debtFactor;
1178
+ } else {
1179
+ const setIndex = (positionTickId + 2) % 3;
1180
+ switch (setIndex) {
1181
+ case 0: {
1182
+ isFullyLiquidated = tickIdData.isFullyLiquidated1 === 1;
1183
+ branchId = tickIdData.liquidationBranchId1;
1184
+ connectionFactor = tickIdData.debtFactor1;
1185
+ break;
1186
+ }
1187
+ case 1: {
1188
+ isFullyLiquidated = tickIdData.isFullyLiquidated2 === 1;
1189
+ branchId = tickIdData.liquidationBranchId2;
1190
+ connectionFactor = tickIdData.debtFactor2;
1191
+ break;
1192
+ }
1193
+ default: {
1194
+ isFullyLiquidated = tickIdData.isFullyLiquidated3 === 1;
1195
+ branchId = tickIdData.liquidationBranchId3;
1196
+ connectionFactor = tickIdData.debtFactor3;
1197
+ }
1198
+ }
1199
+ }
1200
+ return { isFullyLiquidated, branchId, connectionFactor };
1201
+ }
1202
+ function processLiquidatedPosition({
1203
+ branches,
1204
+ branchId,
1205
+ initialConnectionFactor,
1206
+ initialDebtRaw
1207
+ }) {
1208
+ let finalColRaw = new BN(0);
1209
+ let finalTick;
1210
+ const branchMap = new Map(
1211
+ branches.map((branch) => [branch.branchId, branch])
1212
+ );
1213
+ let currentBranchId = branchId;
1214
+ let currentConnectionFactor = initialConnectionFactor;
1215
+ let currentBranch = branchMap.get(currentBranchId);
1216
+ if (!currentBranch) {
1217
+ throw new Error(`Branch ${currentBranchId} not found`);
1218
+ }
1219
+ while (currentBranch.status === 2) {
1220
+ currentConnectionFactor = mulBigNumber(
1221
+ currentConnectionFactor,
1222
+ new BN(currentBranch.debtFactor.toString())
1223
+ );
1224
+ if (currentConnectionFactor.eq(MAX_MASK_DEBT_FACTOR)) {
1225
+ break;
1226
+ }
1227
+ currentBranchId = currentBranch.connectedBranchId;
1228
+ currentBranch = branchMap.get(currentBranchId);
1229
+ if (!currentBranch) {
1230
+ throw new Error(`Connected branch ${currentBranchId} not found`);
1231
+ }
1232
+ }
1233
+ let positionDebtRaw = new BN(0);
1234
+ if (currentBranch.status === 3 || currentConnectionFactor.eq(MAX_MASK_DEBT_FACTOR)) {
1235
+ positionDebtRaw = new BN(0);
1236
+ finalTick = MIN_TICK;
1237
+ } else {
1238
+ positionDebtRaw = mulDivNormal(
1239
+ initialDebtRaw,
1240
+ currentBranch.debtFactor,
1241
+ currentConnectionFactor
1242
+ );
1243
+ positionDebtRaw = positionDebtRaw.gt(initialDebtRaw.div(new BN(100))) ? positionDebtRaw.mul(new BN(9999)).div(new BN(1e4)) : new BN(0);
1244
+ if (positionDebtRaw.gt(new BN(0))) {
1245
+ finalTick = currentBranch.minimaTick;
1246
+ const ratioAtTick = getRatioAtTick(finalTick);
1247
+ const ratioOneLess = ratioAtTick.mul(new BN(1e4)).div(TICK_SPACING);
1248
+ const ratioLength = ratioAtTick.sub(ratioOneLess);
1249
+ const finalRatio = ratioOneLess.add(
1250
+ ratioLength.mul(new BN(currentBranch.minimaTickPartials)).div(X30)
1251
+ );
1252
+ finalColRaw = positionDebtRaw.mul(ZERO_TICK_SCALED_RATIO).div(finalRatio);
1253
+ } else finalTick = MIN_TICK;
1254
+ }
1255
+ return {
1256
+ finalTick,
1257
+ finalColRaw,
1258
+ finalDebtRaw: positionDebtRaw
1259
+ };
1260
+ }
1261
+ const getFinalPosition = async ({
1262
+ vaultId,
1263
+ currentPosition,
1264
+ newColAmount,
1265
+ newDebtAmount,
1266
+ program,
1267
+ connection,
1268
+ signer
1269
+ }) => {
1270
+ program = program ?? getVaultsProgram({ connection, signer });
1271
+ const vaultConfig = await program.account.vaultConfig.fetch(
1272
+ getVaultConfig(vaultId)
1273
+ );
1274
+ const {
1275
+ vaultSupplyExchangePrice: supplyExPrice,
1276
+ vaultBorrowExchangePrice: borrowExPrice
1277
+ } = await getExchangePrices({
1278
+ vaultId,
1279
+ vaultConfig,
1280
+ connection,
1281
+ signer
1282
+ });
1283
+ const borrowFee = vaultConfig.borrowFee;
1284
+ let { colRaw, debtRaw, dustDebtRaw } = currentPosition;
1285
+ if (newColAmount.gt(new BN(0))) {
1286
+ const supplyRaw = newColAmount.mul(EXCHANGE_PRICES_PRECISION).div(supplyExPrice);
1287
+ colRaw = colRaw.add(supplyRaw);
1288
+ } else if (newColAmount.lt(new BN(0))) {
1289
+ let withdrawRaw = new BN(0);
1290
+ if (newColAmount.gt(MIN_I128$1)) {
1291
+ withdrawRaw = newColAmount.abs().mul(EXCHANGE_PRICES_PRECISION).div(supplyExPrice).sub(new BN(1));
1292
+ colRaw = colRaw.sub(withdrawRaw);
1293
+ } else if (newColAmount.eq(MIN_I128$1)) {
1294
+ withdrawRaw = colRaw.mul(supplyExPrice).div(EXCHANGE_PRICES_PRECISION).mul(new BN(-1)).add(new BN(1));
1295
+ colRaw = new BN(0);
1296
+ } else {
1297
+ throw new Error("Invalid newColAmount");
1298
+ }
1299
+ }
1300
+ if (newDebtAmount.gt(new BN(0))) {
1301
+ const borrowRaw = newDebtAmount.mul(EXCHANGE_PRICES_PRECISION).div(borrowExPrice).add(new BN(1));
1302
+ const feeAmount = borrowRaw.mul(new BN(borrowFee)).div(new BN(1e4));
1303
+ const borrowAmountWithFee = borrowRaw.add(feeAmount);
1304
+ debtRaw = debtRaw.add(borrowAmountWithFee);
1305
+ } else if (newDebtAmount.lt(new BN(0))) {
1306
+ if (newDebtAmount.gt(MIN_I128$1)) {
1307
+ const payback_amount = newDebtAmount.abs().mul(EXCHANGE_PRICES_PRECISION).div(borrowExPrice).add(new BN(1));
1308
+ debtRaw = debtRaw.sub(payback_amount);
1309
+ } else if (newDebtAmount.eq(MIN_I128$1)) {
1310
+ debtRaw = new BN(0);
1311
+ } else {
1312
+ throw new Error("Invalid newDebtAmount");
1313
+ }
1314
+ }
1315
+ const netDebtRaw = debtRaw.gt(dustDebtRaw) ? debtRaw.sub(dustDebtRaw) : new BN(0);
1316
+ let finalTick;
1317
+ let isSupplyOnlyPosition;
1318
+ if (netDebtRaw.eq(new BN(0)) || colRaw.eq(new BN(0))) {
1319
+ finalTick = MIN_TICK;
1320
+ isSupplyOnlyPosition = true;
1321
+ } else {
1322
+ const marginAdjustedDebt = netDebtRaw.mul(new BN(1000000001)).div(new BN(1e9)).add(new BN(1));
1323
+ const ratio = marginAdjustedDebt.mul(ZERO_TICK_SCALED_RATIO).div(colRaw);
1324
+ const baseTickAtRatio = getTickAtRatio(ratio);
1325
+ finalTick = baseTickAtRatio + 1;
1326
+ if (finalTick < MIN_TICK) {
1327
+ finalTick = MIN_TICK;
1328
+ } else if (finalTick > MAX_TICK) {
1329
+ finalTick = MAX_TICK;
1330
+ }
1331
+ isSupplyOnlyPosition = false;
1332
+ }
1333
+ return {
1334
+ tick: finalTick,
1335
+ tickId: currentPosition.tickId,
1336
+ colRaw,
1337
+ debtRaw,
1338
+ dustDebtRaw,
1339
+ finalAmount: netDebtRaw.gt(new BN(0)) ? colRaw : new BN(0),
1340
+ isSupplyOnlyPosition
1341
+ };
1342
+ };
1343
+ async function loadRelevantBranches(vaultId, vaultState, liquidationStatus, postLiquidationBranchId, program) {
1344
+ const addedBranchIds = /* @__PURE__ */ new Set();
1345
+ const currentBranchId = postLiquidationBranchId > 0 ? postLiquidationBranchId : vaultState.currentBranchId;
1346
+ let connectedBranchId = 0;
1347
+ if (currentBranchId > 0) {
1348
+ try {
1349
+ const currentBranch = await program.account.branch.fetch(
1350
+ getBranch(vaultId, currentBranchId)
1351
+ );
1352
+ if (currentBranch) {
1353
+ addedBranchIds.add(currentBranch.branchId);
1354
+ connectedBranchId = currentBranch.connectedBranchId;
1355
+ }
1356
+ } catch (error) {
1357
+ console.warn(`Failed to fetch current branch ${currentBranchId}:`, error);
1358
+ }
1359
+ }
1360
+ if (liquidationStatus) {
1361
+ while (connectedBranchId > 0) {
1362
+ try {
1363
+ const connectedBranch = await program.account.branch.fetch(
1364
+ getBranch(vaultId, connectedBranchId)
1365
+ );
1366
+ if (connectedBranch) {
1367
+ if (!addedBranchIds.has(connectedBranch.branchId))
1368
+ addedBranchIds.add(connectedBranch.branchId);
1369
+ connectedBranchId = connectedBranch.connectedBranchId;
1370
+ } else break;
1371
+ } catch (error) {
1372
+ console.warn(
1373
+ `Failed to fetch connected branch ${connectedBranchId}:`,
1374
+ error
1375
+ );
1376
+ break;
1377
+ }
1378
+ }
1379
+ if (!addedBranchIds.has(0)) addedBranchIds.add(0);
1380
+ }
1381
+ return [...addedBranchIds];
1382
+ }
1383
+ async function loadRelevantTicksHasDebtArrays(vaultId, topTick, existingPositionTick, finalTick, program) {
1384
+ const tickHasDebtArrays = /* @__PURE__ */ new Set();
1385
+ if (existingPositionTick == topTick) {
1386
+ let nextTickWithDebt = await findNextTickWithDebt(
1387
+ vaultId,
1388
+ topTick,
1389
+ program
1390
+ );
1391
+ let { arrayIndex: startIndex } = getTickIndices(nextTickWithDebt);
1392
+ let { arrayIndex: endIndex } = getTickIndices(topTick);
1393
+ let { arrayIndex: finalTickIndex } = getTickIndices(finalTick);
1394
+ let finalTickHasDebtPda = getTickHasDebt(vaultId, finalTickIndex);
1395
+ tickHasDebtArrays.add(finalTickHasDebtPda);
1396
+ if (endIndex < 15) endIndex++;
1397
+ try {
1398
+ for (let arrIdx = startIndex; arrIdx <= endIndex; arrIdx++)
1399
+ tickHasDebtArrays.add(getTickHasDebt(vaultId, arrIdx));
1400
+ } catch (error) {
1401
+ console.warn(`Error finding next tick with debt:`, error);
1402
+ }
1403
+ } else {
1404
+ let { arrayIndex: finalTickIndex } = getTickIndices(finalTick);
1405
+ let { arrayIndex: existingPositionTickIndex } = getTickIndices(existingPositionTick);
1406
+ tickHasDebtArrays.add(getTickHasDebt(vaultId, finalTickIndex));
1407
+ tickHasDebtArrays.add(
1408
+ getTickHasDebt(vaultId, existingPositionTickIndex)
1409
+ );
1410
+ }
1411
+ return [...tickHasDebtArrays];
1412
+ }
1413
+ async function getExchangePrices({
1414
+ vaultId,
1415
+ vaultConfig,
1416
+ connection,
1417
+ signer
1418
+ }) {
1419
+ const program = new Program(vaultsIdl, { connection });
1420
+ const ix = await program.methods.getExchangePrices().accounts({
1421
+ vaultState: getVaultState(vaultId),
1422
+ vaultConfig: getVaultConfig(vaultId),
1423
+ supplyTokenReserves: getReserve(vaultConfig.supplyToken),
1424
+ borrowTokenReserves: getReserve(vaultConfig.borrowToken)
1425
+ }).instruction();
1426
+ const transaction = new Transaction().add(ix);
1427
+ const latestBlockHash = await connection.getLatestBlockhash();
1428
+ transaction.recentBlockhash = latestBlockHash.blockhash;
1429
+ transaction.feePayer = signer;
1430
+ const raw = await connection.simulateTransaction(transaction);
1431
+ if (raw.value.err && raw.value.err === "InvalidAccountForFee" && signer.toBase58() !== "HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD") {
1432
+ return await getExchangePrices({
1433
+ vaultId,
1434
+ vaultConfig,
1435
+ connection,
1436
+ signer: new PublicKey("HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD")
1437
+ });
1438
+ }
1439
+ const returnLog = raw.value.logs?.find(
1440
+ (log) => log.startsWith("Program return:")
1441
+ );
1442
+ if (!returnLog) {
1443
+ let error = new Error("No return data found in logs");
1444
+ error.simulation = raw.value;
1445
+ throw error;
1446
+ }
1447
+ const base64Data = returnLog.split(" ")[3];
1448
+ const buffer = Buffer.from(base64Data, "base64");
1449
+ const liquiditySupplyExchangePrice = new BN(buffer.subarray(0, 16), "le");
1450
+ const liquidityBorrowExchangePrice = new BN(buffer.subarray(16, 32), "le");
1451
+ const vaultSupplyExchangePrice = new BN(buffer.subarray(32, 48), "le");
1452
+ const vaultBorrowExchangePrice = new BN(buffer.subarray(48, 64), "le");
1453
+ return {
1454
+ liquiditySupplyExchangePrice,
1455
+ liquidityBorrowExchangePrice,
1456
+ vaultSupplyExchangePrice,
1457
+ vaultBorrowExchangePrice
1458
+ };
1459
+ }
1460
+ async function loadRelevantTicksHasDebtArraysLiquidate(vaultId, topTick, nextTick, program) {
1461
+ const { arrayIndex: topTickIndex } = getTickIndices(topTick);
1462
+ const { arrayIndex: nextTickIndex } = getTickIndices(nextTick);
1463
+ const promises = [];
1464
+ for (let arrIdx = topTickIndex; arrIdx >= nextTickIndex; arrIdx--) {
1465
+ promises.push(
1466
+ program.account.tickHasDebtArray.fetch(
1467
+ getTickHasDebt(vaultId, arrIdx)
1468
+ )
1469
+ );
1470
+ }
1471
+ const results = await Promise.allSettled(promises);
1472
+ const tickHasDebtArrays = results.filter((result) => result.status === "fulfilled").map(
1473
+ (result) => result.value
1474
+ );
1475
+ return tickHasDebtArrays;
1476
+ }
1477
+ async function loadRelevantBranchesForLiquidate(vaultId, vaultState, program) {
1478
+ const branches = [];
1479
+ const currentBranchId = vaultState.currentBranchId;
1480
+ if (currentBranchId > 0) {
1481
+ try {
1482
+ const currentBranch = await program.account.branch.fetch(
1483
+ getBranch(vaultId, currentBranchId)
1484
+ );
1485
+ if (currentBranch) branches.push(currentBranch);
1486
+ } catch (error) {
1487
+ console.warn(`Failed to fetch current branch ${currentBranchId}:`, error);
1488
+ }
1489
+ }
1490
+ let connectedBranchId = branches[0].connectedBranchId;
1491
+ const doesBranchExist = (branchId) => branches.some((b) => b.branchId === branchId);
1492
+ while (!doesBranchExist(connectedBranchId)) {
1493
+ try {
1494
+ const connectedBranch = await program.account.branch.fetch(
1495
+ getBranch(vaultId, connectedBranchId)
1496
+ );
1497
+ connectedBranchId = connectedBranch.connectedBranchId;
1498
+ if (connectedBranch) branches.push(connectedBranch);
1499
+ } catch (error) {
1500
+ console.warn(`Failed to fetch connected branch ${connectedBranchId}:`, error);
1501
+ }
1502
+ }
1503
+ if (!doesBranchExist(0)) branches.push({ branchId: 0 });
1504
+ return branches;
1505
+ }
1506
+ async function readOraclePrice({
1507
+ connection,
1508
+ signer,
1509
+ oracle: oracle$1
1510
+ }) {
1511
+ const program = new Program(
1512
+ oracle,
1513
+ new AnchorProvider(connection, {
1514
+ signTransaction() {
1515
+ throw new Error("Not implemented");
1516
+ },
1517
+ signAllTransactions() {
1518
+ throw new Error("Not implemented");
1519
+ },
1520
+ publicKey: signer ?? new PublicKey("HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD")
1521
+ })
1522
+ );
1523
+ const oracleData = await program.account.oracle.fetch(oracle$1);
1524
+ let remainingAccounts = [];
1525
+ for (const source of oracleData.sources) {
1526
+ remainingAccounts.push({
1527
+ pubkey: source.source,
1528
+ isWritable: false,
1529
+ isSigner: false
1530
+ });
1531
+ }
1532
+ const [oraclePriceOperate, oraclePriceLiquidate] = await Promise.all([
1533
+ program.methods.getExchangeRateOperate(oracleData.nonce).accounts({ oracle: oracle$1 }).remainingAccounts(remainingAccounts).view(),
1534
+ program.methods.getExchangeRateLiquidate(oracleData.nonce).accounts({ oracle: oracle$1 }).remainingAccounts(remainingAccounts).view()
1535
+ ]);
1536
+ return {
1537
+ oraclePriceOperate,
1538
+ oraclePriceLiquidate,
1539
+ oracleSources: oracleData.sources
1540
+ };
1541
+ }
1542
+
1543
+ const MPL_TOKEN_METADATA_PROGRAM_ID = new PublicKey(
1544
+ "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
1545
+ );
1546
+ const LIQUIDITY_PROGRAM_ID = new PublicKey(liquidity.address);
1547
+ const MIN_I128 = new BN("170141183460469231731687303715884105728").neg();
1548
+ async function getOtherInstructionsOperate(vaultId, vaultState, currentPosition, finalPosition, currentTick, program, signer) {
1549
+ const otherIxs = [];
1550
+ const tickToRead = [currentTick];
1551
+ let currentTickData;
1552
+ let finalTickData;
1553
+ tickToRead.push(currentPosition.tick);
1554
+ tickToRead.push(finalPosition.tick);
1555
+ if (tickToRead.length > 0) {
1556
+ const tickData = await program.account.tick.fetchMultiple(
1557
+ tickToRead.map((tick) => getTick(vaultId, tick))
1558
+ );
1559
+ currentTickData = tickData[0];
1560
+ finalTickData = tickData[2];
1561
+ for (const [i, tickDatum] of tickData.entries()) {
1562
+ if (!tickDatum) {
1563
+ const ix = await program.methods.initTick(vaultId, tickToRead[i]).accounts(getInitTickContext(vaultId, tickToRead[i], signer)).instruction();
1564
+ otherIxs.push(ix);
1565
+ }
1566
+ }
1567
+ }
1568
+ let newBranchId;
1569
+ if (vaultState.branchLiquidated) {
1570
+ newBranchId = vaultState.totalBranchId + 1;
1571
+ const newBranchData = await program.account.branch.fetch(
1572
+ getBranch(vaultId, newBranchId)
1573
+ );
1574
+ if (!newBranchData) {
1575
+ const ix = await program.methods.initBranch(vaultId, newBranchId).accounts(getInitBranchContext(vaultId, newBranchId, signer)).instruction();
1576
+ otherIxs.push(ix);
1577
+ }
1578
+ } else {
1579
+ newBranchId = vaultState.currentBranchId;
1580
+ }
1581
+ const newBranchPda = getBranch(vaultId, newBranchId);
1582
+ const currentTickIdDataPda = getTickIdLiquidation(
1583
+ vaultId,
1584
+ currentTick,
1585
+ currentTickData ? currentTickData.totalIds : 0
1586
+ );
1587
+ const tickIdsToRead = [
1588
+ {
1589
+ tick: currentTick,
1590
+ totalIds: currentTickData ? currentTickData.totalIds : 0
1591
+ }
1592
+ ];
1593
+ const finalTickIdDataPda = getTickIdLiquidation(
1594
+ vaultId,
1595
+ finalPosition.tick,
1596
+ finalTickData ? finalTickData.totalIds : 0
1597
+ );
1598
+ if (finalPosition.tick !== currentTick)
1599
+ if (finalTickData) {
1600
+ tickIdsToRead.push({
1601
+ tick: finalPosition.tick,
1602
+ totalIds: finalTickData.totalIds
1603
+ });
1604
+ } else {
1605
+ const context = await getInitTickIdLiquidationContext(
1606
+ vaultId,
1607
+ finalPosition.tick,
1608
+ signer,
1609
+ program
1610
+ );
1611
+ const ix = await program.methods.initTickIdLiquidation(vaultId, finalPosition.tick, 0).accounts(context).instruction();
1612
+ otherIxs.push(ix);
1613
+ }
1614
+ const tickIdData = await program.account.tickIdLiquidation.fetchMultiple(
1615
+ tickIdsToRead.map(
1616
+ ({ tick, totalIds }) => getTickIdLiquidation(vaultId, tick, totalIds)
1617
+ )
1618
+ );
1619
+ if (tickIdData.length > 0) {
1620
+ for (const [i, tickIdDatum] of tickIdData.entries()) {
1621
+ if (!tickIdDatum) {
1622
+ const ix = await program.methods.initTickIdLiquidation(
1623
+ vaultId,
1624
+ tickIdsToRead[i].tick,
1625
+ tickIdsToRead[i].totalIds
1626
+ ).accounts(
1627
+ await getInitTickIdLiquidationContext(
1628
+ vaultId,
1629
+ tickIdsToRead[i].tick,
1630
+ signer,
1631
+ program
1632
+ )
1633
+ ).instruction();
1634
+ otherIxs.push(ix);
1635
+ }
1636
+ }
1637
+ }
1638
+ return {
1639
+ otherIxs,
1640
+ newBranchPda,
1641
+ currentTickIdDataPda,
1642
+ finalTickIdDataPda
1643
+ };
1644
+ }
1645
+ const tickHelper = (tickValue) => {
1646
+ return tickValue === 0 ? INIT_TICK : tickValue;
1647
+ };
1648
+ async function getRemainingAccountsOperate(vaultId, vaultState, vaultConfig, finalPositionTick, existingPositionTick, liquidationStatus, postLiquidationBranchId, program) {
1649
+ const remainingAccounts = [];
1650
+ const oracleProgram = new Program(oracle, program.provider);
1651
+ const [oracleData, branches, tickHasDebt] = await Promise.all([
1652
+ oracleProgram.account.oracle.fetch(new PublicKey(vaultConfig.oracle)),
1653
+ // Add branch accounts (next 10 remaining accounts)
1654
+ loadRelevantBranches(
1655
+ vaultId,
1656
+ vaultState,
1657
+ liquidationStatus,
1658
+ postLiquidationBranchId,
1659
+ program
1660
+ ),
1661
+ loadRelevantTicksHasDebtArrays(
1662
+ vaultId,
1663
+ tickHelper(vaultState.topmostTick),
1664
+ existingPositionTick,
1665
+ finalPositionTick,
1666
+ program
1667
+ )
1668
+ ]);
1669
+ const sourceLength = oracleData.sources.length;
1670
+ for (const source of oracleData.sources)
1671
+ remainingAccounts.push({
1672
+ pubkey: new PublicKey(source.source),
1673
+ isWritable: false,
1674
+ isSigner: false
1675
+ });
1676
+ const branchLength = branches.length;
1677
+ for (const branch of branches) {
1678
+ remainingAccounts.push({
1679
+ pubkey: getBranch(vaultId, branch),
1680
+ isWritable: true,
1681
+ isSigner: false
1682
+ });
1683
+ }
1684
+ const tickHasDebtLength = tickHasDebt.length;
1685
+ for (const tickHasDebtArray of tickHasDebt)
1686
+ remainingAccounts.push({
1687
+ pubkey: tickHasDebtArray,
1688
+ isWritable: true,
1689
+ isSigner: false
1690
+ });
1691
+ const remainingAccountsIndices = [
1692
+ sourceLength,
1693
+ branchLength,
1694
+ tickHasDebtLength
1695
+ ];
1696
+ return {
1697
+ remainingAccounts,
1698
+ remainingAccountsIndices
1699
+ };
1700
+ }
1701
+ async function getOperateContext({
1702
+ vaultId,
1703
+ positionId,
1704
+ program,
1705
+ connection,
1706
+ signer,
1707
+ positionOwner = signer,
1708
+ colAmount: newCol,
1709
+ debtAmount: newDebt,
1710
+ recipient
1711
+ }) {
1712
+ program = program ?? getVaultsProgram({ connection, signer });
1713
+ const [vaultState, vaultConfig, vaultMetadata] = await Promise.all([
1714
+ program.account.vaultState.fetch(getVaultState(vaultId)),
1715
+ program.account.vaultConfig.fetch(getVaultConfig(vaultId)),
1716
+ program.account.vaultMetadata.fetch(getVaultMetadata(vaultId))
1717
+ ]);
1718
+ const [supplyTokenProgram, borrowTokenProgram] = await Promise.all([
1719
+ getAccountOwner(vaultConfig.supplyToken, connection),
1720
+ getAccountOwner(vaultConfig.borrowToken, connection)
1721
+ ]);
1722
+ const vaultSupplyDecimals = vaultMetadata.supplyMintDecimals;
1723
+ const vaultBorrowDecimals = vaultMetadata.borrowMintDecimals;
1724
+ if (newCol.gt(MIN_I128)) {
1725
+ const decimalsDelta = vaultSupplyDecimals < 9 ? 9 - vaultSupplyDecimals : 0;
1726
+ newCol = newCol.mul(new BN(10).pow(new BN(decimalsDelta)));
1727
+ }
1728
+ if (newDebt.gt(MIN_I128)) {
1729
+ const decimalsDelta = vaultBorrowDecimals < 9 ? 9 - vaultBorrowDecimals : 0;
1730
+ newDebt = newDebt.mul(new BN(10).pow(new BN(decimalsDelta)));
1731
+ }
1732
+ const positionData = positionId === 0 ? {
1733
+ nftId: vaultState.nextPositionId,
1734
+ positionMint: new PublicKey(0),
1735
+ isSupplyOnlyPosition: 1,
1736
+ tick: -2147483648,
1737
+ tickId: 0,
1738
+ lastUpdateTimestamp: new BN(0),
1739
+ supplyAmount: new BN(0),
1740
+ dustDebtAmount: new BN(0)} : await program.account.position.fetch(
1741
+ getPosition(vaultId, positionId)
1742
+ );
1743
+ let existingPositionTick = positionData.tick;
1744
+ const currentPosition = await getCurrentPositionState({
1745
+ vaultId,
1746
+ position: positionData,
1747
+ program
1748
+ });
1749
+ if (existingPositionTick === -2147483648) {
1750
+ existingPositionTick = currentPosition.tick;
1751
+ }
1752
+ const currentPositionTickPda = getTick(
1753
+ vaultId,
1754
+ existingPositionTick
1755
+ );
1756
+ const finalPosition = await getFinalPosition({
1757
+ vaultId,
1758
+ currentPosition,
1759
+ newColAmount: newCol,
1760
+ newDebtAmount: newDebt,
1761
+ program,
1762
+ connection,
1763
+ signer
1764
+ });
1765
+ const { otherIxs, newBranchPda, currentTickIdDataPda, finalTickIdDataPda } = await getOtherInstructionsOperate(
1766
+ vaultId,
1767
+ vaultState,
1768
+ currentPosition,
1769
+ finalPosition,
1770
+ existingPositionTick,
1771
+ program,
1772
+ signer
1773
+ );
1774
+ const { remainingAccounts, remainingAccountsIndices } = await getRemainingAccountsOperate(
1775
+ vaultId,
1776
+ vaultState,
1777
+ vaultConfig,
1778
+ finalPosition.tick,
1779
+ existingPositionTick,
1780
+ currentPosition.userLiquidationStatus,
1781
+ currentPosition.postLiquidationBranchId,
1782
+ program
1783
+ );
1784
+ const accounts = {
1785
+ signer,
1786
+ signerSupplyTokenAccount: getAssociatedTokenAddressSync(
1787
+ vaultConfig.supplyToken,
1788
+ signer,
1789
+ false,
1790
+ supplyTokenProgram
1791
+ ),
1792
+ signerBorrowTokenAccount: getAssociatedTokenAddressSync(
1793
+ vaultConfig.borrowToken,
1794
+ signer,
1795
+ false,
1796
+ borrowTokenProgram
1797
+ ),
1798
+ recipient: recipient ?? null,
1799
+ recipientSupplyTokenAccount: recipient ? getAssociatedTokenAddressSync(
1800
+ vaultConfig.supplyToken,
1801
+ recipient,
1802
+ false,
1803
+ supplyTokenProgram
1804
+ ) : null,
1805
+ recipientBorrowTokenAccount: recipient ? getAssociatedTokenAddressSync(
1806
+ vaultConfig.borrowToken,
1807
+ recipient,
1808
+ false,
1809
+ borrowTokenProgram
1810
+ ) : null,
1811
+ vaultConfig: getVaultConfig(vaultId),
1812
+ vaultState: getVaultState(vaultId),
1813
+ supplyToken: vaultConfig.supplyToken,
1814
+ borrowToken: vaultConfig.borrowToken,
1815
+ oracle: new PublicKey(vaultConfig.oracle),
1816
+ position: getPosition(vaultId, positionData.nftId),
1817
+ positionTokenAccount: getPositionTokenAccount(
1818
+ vaultId,
1819
+ positionData.nftId,
1820
+ positionOwner
1821
+ ),
1822
+ currentPositionTick: currentPositionTickPda,
1823
+ finalPositionTick: getTick(vaultId, finalPosition.tick),
1824
+ currentPositionTickId: currentTickIdDataPda,
1825
+ finalPositionTickId: finalTickIdDataPda,
1826
+ newBranch: newBranchPda,
1827
+ supplyTokenReservesLiquidity: getLiquidityReserve(
1828
+ vaultConfig.supplyToken
1829
+ ),
1830
+ borrowTokenReservesLiquidity: getLiquidityReserve(
1831
+ vaultConfig.borrowToken
1832
+ ),
1833
+ vaultSupplyPositionOnLiquidity: getUserSupplyPosition(
1834
+ vaultConfig.supplyToken,
1835
+ getVaultConfig(vaultId)
1836
+ ),
1837
+ vaultBorrowPositionOnLiquidity: getUserBorrowPosition(
1838
+ vaultConfig.borrowToken,
1839
+ getVaultConfig(vaultId)
1840
+ ),
1841
+ supplyRateModel: getRateModel(vaultConfig.supplyToken),
1842
+ borrowRateModel: getRateModel(vaultConfig.borrowToken),
1843
+ supplyTokenClaimAccount: null,
1844
+ borrowTokenClaimAccount: null,
1845
+ liquidity: getLiquidity(),
1846
+ liquidityProgram: LIQUIDITY_PROGRAM_ID,
1847
+ vaultSupplyTokenAccount: getAssociatedTokenAddressSync(
1848
+ vaultConfig.supplyToken,
1849
+ getLiquidity(),
1850
+ true,
1851
+ supplyTokenProgram
1852
+ ),
1853
+ vaultBorrowTokenAccount: getAssociatedTokenAddressSync(
1854
+ vaultConfig.borrowToken,
1855
+ getLiquidity(),
1856
+ true,
1857
+ borrowTokenProgram
1858
+ ),
1859
+ oracleProgram: new PublicKey(vaultConfig.oracleProgram),
1860
+ supplyTokenProgram,
1861
+ borrowTokenProgram,
1862
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
1863
+ systemProgram: SystemProgram.programId
1864
+ };
1865
+ return {
1866
+ nftId: positionData.nftId,
1867
+ accounts,
1868
+ remainingAccounts,
1869
+ initPositionIx: positionId === 0 ? await program.methods.initPosition(vaultId, positionData.nftId).accounts(
1870
+ getInitPositionContext(vaultId, positionData.nftId, signer)
1871
+ ).instruction() : null,
1872
+ otherIxs,
1873
+ remainingAccountsIndices,
1874
+ lookupTable: vaultMetadata.lookupTable
1875
+ };
1876
+ }
1877
+ async function getInitPositionIx({
1878
+ vaultId,
1879
+ connection,
1880
+ signer
1881
+ }) {
1882
+ const program = getVaultsProgram({ connection, signer });
1883
+ const vaultState = await program.account.vaultState.fetch(
1884
+ getVaultState(vaultId)
1885
+ );
1886
+ return {
1887
+ ix: await program.methods.initPosition(vaultId, vaultState.nextPositionId).accounts(
1888
+ getInitPositionContext(vaultId, vaultState.nextPositionId, signer)
1889
+ ).instruction(),
1890
+ nftId: vaultState.nextPositionId
1891
+ };
1892
+ }
1893
+ function getInitPositionContext(vaultId, positionId, signer) {
1894
+ return {
1895
+ signer,
1896
+ vaultAdmin: getVaultAdmin(),
1897
+ vaultState: getVaultState(vaultId),
1898
+ position: getPosition(vaultId, positionId),
1899
+ positionMint: getPositionMint(vaultId, positionId),
1900
+ positionTokenAccount: getPositionTokenAccount(
1901
+ vaultId,
1902
+ positionId,
1903
+ signer
1904
+ ),
1905
+ tokenProgram: TOKEN_PROGRAM_ID,
1906
+ metadataAccount: getPositionMetadata(vaultId, positionId),
1907
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
1908
+ systemProgram: SystemProgram.programId,
1909
+ sysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY,
1910
+ metadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID,
1911
+ rent: SYSVAR_RENT_PUBKEY
1912
+ };
1913
+ }
1914
+ const getOperateIx = async ({
1915
+ vaultId,
1916
+ positionId,
1917
+ colAmount,
1918
+ debtAmount,
1919
+ connection,
1920
+ signer,
1921
+ recipient,
1922
+ positionOwner
1923
+ }) => {
1924
+ const program = getVaultsProgram({ connection, signer });
1925
+ const {
1926
+ accounts,
1927
+ remainingAccounts,
1928
+ remainingAccountsIndices,
1929
+ initPositionIx,
1930
+ otherIxs,
1931
+ lookupTable,
1932
+ nftId
1933
+ } = await getOperateContext({
1934
+ vaultId,
1935
+ positionId,
1936
+ colAmount,
1937
+ debtAmount,
1938
+ signer,
1939
+ positionOwner,
1940
+ connection,
1941
+ recipient,
1942
+ program
1943
+ });
1944
+ const [operateIx, addressLookupTable] = await Promise.all([
1945
+ program.methods.operate(
1946
+ colAmount,
1947
+ debtAmount,
1948
+ { direct: {} },
1949
+ Buffer.from(remainingAccountsIndices)
1950
+ ).accounts(accounts).remainingAccounts(remainingAccounts).instruction(),
1951
+ connection.getAddressLookupTable(lookupTable)
1952
+ ]);
1953
+ return {
1954
+ nftId,
1955
+ accounts,
1956
+ remainingAccounts,
1957
+ remainingAccountsIndices,
1958
+ addressLookupTableAddresses: lookupTable ? [lookupTable] : [],
1959
+ addressLookupTableAccounts: addressLookupTable.value ? [addressLookupTable.value] : [],
1960
+ ixs: initPositionIx ? [initPositionIx, ...otherIxs, operateIx] : [...otherIxs, operateIx]
1961
+ };
1962
+ };
1963
+ function getInitBranchContext(vaultId, branchId, signer) {
1964
+ return {
1965
+ signer,
1966
+ vaultConfig: getVaultConfig(vaultId),
1967
+ branch: getBranch(vaultId, branchId),
1968
+ systemProgram: SystemProgram.programId
1969
+ };
1970
+ }
1971
+ function getInitTickContext(vaultId, tick, signer) {
1972
+ return {
1973
+ signer,
1974
+ vaultConfig: getVaultConfig(vaultId),
1975
+ tickData: getTick(vaultId, tick),
1976
+ systemProgram: SystemProgram.programId
1977
+ };
1978
+ }
1979
+ async function getInitTickIdLiquidationContext(vaultId, tick, signer, program) {
1980
+ const tickData = await program.account.tick.fetch(getTick(vaultId, tick)).catch(() => null);
1981
+ if (!tickData) {
1982
+ return {
1983
+ signer,
1984
+ vaultConfig: getVaultConfig(vaultId),
1985
+ tickIdLiquidation: getTickIdLiquidation(vaultId, tick, 0),
1986
+ tickData: getTick(vaultId, tick),
1987
+ systemProgram: SystemProgram.programId
1988
+ };
1989
+ }
1990
+ return {
1991
+ signer,
1992
+ vaultConfig: getVaultConfig(vaultId),
1993
+ tickIdLiquidation: getTickIdLiquidation(
1994
+ vaultId,
1995
+ tick,
1996
+ tickData.totalIds
1997
+ ),
1998
+ tickData: getTick(vaultId, tick),
1999
+ systemProgram: SystemProgram.programId
2000
+ };
2001
+ }
2002
+ async function getLiquidateContext({
2003
+ vaultId,
2004
+ to,
2005
+ program,
2006
+ connection,
2007
+ signer
2008
+ }) {
2009
+ program = program ?? getVaultsProgram({ connection, signer });
2010
+ const [vaultState, vaultConfig, vaultMetadata] = await Promise.all([
2011
+ program.account.vaultState.fetch(getVaultState(vaultId)),
2012
+ program.account.vaultConfig.fetch(getVaultConfig(vaultId)),
2013
+ program.account.vaultMetadata.fetch(getVaultMetadata(vaultId))
2014
+ ]);
2015
+ const [supplyTokenProgram, borrowTokenProgram] = await Promise.all([
2016
+ getAccountOwner(vaultConfig.supplyToken, connection),
2017
+ getAccountOwner(vaultConfig.borrowToken, connection)
2018
+ ]);
2019
+ const { arrayIndex } = getTickIndices(vaultState.topmostTick);
2020
+ let { otherIxs, newBranchPda } = await getOtherInstructionsLiquidate(
2021
+ vaultId,
2022
+ vaultState,
2023
+ program,
2024
+ signer
2025
+ );
2026
+ const {
2027
+ remainingAccounts,
2028
+ remainingAccountsIndices,
2029
+ otherIxs: finalOtherIxs
2030
+ } = await getRemainingAccountsLiquidate(
2031
+ vaultId,
2032
+ vaultState,
2033
+ vaultConfig,
2034
+ otherIxs,
2035
+ program,
2036
+ connection,
2037
+ signer
2038
+ );
2039
+ return {
2040
+ accounts: {
2041
+ signer,
2042
+ signerTokenAccount: getAssociatedTokenAddressSync(
2043
+ vaultConfig.borrowToken,
2044
+ signer,
2045
+ false,
2046
+ borrowTokenProgram
2047
+ ),
2048
+ to,
2049
+ toTokenAccount: getAssociatedTokenAddressSync(
2050
+ vaultConfig.supplyToken,
2051
+ to,
2052
+ false,
2053
+ supplyTokenProgram
2054
+ ),
2055
+ vaultAdmin: getVaultAdmin(),
2056
+ vaultConfig: getVaultConfig(vaultId),
2057
+ vaultState: getVaultState(vaultId),
2058
+ supplyToken: vaultConfig.supplyToken,
2059
+ borrowToken: vaultConfig.borrowToken,
2060
+ oracle: new PublicKey(vaultConfig.oracle),
2061
+ tickHasDebt: getTickHasDebt(vaultId, arrayIndex),
2062
+ newBranch: newBranchPda,
2063
+ supplyTokenReservesLiquidity: getLiquidityReserve(
2064
+ vaultConfig.supplyToken
2065
+ ),
2066
+ borrowTokenReservesLiquidity: getLiquidityReserve(
2067
+ vaultConfig.borrowToken
2068
+ ),
2069
+ vaultSupplyPositionOnLiquidity: getUserSupplyPosition(
2070
+ vaultConfig.supplyToken,
2071
+ getVaultConfig(vaultId)
2072
+ ),
2073
+ vaultBorrowPositionOnLiquidity: getUserBorrowPosition(
2074
+ vaultConfig.borrowToken,
2075
+ getVaultConfig(vaultId)
2076
+ ),
2077
+ supplyRateModel: getRateModel(vaultConfig.supplyToken),
2078
+ borrowRateModel: getRateModel(vaultConfig.borrowToken),
2079
+ supplyTokenClaimAccount: getClaimAccount(
2080
+ vaultConfig.supplyToken,
2081
+ getVaultConfig(vaultId)
2082
+ ),
2083
+ borrowTokenClaimAccount: getClaimAccount(
2084
+ vaultConfig.borrowToken,
2085
+ getVaultConfig(vaultId)
2086
+ ),
2087
+ liquidity: getLiquidity(),
2088
+ liquidityProgram: LIQUIDITY_PROGRAM_ID,
2089
+ vaultSupplyTokenAccount: getAssociatedTokenAddressSync(
2090
+ vaultConfig.supplyToken,
2091
+ getLiquidity(),
2092
+ true,
2093
+ supplyTokenProgram
2094
+ ),
2095
+ vaultBorrowTokenAccount: getAssociatedTokenAddressSync(
2096
+ vaultConfig.borrowToken,
2097
+ getLiquidity(),
2098
+ true,
2099
+ borrowTokenProgram
2100
+ ),
2101
+ oracleProgram: new PublicKey(vaultConfig.oracleProgram),
2102
+ supplyTokenProgram,
2103
+ borrowTokenProgram,
2104
+ systemProgram: SystemProgram.programId,
2105
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID
2106
+ },
2107
+ remainingAccounts,
2108
+ otherIxs: finalOtherIxs,
2109
+ remainingAccountsIndices,
2110
+ lookupTable: vaultMetadata.lookupTable
2111
+ };
2112
+ }
2113
+ const getLiquidateIx = async ({
2114
+ vaultId,
2115
+ debtAmount,
2116
+ colPerUnitDebt = new BN(0),
2117
+ absorb = false,
2118
+ signer,
2119
+ to = signer,
2120
+ connection
2121
+ }) => {
2122
+ const program = getVaultsProgram({ connection, signer });
2123
+ const {
2124
+ accounts,
2125
+ remainingAccounts,
2126
+ remainingAccountsIndices,
2127
+ otherIxs,
2128
+ lookupTable
2129
+ } = await getLiquidateContext({
2130
+ vaultId,
2131
+ to,
2132
+ program,
2133
+ signer,
2134
+ connection
2135
+ });
2136
+ const ixs = [];
2137
+ if (otherIxs.length > 0) {
2138
+ ixs.push(...otherIxs);
2139
+ }
2140
+ const [ix, addressLookupTable] = await Promise.all([
2141
+ program.methods.liquidate(
2142
+ debtAmount,
2143
+ colPerUnitDebt,
2144
+ absorb,
2145
+ { direct: {} },
2146
+ Buffer.from(remainingAccountsIndices)
2147
+ ).accounts(accounts).remainingAccounts(remainingAccounts).instruction(),
2148
+ connection.getAddressLookupTable(lookupTable)
2149
+ ]);
2150
+ ixs.push(ix);
2151
+ return {
2152
+ accounts,
2153
+ remainingAccounts,
2154
+ remainingAccountsIndices,
2155
+ ixs,
2156
+ addressLookupTableAddresses: lookupTable ? [lookupTable] : [],
2157
+ addressLookupTableAccounts: addressLookupTable.value ? [addressLookupTable.value] : []
2158
+ };
2159
+ };
2160
+ async function getOtherInstructionsLiquidate(vaultId, vaultState, program, signer) {
2161
+ const otherIxs = [];
2162
+ let newBranchId = vaultState.branchLiquidated === 1 ? vaultState.totalBranchId + 1 : vaultState.currentBranchId;
2163
+ let newBranchPda = getBranch(vaultId, newBranchId);
2164
+ const [newBranchData, tickData] = await Promise.all([
2165
+ program.account.branch.fetch(newBranchPda).catch(() => null),
2166
+ // might be possible that liquidation ends on a tick that is not initialized
2167
+ program.account.tick.fetch(getTick(vaultId, vaultState.topmostTick)).catch(() => null)
2168
+ ]);
2169
+ if (!newBranchData) {
2170
+ const ix = await program.methods.initBranch(vaultId, newBranchId).accounts(getInitBranchContext(vaultId, newBranchId, signer)).instruction();
2171
+ otherIxs.push(ix);
2172
+ }
2173
+ if (!tickData) {
2174
+ const ix = await program.methods.initTick(vaultId, vaultState.topmostTick).accounts(getInitTickContext(vaultId, vaultState.topmostTick, signer)).instruction();
2175
+ otherIxs.push(ix);
2176
+ }
2177
+ return {
2178
+ otherIxs,
2179
+ newBranchPda
2180
+ };
2181
+ }
2182
+ async function loadRelevantTicksForLiquidate(vaultId, vaultState, liquidationTick, program) {
2183
+ const ticks = [];
2184
+ let topTick = vaultState.topmostTick;
2185
+ if (topTick > liquidationTick)
2186
+ try {
2187
+ const topTickData = await program.account.tick.fetch(
2188
+ getTick(vaultId, topTick)
2189
+ );
2190
+ if (topTickData) ticks.push({ ...topTickData, tick: topTick });
2191
+ } catch {
2192
+ }
2193
+ let nextTick = MIN_TICK$1;
2194
+ try {
2195
+ nextTick = await findNextTickWithDebt(vaultId, topTick, program);
2196
+ } catch {
2197
+ }
2198
+ const doesTickExist = (tick) => ticks.some((t) => t.tick === tick);
2199
+ while (nextTick > liquidationTick && !doesTickExist(nextTick)) {
2200
+ try {
2201
+ const nextTickData = await program.account.tick.fetch(
2202
+ getTick(vaultId, nextTick)
2203
+ );
2204
+ if (nextTickData) ticks.push({ ...nextTickData, tick: nextTick });
2205
+ else throw new Error("Tick not found to load");
2206
+ nextTick = await findNextTickWithDebt(vaultId, nextTick, program);
2207
+ } catch {
2208
+ }
2209
+ }
2210
+ return { ticks, nextTick };
2211
+ }
2212
+ async function getRemainingAccountsLiquidate(vaultId, vaultState, vaultConfig, otherIxs, program, connection, signer) {
2213
+ const remainingAccounts = [];
2214
+ const { oraclePriceLiquidate, oracleSources } = await readOraclePrice({
2215
+ oracle: vaultConfig.oracle,
2216
+ connection
2217
+ // signer,
2218
+ });
2219
+ const liquidationRatio = new BN(oraclePriceLiquidate).mul(new BN(281474976710656)).div(new BN(10).pow(new BN(15)));
2220
+ const liquidationThresholdRatio = liquidationRatio.mul(new BN(vaultConfig.liquidationThreshold)).div(new BN(10).pow(new BN(3)));
2221
+ const liquidationTick = getTickAtRatio(liquidationThresholdRatio);
2222
+ for (const source of oracleSources) {
2223
+ remainingAccounts.push({
2224
+ pubkey: source.source,
2225
+ isWritable: false,
2226
+ isSigner: false
2227
+ });
2228
+ }
2229
+ const [branches, { ticks: tickAccounts, nextTick }] = await Promise.all([
2230
+ loadRelevantBranchesForLiquidate(vaultId, vaultState, program),
2231
+ loadRelevantTicksForLiquidate(
2232
+ vaultId,
2233
+ vaultState,
2234
+ liquidationTick,
2235
+ program
2236
+ )
2237
+ ]);
2238
+ const tickHasDebt = await loadRelevantTicksHasDebtArraysLiquidate(
2239
+ vaultId,
2240
+ vaultState.topmostTick,
2241
+ nextTick,
2242
+ program
2243
+ );
2244
+ for (const branch of branches) {
2245
+ remainingAccounts.push({
2246
+ pubkey: getBranch(vaultId, branch.branchId),
2247
+ isWritable: true,
2248
+ isSigner: false
2249
+ });
2250
+ }
2251
+ const tickToInit = [];
2252
+ const existingTicks = await Promise.all(
2253
+ tickAccounts.map(
2254
+ (tickData) => program.account.tick.fetch(getTick(vaultId, tickData.tick)).catch(() => null)
2255
+ )
2256
+ );
2257
+ const initInstructions = await Promise.all(
2258
+ tickAccounts.map(async (tickData, index) => {
2259
+ const existingTick = existingTicks[index];
2260
+ if (!existingTick && !tickToInit.includes(tickData.tick)) {
2261
+ tickToInit.push(tickData.tick);
2262
+ return program.methods.initTick(vaultId, tickData.tick).accounts(getInitTickContext(vaultId, tickData.tick, signer)).instruction();
2263
+ }
2264
+ return null;
2265
+ })
2266
+ );
2267
+ for (const ix of initInstructions) {
2268
+ if (ix) {
2269
+ otherIxs.push(ix);
2270
+ }
2271
+ }
2272
+ for (const tickData of tickAccounts) {
2273
+ remainingAccounts.push({
2274
+ pubkey: getTick(vaultId, tickData.tick),
2275
+ isWritable: true,
2276
+ isSigner: false
2277
+ });
2278
+ }
2279
+ for (const tickHasDebtArray of tickHasDebt) {
2280
+ remainingAccounts.push({
2281
+ pubkey: getTickHasDebt(vaultId, tickHasDebtArray.index),
2282
+ isWritable: true,
2283
+ isSigner: false
2284
+ });
2285
+ }
2286
+ const remainingAccountsIndices = [
2287
+ oracleSources.length,
2288
+ branches.length,
2289
+ tickAccounts.length,
2290
+ tickHasDebt.length
2291
+ ];
2292
+ return {
2293
+ remainingAccounts,
2294
+ otherIxs,
2295
+ remainingAccountsIndices
2296
+ };
2297
+ }
2298
+
2299
+ export { findNextTickWithDebt as A, INIT_TICK as I, MIN_TICK$1 as M, TICK_HAS_DEBT_ARRAY_SIZE as T, ZERO_TICK_SCALED_RATIO$1 as Z, getVaultsProgram as a, getOperateContext as b, getInitPositionIx as c, getInitPositionContext as d, getOperateIx as e, getLiquidateContext as f, getLiquidateIx as g, getAccountOwner as h, getCurrentPosition as i, getCurrentPositionState as j, getFinalPosition as k, loadRelevantBranches as l, loadRelevantTicksHasDebtArrays as m, loadRelevantTicksHasDebtArraysLiquidate as n, loadRelevantBranchesForLiquidate as o, MAX_TICK$1 as p, TICKS_PER_TICK_HAS_DEBT as q, readOraclePrice as r, TICK_HAS_DEBT_CHILDREN_SIZE as s, TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS as t, TOTAL_INDICES_NEEDED as u, getRatioAtTick as v, getTickAtRatio as w, getFirstTickForIndex as x, getTickIndices as y, readTickHasDebtArray as z };