@jup-ag/lend 0.1.8 → 0.1.10-beta.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.
@@ -1,2327 +0,0 @@
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, NATIVE_MINT } 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.CsYeVtpe.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
- code: 6024,
494
- name: "JupLendAccountMismatch",
495
- msg: "JUP_LEND_ACCOUNT_MISMATCH"
496
- }
497
- ];
498
- const types = [
499
- {
500
- name: "AddressBool",
501
- type: {
502
- kind: "struct",
503
- fields: [
504
- {
505
- name: "addr",
506
- type: "pubkey"
507
- },
508
- {
509
- name: "value",
510
- type: "bool"
511
- }
512
- ]
513
- }
514
- },
515
- {
516
- name: "LogStakePoolHighFeeDetected",
517
- type: {
518
- kind: "struct",
519
- fields: [
520
- {
521
- name: "stake_pool",
522
- type: "pubkey"
523
- },
524
- {
525
- name: "epoch",
526
- type: "u64"
527
- }
528
- ]
529
- }
530
- },
531
- {
532
- name: "LogUpdateAuthority",
533
- type: {
534
- kind: "struct",
535
- fields: [
536
- {
537
- name: "new_authority",
538
- type: "pubkey"
539
- }
540
- ]
541
- }
542
- },
543
- {
544
- name: "LogUpdateAuths",
545
- type: {
546
- kind: "struct",
547
- fields: [
548
- {
549
- name: "auth_status",
550
- type: {
551
- vec: {
552
- defined: {
553
- name: "AddressBool"
554
- }
555
- }
556
- }
557
- }
558
- ]
559
- }
560
- },
561
- {
562
- name: "Oracle",
563
- type: {
564
- kind: "struct",
565
- fields: [
566
- {
567
- name: "nonce",
568
- type: "u16"
569
- },
570
- {
571
- name: "sources",
572
- type: {
573
- vec: {
574
- defined: {
575
- name: "Sources"
576
- }
577
- }
578
- }
579
- },
580
- {
581
- name: "bump",
582
- type: "u8"
583
- }
584
- ]
585
- }
586
- },
587
- {
588
- name: "OracleAdmin",
589
- type: {
590
- kind: "struct",
591
- fields: [
592
- {
593
- name: "authority",
594
- type: "pubkey"
595
- },
596
- {
597
- name: "auths",
598
- type: {
599
- vec: "pubkey"
600
- }
601
- }
602
- ]
603
- }
604
- },
605
- {
606
- name: "SourceType",
607
- type: {
608
- kind: "enum",
609
- variants: [
610
- {
611
- name: "Pyth"
612
- },
613
- {
614
- name: "StakePool"
615
- },
616
- {
617
- name: "MsolPool"
618
- },
619
- {
620
- name: "Redstone"
621
- },
622
- {
623
- name: "Chainlink"
624
- },
625
- {
626
- name: "SinglePool"
627
- },
628
- {
629
- name: "JupLend"
630
- }
631
- ]
632
- }
633
- },
634
- {
635
- name: "Sources",
636
- type: {
637
- kind: "struct",
638
- fields: [
639
- {
640
- name: "source",
641
- type: "pubkey"
642
- },
643
- {
644
- name: "invert",
645
- type: "bool"
646
- },
647
- {
648
- name: "multiplier",
649
- type: "u128"
650
- },
651
- {
652
- name: "divisor",
653
- type: "u128"
654
- },
655
- {
656
- name: "source_type",
657
- type: {
658
- defined: {
659
- name: "SourceType"
660
- }
661
- }
662
- }
663
- ]
664
- }
665
- }
666
- ];
667
- const oracle = {
668
- address: address,
669
- metadata: metadata,
670
- instructions: instructions,
671
- accounts: accounts,
672
- events: events,
673
- errors: errors,
674
- types: types
675
- };
676
-
677
- const MIN_TICK$1 = -16383;
678
- const MAX_TICK$1 = 16383;
679
- const ZERO_TICK_SCALED_RATIO$1 = new BN(281474976710656);
680
- const TICK_HAS_DEBT_ARRAY_SIZE = 8;
681
- const TICKS_PER_TICK_HAS_DEBT = TICK_HAS_DEBT_ARRAY_SIZE * 256;
682
- const TICK_HAS_DEBT_CHILDREN_SIZE = 32;
683
- const TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS = 256;
684
- const TOTAL_INDICES_NEEDED = 16;
685
- function getRatioAtTick(tick) {
686
- if (tick < MIN_TICK$1 || tick > MAX_TICK$1) {
687
- throw new Error(`Tick ${tick} out of range [${MIN_TICK$1}, ${MAX_TICK$1}]`);
688
- }
689
- const FACTOR00 = new BN("18446744073709551616");
690
- const FACTOR01 = new BN("18419115400608638658");
691
- const FACTOR02 = new BN("18391528108445969703");
692
- const FACTOR03 = new BN("18336477419114433396");
693
- const FACTOR04 = new BN("18226869890870665593");
694
- const FACTOR05 = new BN("18009616477100071088");
695
- const FACTOR06 = new BN("17582847377087825313");
696
- const FACTOR07 = new BN("16759408633341240198");
697
- const FACTOR08 = new BN("15226414841393184936");
698
- const FACTOR09 = new BN("12568272644527235157");
699
- const FACTOR10 = new BN("8563108841104354677");
700
- const FACTOR11 = new BN("3975055583337633975");
701
- const FACTOR12 = new BN("856577552520149366");
702
- const FACTOR13 = new BN("39775317560084773");
703
- const FACTOR14 = new BN("85764505686420");
704
- const FACTOR15 = new BN("398745188");
705
- const absTick = Math.abs(tick);
706
- let factor = FACTOR00;
707
- if (absTick & 1) factor = FACTOR01;
708
- if (absTick & 2) factor = mulShift64(factor, FACTOR02);
709
- if (absTick & 4) factor = mulShift64(factor, FACTOR03);
710
- if (absTick & 8) factor = mulShift64(factor, FACTOR04);
711
- if (absTick & 16) factor = mulShift64(factor, FACTOR05);
712
- if (absTick & 32) factor = mulShift64(factor, FACTOR06);
713
- if (absTick & 64) factor = mulShift64(factor, FACTOR07);
714
- if (absTick & 128) factor = mulShift64(factor, FACTOR08);
715
- if (absTick & 256) factor = mulShift64(factor, FACTOR09);
716
- if (absTick & 512) factor = mulShift64(factor, FACTOR10);
717
- if (absTick & 1024) factor = mulShift64(factor, FACTOR11);
718
- if (absTick & 2048) factor = mulShift64(factor, FACTOR12);
719
- if (absTick & 4096) factor = mulShift64(factor, FACTOR13);
720
- if (absTick & 8192) factor = mulShift64(factor, FACTOR14);
721
- if (absTick & 16384) factor = mulShift64(factor, FACTOR15);
722
- let precision = new BN(0);
723
- if (tick > 0) {
724
- const maxU128 = new BN(2).pow(new BN(128)).sub(new BN(1));
725
- factor = maxU128.div(factor);
726
- if (!factor.mod(new BN(65536)).isZero()) {
727
- precision = new BN(1);
728
- }
729
- }
730
- const ratioX48 = factor.shrn(16).add(precision);
731
- return ratioX48;
732
- }
733
- function mulShift64(n0, n1) {
734
- try {
735
- return n0.mul(n1).shrn(64);
736
- } catch {
737
- const product = n0.mul(n1);
738
- return product.div(new BN(2).pow(new BN(64)));
739
- }
740
- }
741
- function getTickAtRatio(ratioX48) {
742
- const MIN_RATIOX48 = new BN(6093);
743
- const MAX_RATIOX48 = new BN("13002088133096036565414295");
744
- const _1E13 = new BN("10000000000000");
745
- if (ratioX48.lt(MIN_RATIOX48) || ratioX48.gt(MAX_RATIOX48)) {
746
- throw new Error(`Ratio ${ratioX48.toString()} out of bounds`);
747
- }
748
- const isNegative = ratioX48.lt(ZERO_TICK_SCALED_RATIO$1);
749
- let factor;
750
- factor = isNegative ? ZERO_TICK_SCALED_RATIO$1.mul(_1E13).div(ratioX48) : ratioX48.mul(_1E13).div(ZERO_TICK_SCALED_RATIO$1);
751
- let tick = 0;
752
- if (factor.gte(new BN("2150859953785115391"))) {
753
- tick |= 8192;
754
- factor = factor.mul(_1E13).div(new BN("2150859953785115391"));
755
- }
756
- if (factor.gte(new BN("4637736467054931"))) {
757
- tick |= 4096;
758
- factor = factor.mul(_1E13).div(new BN("4637736467054931"));
759
- }
760
- if (factor.gte(new BN("215354044936586"))) {
761
- tick |= 2048;
762
- factor = factor.mul(_1E13).div(new BN("215354044936586"));
763
- }
764
- if (factor.gte(new BN("46406254420777"))) {
765
- tick |= 1024;
766
- factor = factor.mul(_1E13).div(new BN("46406254420777"));
767
- }
768
- if (factor.gte(new BN("21542110950596"))) {
769
- tick |= 512;
770
- factor = factor.mul(_1E13).div(new BN("21542110950596"));
771
- }
772
- if (factor.gte(new BN("14677230989051"))) {
773
- tick |= 256;
774
- factor = factor.mul(_1E13).div(new BN("14677230989051"));
775
- }
776
- if (factor.gte(new BN("12114962232319"))) {
777
- tick |= 128;
778
- factor = factor.mul(_1E13).div(new BN("12114962232319"));
779
- }
780
- if (factor.gte(new BN("11006798913544"))) {
781
- tick |= 64;
782
- factor = factor.mul(_1E13).div(new BN("11006798913544"));
783
- }
784
- if (factor.gte(new BN("10491329235871"))) {
785
- tick |= 32;
786
- factor = factor.mul(_1E13).div(new BN("10491329235871"));
787
- }
788
- if (factor.gte(new BN("10242718992470"))) {
789
- tick |= 16;
790
- factor = factor.mul(_1E13).div(new BN("10242718992470"));
791
- }
792
- if (factor.gte(new BN("10120631893548"))) {
793
- tick |= 8;
794
- factor = factor.mul(_1E13).div(new BN("10120631893548"));
795
- }
796
- if (factor.gte(new BN("10060135135051"))) {
797
- tick |= 4;
798
- factor = factor.mul(_1E13).div(new BN("10060135135051"));
799
- }
800
- if (factor.gte(new BN("10030022500000"))) {
801
- tick |= 2;
802
- factor = factor.mul(_1E13).div(new BN("10030022500000"));
803
- }
804
- if (factor.gte(new BN("10015000000000"))) {
805
- tick |= 1;
806
- }
807
- if (isNegative) {
808
- tick = ~tick;
809
- }
810
- return tick;
811
- }
812
- function getFirstTickForIndex(index) {
813
- if (index >= TOTAL_INDICES_NEEDED) {
814
- throw new Error(
815
- `Invalid index: ${index}. Must be between 0 and ${TOTAL_INDICES_NEEDED - 1}`
816
- );
817
- }
818
- return MIN_TICK$1 + index * TICKS_PER_TICK_HAS_DEBT;
819
- }
820
- function getTickIndices(tick) {
821
- if (tick < MIN_TICK$1 || tick > MAX_TICK$1) {
822
- throw new Error("Tick out of range");
823
- }
824
- const tickOffset = tick - MIN_TICK$1;
825
- const arrayIndex = Math.floor(tickOffset / TICKS_PER_TICK_HAS_DEBT);
826
- const firstTickForIndex = getFirstTickForIndex(arrayIndex);
827
- const tickWithinArray = tick - firstTickForIndex;
828
- const mapIndex = Math.floor(
829
- tickWithinArray / TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS
830
- );
831
- const tickWithinMap = tickWithinArray % TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS;
832
- const byteIndex = Math.floor(tickWithinMap / 8);
833
- const bitIndex = tickWithinMap % 8;
834
- return { arrayIndex, mapIndex, byteIndex, bitIndex };
835
- }
836
- async function readTickHasDebtArray({
837
- vaultId,
838
- index,
839
- program
840
- }) {
841
- const tickPda = getTickHasDebt(vaultId, index);
842
- return await program.account.tickHasDebtArray.fetch(tickPda);
843
- }
844
- async function findNextTickWithDebt(vaultId, startTick, program) {
845
- try {
846
- const { arrayIndex, mapIndex, byteIndex, bitIndex } = getTickIndices(startTick);
847
- let currentArrayIndex = arrayIndex;
848
- let currentMapIndex = mapIndex;
849
- let tickHasDebtData = await readTickHasDebtArray({
850
- vaultId,
851
- index: currentArrayIndex,
852
- program
853
- });
854
- if (!tickHasDebtData) {
855
- return MIN_TICK$1;
856
- }
857
- clearBitsInBitmap(tickHasDebtData, mapIndex, byteIndex, bitIndex);
858
- while (true) {
859
- const { nextTick, hasNextTick } = fetchNextTopTickFromBitmap(
860
- tickHasDebtData,
861
- currentMapIndex
862
- );
863
- if (hasNextTick && nextTick !== MIN_TICK$1) {
864
- return nextTick;
865
- }
866
- if (currentArrayIndex === 0) {
867
- return MIN_TICK$1;
868
- }
869
- currentArrayIndex -= 1;
870
- currentMapIndex = TICK_HAS_DEBT_ARRAY_SIZE - 1;
871
- tickHasDebtData = await readTickHasDebtArray({
872
- vaultId,
873
- index: currentArrayIndex,
874
- program
875
- });
876
- if (!tickHasDebtData) {
877
- return MIN_TICK$1;
878
- }
879
- }
880
- } catch (error) {
881
- console.warn(`Error finding next tick with debt:`, error);
882
- return MIN_TICK$1;
883
- }
884
- }
885
- function clearBitsInBitmap(tickHasDebtData, mapIndex, byteIndex, bitIndex) {
886
- const bitmap = [...tickHasDebtData.tickHasDebt[mapIndex].childrenBits];
887
- if (bitIndex > 0) {
888
- const mask = (1 << bitIndex) - 1;
889
- bitmap[byteIndex] &= mask;
890
- } else {
891
- bitmap[byteIndex] = 0;
892
- }
893
- for (let i = byteIndex + 1; i < TICK_HAS_DEBT_CHILDREN_SIZE; i++) {
894
- bitmap[i] = 0;
895
- }
896
- tickHasDebtData.tickHasDebt[mapIndex].childrenBits = bitmap;
897
- }
898
- function fetchNextTopTickFromBitmap(tickHasDebtData, startMapIndex) {
899
- let mapIndex = startMapIndex;
900
- while (mapIndex >= 0) {
901
- if (hasBitsInMap(tickHasDebtData, mapIndex)) {
902
- const { nextTick, hasNextTick } = getNextTickFromMap(
903
- tickHasDebtData,
904
- mapIndex
905
- );
906
- if (hasNextTick) {
907
- return { nextTick, hasNextTick: true };
908
- }
909
- }
910
- mapIndex--;
911
- }
912
- return { nextTick: MIN_TICK$1, hasNextTick: false };
913
- }
914
- function hasBitsInMap(tickHasDebtData, mapIndex) {
915
- const childrenBits = tickHasDebtData.tickHasDebt[mapIndex].childrenBits;
916
- return childrenBits.some((byte) => byte !== 0);
917
- }
918
- function getNextTickFromMap(tickHasDebtData, mapIndex) {
919
- const childrenBits = tickHasDebtData.tickHasDebt[mapIndex].childrenBits;
920
- for (let byteIdx = TICK_HAS_DEBT_CHILDREN_SIZE - 1; byteIdx >= 0; byteIdx--) {
921
- if (childrenBits[byteIdx] !== 0) {
922
- const leadingZeros = getMostSignificantBit(childrenBits[byteIdx]);
923
- const bitPos = 7 - leadingZeros;
924
- const tickWithinMap = byteIdx * 8 + bitPos;
925
- const mapFirstTick = getFirstTickForMapIndex(
926
- tickHasDebtData.index,
927
- mapIndex
928
- );
929
- return {
930
- nextTick: mapFirstTick + tickWithinMap,
931
- hasNextTick: true
932
- };
933
- }
934
- }
935
- return { nextTick: MIN_TICK$1, hasNextTick: false };
936
- }
937
- function getMostSignificantBit(byte) {
938
- if (byte === 0) return 8;
939
- let leadingZeros = 0;
940
- let mask = 128;
941
- while ((byte & mask) === 0 && leadingZeros < 8) {
942
- leadingZeros++;
943
- mask >>>= 1;
944
- }
945
- return leadingZeros;
946
- }
947
- function getFirstTickForMapIndex(arrayIndex, mapIndex) {
948
- const arrayFirstTick = getFirstTickForIndex(arrayIndex);
949
- return arrayFirstTick + mapIndex * TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS;
950
- }
951
-
952
- const COEFFICIENT_SIZE_DEBT_FACTOR = 35;
953
- const EXPONENT_SIZE_DEBT_FACTOR = 15;
954
- const EXPONENT_MAX_DEBT_FACTOR = new BN(1).shln(EXPONENT_SIZE_DEBT_FACTOR).subn(1);
955
- const DECIMALS_DEBT_FACTOR = new BN(16384);
956
- const MAX_MASK_DEBT_FACTOR$1 = new BN(1).shln(COEFFICIENT_SIZE_DEBT_FACTOR + EXPONENT_SIZE_DEBT_FACTOR).subn(1);
957
- const PRECISION = 64;
958
- const TWO_POWER_64 = new BN("18446744073709551615");
959
- const TWO_POWER_69_MINUS_1 = new BN(1).shln(69).subn(1);
960
- const COEFFICIENT_PLUS_PRECISION = COEFFICIENT_SIZE_DEBT_FACTOR + PRECISION;
961
- const COEFFICIENT_PLUS_PRECISION_MINUS_1 = COEFFICIENT_PLUS_PRECISION - 1;
962
- new BN(1).shln(COEFFICIENT_PLUS_PRECISION_MINUS_1).subn(1);
963
- new BN(1).shln(COEFFICIENT_PLUS_PRECISION_MINUS_1 - 1).subn(1);
964
- function mulDivNormal(normal, bigNumber1, bigNumber2) {
965
- if (bigNumber1.isZero() || bigNumber2.isZero()) {
966
- return new BN(0);
967
- }
968
- const exponent1 = bigNumber1.and(EXPONENT_MAX_DEBT_FACTOR);
969
- const exponent2 = bigNumber2.and(EXPONENT_MAX_DEBT_FACTOR);
970
- if (exponent2.lt(exponent1)) {
971
- throw new Error("LibraryBnError: exponent2 should be >= exponent1");
972
- }
973
- const netExponent = exponent2.sub(exponent1);
974
- if (netExponent.lt(new BN(129))) {
975
- const coefficient1 = bigNumber1.shrn(EXPONENT_SIZE_DEBT_FACTOR);
976
- const coefficient2 = bigNumber2.shrn(EXPONENT_SIZE_DEBT_FACTOR);
977
- const numerator = normal.mul(coefficient1);
978
- const denominator = coefficient2.shln(netExponent.toNumber());
979
- if (denominator.isZero()) {
980
- throw new Error("LibraryDivisionByZero");
981
- }
982
- const result = numerator.div(denominator);
983
- if (result.gt(TWO_POWER_64)) {
984
- throw new Error("LibraryBnError: result overflow");
985
- }
986
- return result;
987
- } else {
988
- return new BN(0);
989
- }
990
- }
991
- function mulBigNumber(bigNumber1, bigNumber2) {
992
- const coefficient1 = bigNumber1.shrn(EXPONENT_SIZE_DEBT_FACTOR);
993
- const coefficient2 = bigNumber2.shrn(EXPONENT_SIZE_DEBT_FACTOR);
994
- const exponent1 = bigNumber1.and(EXPONENT_MAX_DEBT_FACTOR);
995
- const exponent2 = bigNumber2.and(EXPONENT_MAX_DEBT_FACTOR);
996
- const resCoefficient = coefficient1.mul(coefficient2);
997
- const overflowLen = resCoefficient.gt(TWO_POWER_69_MINUS_1) ? COEFFICIENT_SIZE_DEBT_FACTOR : COEFFICIENT_SIZE_DEBT_FACTOR - 1;
998
- const adjustedCoefficient = resCoefficient.shrn(overflowLen);
999
- const resExponent = exponent1.add(exponent2).add(new BN(overflowLen));
1000
- if (resExponent.lt(DECIMALS_DEBT_FACTOR)) {
1001
- throw new Error("LibraryBnError: exponent underflow");
1002
- }
1003
- const finalExponent = resExponent.sub(DECIMALS_DEBT_FACTOR);
1004
- if (finalExponent.gt(EXPONENT_MAX_DEBT_FACTOR)) {
1005
- return MAX_MASK_DEBT_FACTOR$1;
1006
- }
1007
- return adjustedCoefficient.shln(EXPONENT_SIZE_DEBT_FACTOR).or(finalExponent);
1008
- }
1009
-
1010
- const getVaultsProgram = ({
1011
- connection,
1012
- signer
1013
- }) => new Program(vaultsIdl, {
1014
- connection,
1015
- publicKey: signer
1016
- });
1017
- const INIT_TICK = -2147483648;
1018
- const MIN_TICK = -16383;
1019
- const MAX_TICK = 16383;
1020
- const MAX_MASK_DEBT_FACTOR = new BN("1125899906842623");
1021
- const EXCHANGE_PRICES_PRECISION = new BN(10).pow(new BN(12));
1022
- const ZERO_TICK_SCALED_RATIO = new BN(281474976710656);
1023
- const TICK_SPACING = new BN(10015);
1024
- const X30 = new BN(1073741823);
1025
- const MIN_I128 = new BN("170141183460469231731687303715884105728").neg();
1026
- const MAX_REPAY_AMOUNT = MIN_I128;
1027
- const MAX_WITHDRAW_AMOUNT = MIN_I128;
1028
- const getAccountOwner = async (account, connection) => {
1029
- const info = await connection.getAccountInfo(account);
1030
- if (!info)
1031
- throw new Error(`Account info not found for ${account.toString()}`);
1032
- return info.owner;
1033
- };
1034
- const getCurrentPosition = async ({
1035
- vaultId,
1036
- positionId,
1037
- connection
1038
- }) => {
1039
- const program = new Program(vaultsIdl, { connection });
1040
- const position = await program.account.position.fetch(
1041
- getPosition(vaultId, positionId)
1042
- );
1043
- return await getCurrentPositionState({
1044
- vaultId,
1045
- position,
1046
- program
1047
- });
1048
- };
1049
- const getCurrentPositionState = async ({
1050
- vaultId,
1051
- position,
1052
- program
1053
- }) => {
1054
- let positionTick = position.tick;
1055
- if (positionTick === INIT_TICK) {
1056
- positionTick = MIN_TICK;
1057
- }
1058
- if (position.isSupplyOnlyPosition) {
1059
- return {
1060
- tick: MIN_TICK,
1061
- tickId: 0,
1062
- colRaw: new BN(position.supplyAmount.toString()),
1063
- finalAmount: new BN(position.supplyAmount.toString()),
1064
- debtRaw: new BN(0),
1065
- dustDebtRaw: new BN(0),
1066
- isSupplyOnlyPosition: true,
1067
- userLiquidationStatus: false,
1068
- postLiquidationBranchId: 0
1069
- };
1070
- }
1071
- const colRaw = new BN(position.supplyAmount.toString());
1072
- const dustDebtRaw = new BN(position.dustDebtAmount.toString());
1073
- let debtRaw = new BN(0);
1074
- if (positionTick > MIN_TICK) {
1075
- const collateralForDebtCalc = colRaw.add(new BN(1));
1076
- const ratio = getRatioAtTick(positionTick);
1077
- debtRaw = ratio.mul(collateralForDebtCalc).shrn(48).add(new BN(1));
1078
- } else {
1079
- debtRaw = new BN(0);
1080
- }
1081
- let userLiquidationStatus = false;
1082
- let postLiquidationBranchId = 0;
1083
- if (positionTick > MIN_TICK) {
1084
- const tickData = await program.account.tick.fetch(
1085
- getTick(vaultId, positionTick)
1086
- );
1087
- if (tickData.isLiquidated || tickData.totalIds > position.tickId) {
1088
- userLiquidationStatus = true;
1089
- let [tickIdData, branches] = await Promise.all([
1090
- program.account.tickIdLiquidation.fetch(
1091
- getTickIdLiquidation(
1092
- vaultId,
1093
- positionTick,
1094
- position.tickId
1095
- )
1096
- ).catch(() => null),
1097
- getAllBranches({ vaultId, program })
1098
- ]);
1099
- if (!tickIdData) {
1100
- tickIdData = {
1101
- vaultId,
1102
- tick: positionTick,
1103
- tickMap: position.tickId,
1104
- isFullyLiquidated1: 0,
1105
- liquidationBranchId1: 0,
1106
- debtFactor1: new BN(0),
1107
- isFullyLiquidated2: 0,
1108
- liquidationBranchId2: 0,
1109
- debtFactor2: new BN(0),
1110
- isFullyLiquidated3: 0,
1111
- liquidationBranchId3: 0,
1112
- debtFactor3: new BN(0)
1113
- };
1114
- }
1115
- const { isFullyLiquidated, branchId, connectionFactor } = getLiquidationStatus(position.tickId, tickData, tickIdData);
1116
- postLiquidationBranchId = branchId;
1117
- if (isFullyLiquidated) {
1118
- return {
1119
- tick: MIN_TICK,
1120
- tickId: 0,
1121
- colRaw: new BN(0),
1122
- debtRaw: new BN(0),
1123
- dustDebtRaw: new BN(0),
1124
- finalAmount: new BN(0),
1125
- isSupplyOnlyPosition: true,
1126
- userLiquidationStatus: true,
1127
- postLiquidationBranchId: 0
1128
- };
1129
- }
1130
- const { finalTick, finalColRaw, finalDebtRaw } = processLiquidatedPosition({
1131
- branches,
1132
- branchId: postLiquidationBranchId,
1133
- initialConnectionFactor: connectionFactor,
1134
- initialDebtRaw: debtRaw
1135
- });
1136
- const netDebtRaw2 = finalDebtRaw.gt(dustDebtRaw) ? finalDebtRaw.sub(dustDebtRaw) : new BN(0);
1137
- return {
1138
- tick: finalTick,
1139
- tickId: position.tickId,
1140
- colRaw: finalColRaw,
1141
- debtRaw: finalDebtRaw,
1142
- dustDebtRaw,
1143
- finalAmount: netDebtRaw2.gt(new BN(0)) ? finalColRaw : new BN(0),
1144
- isSupplyOnlyPosition: finalTick === MIN_TICK,
1145
- userLiquidationStatus,
1146
- postLiquidationBranchId
1147
- };
1148
- }
1149
- }
1150
- const netDebtRaw = debtRaw.gt(dustDebtRaw) ? debtRaw.sub(dustDebtRaw) : new BN(0);
1151
- return {
1152
- tick: positionTick,
1153
- tickId: position.tickId,
1154
- colRaw,
1155
- debtRaw,
1156
- dustDebtRaw,
1157
- finalAmount: netDebtRaw.gt(new BN(0)) ? colRaw : new BN(0),
1158
- isSupplyOnlyPosition: positionTick === MIN_TICK,
1159
- userLiquidationStatus,
1160
- postLiquidationBranchId
1161
- };
1162
- };
1163
- async function getAllBranches({
1164
- vaultId,
1165
- program
1166
- }) {
1167
- const vaultState = await program.account.vaultState.fetch(
1168
- getVaultState(vaultId)
1169
- );
1170
- const branchPromises = [];
1171
- for (let i = 0; i <= vaultState.totalBranchId; i++) {
1172
- branchPromises.push(
1173
- program.account.branch.fetch(getBranch(vaultId, i)).catch(() => null)
1174
- );
1175
- }
1176
- const branchResults = await Promise.all(branchPromises);
1177
- const branches = branchResults.filter((branch) => branch !== null);
1178
- return branches;
1179
- }
1180
- function getLiquidationStatus(positionTickId, tickData, tickIdData) {
1181
- let isFullyLiquidated;
1182
- let branchId;
1183
- let connectionFactor;
1184
- if (tickData.totalIds === positionTickId) {
1185
- isFullyLiquidated = tickData.isFullyLiquidated === 1;
1186
- branchId = tickData.liquidationBranchId;
1187
- connectionFactor = tickData.debtFactor;
1188
- } else {
1189
- const setIndex = (positionTickId + 2) % 3;
1190
- switch (setIndex) {
1191
- case 0: {
1192
- isFullyLiquidated = tickIdData.isFullyLiquidated1 === 1;
1193
- branchId = tickIdData.liquidationBranchId1;
1194
- connectionFactor = tickIdData.debtFactor1;
1195
- break;
1196
- }
1197
- case 1: {
1198
- isFullyLiquidated = tickIdData.isFullyLiquidated2 === 1;
1199
- branchId = tickIdData.liquidationBranchId2;
1200
- connectionFactor = tickIdData.debtFactor2;
1201
- break;
1202
- }
1203
- default: {
1204
- isFullyLiquidated = tickIdData.isFullyLiquidated3 === 1;
1205
- branchId = tickIdData.liquidationBranchId3;
1206
- connectionFactor = tickIdData.debtFactor3;
1207
- }
1208
- }
1209
- }
1210
- return { isFullyLiquidated, branchId, connectionFactor };
1211
- }
1212
- function processLiquidatedPosition({
1213
- branches,
1214
- branchId,
1215
- initialConnectionFactor,
1216
- initialDebtRaw
1217
- }) {
1218
- let finalColRaw = new BN(0);
1219
- let finalTick;
1220
- const branchMap = new Map(
1221
- branches.map((branch) => [branch.branchId, branch])
1222
- );
1223
- let currentBranchId = branchId;
1224
- let currentConnectionFactor = initialConnectionFactor;
1225
- let currentBranch = branchMap.get(currentBranchId);
1226
- if (!currentBranch) {
1227
- throw new Error(`Branch ${currentBranchId} not found`);
1228
- }
1229
- while (currentBranch.status === 2) {
1230
- currentConnectionFactor = mulBigNumber(
1231
- currentConnectionFactor,
1232
- new BN(currentBranch.debtFactor.toString())
1233
- );
1234
- if (currentConnectionFactor.eq(MAX_MASK_DEBT_FACTOR)) {
1235
- break;
1236
- }
1237
- currentBranchId = currentBranch.connectedBranchId;
1238
- currentBranch = branchMap.get(currentBranchId);
1239
- if (!currentBranch) {
1240
- throw new Error(`Connected branch ${currentBranchId} not found`);
1241
- }
1242
- }
1243
- let positionDebtRaw = new BN(0);
1244
- if (currentBranch.status === 3 || currentConnectionFactor.eq(MAX_MASK_DEBT_FACTOR)) {
1245
- positionDebtRaw = new BN(0);
1246
- finalTick = MIN_TICK;
1247
- } else {
1248
- positionDebtRaw = mulDivNormal(
1249
- initialDebtRaw,
1250
- currentBranch.debtFactor,
1251
- currentConnectionFactor
1252
- );
1253
- positionDebtRaw = positionDebtRaw.gt(initialDebtRaw.div(new BN(100))) ? positionDebtRaw.mul(new BN(9999)).div(new BN(1e4)) : new BN(0);
1254
- if (positionDebtRaw.gt(new BN(0))) {
1255
- finalTick = currentBranch.minimaTick;
1256
- const ratioAtTick = getRatioAtTick(finalTick);
1257
- const ratioOneLess = ratioAtTick.mul(new BN(1e4)).div(TICK_SPACING);
1258
- const ratioLength = ratioAtTick.sub(ratioOneLess);
1259
- const finalRatio = ratioOneLess.add(
1260
- ratioLength.mul(new BN(currentBranch.minimaTickPartials)).div(X30)
1261
- );
1262
- finalColRaw = positionDebtRaw.mul(ZERO_TICK_SCALED_RATIO).div(finalRatio);
1263
- } else finalTick = MIN_TICK;
1264
- }
1265
- return {
1266
- finalTick,
1267
- finalColRaw,
1268
- finalDebtRaw: positionDebtRaw
1269
- };
1270
- }
1271
- const getFinalPosition = async ({
1272
- vaultId,
1273
- currentPosition,
1274
- newColAmount,
1275
- newDebtAmount,
1276
- program,
1277
- connection,
1278
- signer
1279
- }) => {
1280
- program = program ?? getVaultsProgram({ connection, signer });
1281
- const vaultConfig = await program.account.vaultConfig.fetch(
1282
- getVaultConfig(vaultId)
1283
- );
1284
- const {
1285
- vaultSupplyExchangePrice: supplyExPrice,
1286
- vaultBorrowExchangePrice: borrowExPrice
1287
- } = await getExchangePrices({
1288
- vaultId,
1289
- vaultConfig,
1290
- connection,
1291
- signer
1292
- });
1293
- const borrowFee = vaultConfig.borrowFee;
1294
- let { colRaw, debtRaw, dustDebtRaw } = currentPosition;
1295
- if (newColAmount.gt(new BN(0))) {
1296
- const supplyRaw = newColAmount.mul(EXCHANGE_PRICES_PRECISION).div(supplyExPrice);
1297
- colRaw = colRaw.add(supplyRaw);
1298
- } else if (newColAmount.lt(new BN(0))) {
1299
- let withdrawRaw = new BN(0);
1300
- if (newColAmount.gt(MIN_I128)) {
1301
- withdrawRaw = newColAmount.abs().mul(EXCHANGE_PRICES_PRECISION).div(supplyExPrice).sub(new BN(1));
1302
- colRaw = colRaw.sub(withdrawRaw);
1303
- } else if (newColAmount.eq(MIN_I128)) {
1304
- withdrawRaw = colRaw.mul(supplyExPrice).div(EXCHANGE_PRICES_PRECISION).mul(new BN(-1)).add(new BN(1));
1305
- colRaw = new BN(0);
1306
- } else {
1307
- throw new Error("Invalid newColAmount");
1308
- }
1309
- }
1310
- if (newDebtAmount.gt(new BN(0))) {
1311
- const borrowRaw = newDebtAmount.mul(EXCHANGE_PRICES_PRECISION).div(borrowExPrice).add(new BN(1));
1312
- const feeAmount = borrowRaw.mul(new BN(borrowFee)).div(new BN(1e4));
1313
- const borrowAmountWithFee = borrowRaw.add(feeAmount);
1314
- debtRaw = debtRaw.add(borrowAmountWithFee);
1315
- } else if (newDebtAmount.lt(new BN(0))) {
1316
- if (newDebtAmount.gt(MIN_I128)) {
1317
- const payback_amount = newDebtAmount.abs().mul(EXCHANGE_PRICES_PRECISION).div(borrowExPrice).add(new BN(1));
1318
- debtRaw = debtRaw.sub(payback_amount);
1319
- } else if (newDebtAmount.eq(MIN_I128)) {
1320
- debtRaw = new BN(0);
1321
- } else {
1322
- throw new Error("Invalid newDebtAmount");
1323
- }
1324
- }
1325
- const netDebtRaw = debtRaw.gt(dustDebtRaw) ? debtRaw.sub(dustDebtRaw) : new BN(0);
1326
- let finalTick;
1327
- let isSupplyOnlyPosition;
1328
- if (netDebtRaw.eq(new BN(0)) || colRaw.eq(new BN(0))) {
1329
- finalTick = MIN_TICK;
1330
- isSupplyOnlyPosition = true;
1331
- } else {
1332
- const marginAdjustedDebt = netDebtRaw.mul(new BN(1000000001)).div(new BN(1e9)).add(new BN(1));
1333
- const ratio = marginAdjustedDebt.mul(ZERO_TICK_SCALED_RATIO).div(colRaw);
1334
- const baseTickAtRatio = getTickAtRatio(ratio);
1335
- finalTick = baseTickAtRatio + 1;
1336
- if (finalTick < MIN_TICK) {
1337
- finalTick = MIN_TICK;
1338
- } else if (finalTick > MAX_TICK) {
1339
- finalTick = MAX_TICK;
1340
- }
1341
- isSupplyOnlyPosition = false;
1342
- }
1343
- return {
1344
- tick: finalTick,
1345
- tickId: currentPosition.tickId,
1346
- colRaw,
1347
- debtRaw,
1348
- dustDebtRaw,
1349
- finalAmount: netDebtRaw.gt(new BN(0)) ? colRaw : new BN(0),
1350
- isSupplyOnlyPosition
1351
- };
1352
- };
1353
- async function loadRelevantBranches(vaultId, vaultState, liquidationStatus, postLiquidationBranchId, program) {
1354
- const addedBranchIds = /* @__PURE__ */ new Set();
1355
- const currentBranchId = postLiquidationBranchId > 0 ? postLiquidationBranchId : vaultState.currentBranchId;
1356
- let connectedBranchId = 0;
1357
- if (currentBranchId > 0) {
1358
- try {
1359
- const currentBranch = await program.account.branch.fetch(
1360
- getBranch(vaultId, currentBranchId)
1361
- );
1362
- if (currentBranch) {
1363
- addedBranchIds.add(currentBranch.branchId);
1364
- connectedBranchId = currentBranch.connectedBranchId;
1365
- }
1366
- } catch (error) {
1367
- console.warn(`Failed to fetch current branch ${currentBranchId}:`, error);
1368
- }
1369
- }
1370
- if (liquidationStatus) {
1371
- while (connectedBranchId > 0) {
1372
- try {
1373
- const connectedBranch = await program.account.branch.fetch(
1374
- getBranch(vaultId, connectedBranchId)
1375
- );
1376
- if (connectedBranch) {
1377
- if (!addedBranchIds.has(connectedBranch.branchId))
1378
- addedBranchIds.add(connectedBranch.branchId);
1379
- connectedBranchId = connectedBranch.connectedBranchId;
1380
- } else break;
1381
- } catch (error) {
1382
- console.warn(
1383
- `Failed to fetch connected branch ${connectedBranchId}:`,
1384
- error
1385
- );
1386
- break;
1387
- }
1388
- }
1389
- if (!addedBranchIds.has(0)) addedBranchIds.add(0);
1390
- }
1391
- return [...addedBranchIds];
1392
- }
1393
- async function loadRelevantTicksHasDebtArrays(vaultId, topTick, existingPositionTick, finalTick, program) {
1394
- const tickHasDebtArrays = /* @__PURE__ */ new Set();
1395
- if (existingPositionTick == topTick) {
1396
- let nextTickWithDebt = await findNextTickWithDebt(
1397
- vaultId,
1398
- topTick,
1399
- program
1400
- );
1401
- let { arrayIndex: startIndex } = getTickIndices(nextTickWithDebt);
1402
- let { arrayIndex: endIndex } = getTickIndices(topTick);
1403
- let { arrayIndex: finalTickIndex } = getTickIndices(finalTick);
1404
- let finalTickHasDebtPda = getTickHasDebt(vaultId, finalTickIndex);
1405
- tickHasDebtArrays.add(finalTickHasDebtPda);
1406
- if (endIndex < 15) endIndex++;
1407
- try {
1408
- for (let arrIdx = startIndex; arrIdx <= endIndex; arrIdx++)
1409
- tickHasDebtArrays.add(getTickHasDebt(vaultId, arrIdx));
1410
- } catch (error) {
1411
- console.warn(`Error finding next tick with debt:`, error);
1412
- }
1413
- } else {
1414
- let { arrayIndex: finalTickIndex } = getTickIndices(finalTick);
1415
- let { arrayIndex: existingPositionTickIndex } = getTickIndices(existingPositionTick);
1416
- tickHasDebtArrays.add(getTickHasDebt(vaultId, finalTickIndex));
1417
- tickHasDebtArrays.add(
1418
- getTickHasDebt(vaultId, existingPositionTickIndex)
1419
- );
1420
- }
1421
- return [...tickHasDebtArrays];
1422
- }
1423
- async function getExchangePrices({
1424
- vaultId,
1425
- vaultConfig,
1426
- connection,
1427
- signer
1428
- }) {
1429
- const program = new Program(vaultsIdl, { connection });
1430
- const ix = await program.methods.getExchangePrices().accounts({
1431
- vaultState: getVaultState(vaultId),
1432
- vaultConfig: getVaultConfig(vaultId),
1433
- supplyTokenReserves: getReserve(vaultConfig.supplyToken),
1434
- borrowTokenReserves: getReserve(vaultConfig.borrowToken)
1435
- }).instruction();
1436
- const transaction = new Transaction().add(ix);
1437
- const latestBlockHash = await connection.getLatestBlockhash();
1438
- transaction.recentBlockhash = latestBlockHash.blockhash;
1439
- transaction.feePayer = signer;
1440
- const raw = await connection.simulateTransaction(transaction);
1441
- if (raw.value.err && raw.value.err === "InvalidAccountForFee" && signer.toBase58() !== "HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD") {
1442
- return await getExchangePrices({
1443
- vaultId,
1444
- vaultConfig,
1445
- connection,
1446
- signer: new PublicKey("HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD")
1447
- });
1448
- }
1449
- const returnLog = raw.value.logs?.find(
1450
- (log) => log.startsWith("Program return:")
1451
- );
1452
- if (!returnLog) {
1453
- let error = new Error("No return data found in logs");
1454
- error.simulation = raw.value;
1455
- throw error;
1456
- }
1457
- const base64Data = returnLog.split(" ")[3];
1458
- const buffer = Buffer.from(base64Data, "base64");
1459
- const liquiditySupplyExchangePrice = new BN(buffer.subarray(0, 16), "le");
1460
- const liquidityBorrowExchangePrice = new BN(buffer.subarray(16, 32), "le");
1461
- const vaultSupplyExchangePrice = new BN(buffer.subarray(32, 48), "le");
1462
- const vaultBorrowExchangePrice = new BN(buffer.subarray(48, 64), "le");
1463
- return {
1464
- liquiditySupplyExchangePrice,
1465
- liquidityBorrowExchangePrice,
1466
- vaultSupplyExchangePrice,
1467
- vaultBorrowExchangePrice
1468
- };
1469
- }
1470
- async function loadRelevantTicksHasDebtArraysLiquidate(vaultId, topTick, nextTick, program) {
1471
- const { arrayIndex: topTickIndex } = getTickIndices(topTick);
1472
- const { arrayIndex: nextTickIndex } = getTickIndices(nextTick);
1473
- const promises = [];
1474
- for (let arrIdx = topTickIndex; arrIdx >= nextTickIndex; arrIdx--) {
1475
- promises.push(
1476
- program.account.tickHasDebtArray.fetch(
1477
- getTickHasDebt(vaultId, arrIdx)
1478
- )
1479
- );
1480
- }
1481
- const results = await Promise.allSettled(promises);
1482
- const tickHasDebtArrays = results.filter((result) => result.status === "fulfilled").map(
1483
- (result) => result.value
1484
- );
1485
- return tickHasDebtArrays;
1486
- }
1487
- async function loadRelevantBranchesForLiquidate(vaultId, vaultState, program) {
1488
- const branches = [];
1489
- const currentBranchId = vaultState.currentBranchId;
1490
- if (currentBranchId > 0) {
1491
- try {
1492
- const currentBranch = await program.account.branch.fetch(
1493
- getBranch(vaultId, currentBranchId)
1494
- );
1495
- if (currentBranch) branches.push(currentBranch);
1496
- } catch (error) {
1497
- console.warn(`Failed to fetch current branch ${currentBranchId}:`, error);
1498
- }
1499
- }
1500
- let connectedBranchId = branches[0].connectedBranchId;
1501
- const doesBranchExist = (branchId) => branches.some((b) => b.branchId === branchId);
1502
- while (!doesBranchExist(connectedBranchId)) {
1503
- try {
1504
- const connectedBranch = await program.account.branch.fetch(
1505
- getBranch(vaultId, connectedBranchId)
1506
- );
1507
- connectedBranchId = connectedBranch.connectedBranchId;
1508
- if (connectedBranch) branches.push(connectedBranch);
1509
- } catch (error) {
1510
- console.warn(`Failed to fetch connected branch ${connectedBranchId}:`, error);
1511
- }
1512
- }
1513
- if (!doesBranchExist(0)) branches.push({ branchId: 0 });
1514
- return branches;
1515
- }
1516
- async function readOraclePrice({
1517
- connection,
1518
- signer,
1519
- oracle: oracle$1
1520
- }) {
1521
- const program = new Program(
1522
- oracle,
1523
- new AnchorProvider(connection, {
1524
- signTransaction() {
1525
- throw new Error("Not implemented");
1526
- },
1527
- signAllTransactions() {
1528
- throw new Error("Not implemented");
1529
- },
1530
- publicKey: signer ?? new PublicKey("HEyJLdMfZhhQ7FHCtjD5DWDFNFQhaeAVAsHeWqoY6dSD")
1531
- })
1532
- );
1533
- const oracleData = await program.account.oracle.fetch(oracle$1);
1534
- let remainingAccounts = [];
1535
- for (const source of oracleData.sources) {
1536
- remainingAccounts.push({
1537
- pubkey: source.source,
1538
- isWritable: false,
1539
- isSigner: false
1540
- });
1541
- }
1542
- const [oraclePriceOperate, oraclePriceLiquidate] = await Promise.all([
1543
- program.methods.getExchangeRateOperate(oracleData.nonce).accounts({ oracle: oracle$1 }).remainingAccounts(remainingAccounts).view(),
1544
- program.methods.getExchangeRateLiquidate(oracleData.nonce).accounts({ oracle: oracle$1 }).remainingAccounts(remainingAccounts).view()
1545
- ]);
1546
- return {
1547
- oraclePriceOperate,
1548
- oraclePriceLiquidate,
1549
- oracleSources: oracleData.sources
1550
- };
1551
- }
1552
-
1553
- const MPL_TOKEN_METADATA_PROGRAM_ID = new PublicKey(
1554
- "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
1555
- );
1556
- const LIQUIDITY_PROGRAM_ID = new PublicKey(liquidity.address);
1557
- async function getOtherInstructionsOperate(vaultId, vaultState, currentPosition, finalPosition, currentTick, currentTickId, program, signer) {
1558
- const otherIxs = [];
1559
- const tickToRead = [currentTick];
1560
- let finalTickData;
1561
- tickToRead.push(currentPosition.tick);
1562
- tickToRead.push(finalPosition.tick);
1563
- if (tickToRead.length > 0) {
1564
- const tickData = await program.account.tick.fetchMultiple(
1565
- tickToRead.map((tick) => getTick(vaultId, tick))
1566
- );
1567
- tickData[0];
1568
- finalTickData = tickData[2];
1569
- for (const [i, tickDatum] of tickData.entries()) {
1570
- if (!tickDatum) {
1571
- const ix = await program.methods.initTick(vaultId, tickToRead[i]).accounts(getInitTickContext(vaultId, tickToRead[i], signer)).instruction();
1572
- otherIxs.push(ix);
1573
- }
1574
- }
1575
- }
1576
- let newBranchId;
1577
- if (vaultState.branchLiquidated) {
1578
- newBranchId = vaultState.totalBranchId + 1;
1579
- let newBranchData = null;
1580
- try {
1581
- newBranchData = await program.account.branch.fetch(
1582
- getBranch(vaultId, newBranchId)
1583
- );
1584
- } catch {
1585
- }
1586
- if (!newBranchData) {
1587
- const ix = await program.methods.initBranch(vaultId, newBranchId).accounts(getInitBranchContext(vaultId, newBranchId, signer)).instruction();
1588
- otherIxs.push(ix);
1589
- }
1590
- } else {
1591
- newBranchId = vaultState.currentBranchId;
1592
- }
1593
- const newBranchPda = getBranch(vaultId, newBranchId);
1594
- const currentTickIdDataPda = getTickIdLiquidation(
1595
- vaultId,
1596
- currentTick,
1597
- // Position tick
1598
- currentTickId
1599
- // Position tick ID
1600
- );
1601
- const tickIdsToRead = [
1602
- {
1603
- tick: currentTick,
1604
- totalIds: currentTickId
1605
- }
1606
- ];
1607
- const finalTickIdDataPda = getTickIdLiquidation(
1608
- vaultId,
1609
- finalPosition.tick,
1610
- finalTickData ? finalTickData.totalIds : 0
1611
- );
1612
- if (finalPosition.tick !== currentTick)
1613
- if (finalTickData) {
1614
- tickIdsToRead.push({
1615
- tick: finalPosition.tick,
1616
- totalIds: finalTickData.totalIds
1617
- });
1618
- } else {
1619
- const context = await getInitTickIdLiquidationContext(
1620
- vaultId,
1621
- finalPosition.tick,
1622
- signer,
1623
- program
1624
- );
1625
- const ix = await program.methods.initTickIdLiquidation(vaultId, finalPosition.tick, 0).accounts(context).instruction();
1626
- otherIxs.push(ix);
1627
- }
1628
- const tickIdData = await program.account.tickIdLiquidation.fetchMultiple(
1629
- tickIdsToRead.map(
1630
- ({ tick, totalIds }) => getTickIdLiquidation(vaultId, tick, totalIds)
1631
- )
1632
- );
1633
- if (tickIdData.length > 0) {
1634
- for (const [i, tickIdDatum] of tickIdData.entries()) {
1635
- if (!tickIdDatum) {
1636
- const ix = await program.methods.initTickIdLiquidation(
1637
- vaultId,
1638
- tickIdsToRead[i].tick,
1639
- tickIdsToRead[i].totalIds
1640
- ).accounts(
1641
- await getInitTickIdLiquidationContext(
1642
- vaultId,
1643
- tickIdsToRead[i].tick,
1644
- signer,
1645
- program
1646
- )
1647
- ).instruction();
1648
- otherIxs.push(ix);
1649
- }
1650
- }
1651
- }
1652
- return {
1653
- otherIxs,
1654
- newBranchPda,
1655
- currentTickIdDataPda,
1656
- finalTickIdDataPda
1657
- };
1658
- }
1659
- const tickHelper = (tickValue) => {
1660
- return tickValue === 0 ? INIT_TICK : tickValue;
1661
- };
1662
- async function getRemainingAccountsOperate(vaultId, vaultState, vaultConfig, finalPositionTick, existingPositionTick, liquidationStatus, postLiquidationBranchId, program) {
1663
- const remainingAccounts = [];
1664
- const oracleProgram = new Program(oracle, program.provider);
1665
- const [oracleData, branches, tickHasDebt] = await Promise.all([
1666
- oracleProgram.account.oracle.fetch(new PublicKey(vaultConfig.oracle)),
1667
- // Add branch accounts (next 10 remaining accounts)
1668
- loadRelevantBranches(
1669
- vaultId,
1670
- vaultState,
1671
- liquidationStatus,
1672
- postLiquidationBranchId,
1673
- program
1674
- ),
1675
- loadRelevantTicksHasDebtArrays(
1676
- vaultId,
1677
- tickHelper(vaultState.topmostTick),
1678
- existingPositionTick,
1679
- finalPositionTick,
1680
- program
1681
- )
1682
- ]);
1683
- const sourceLength = oracleData.sources.length;
1684
- for (const source of oracleData.sources)
1685
- remainingAccounts.push({
1686
- pubkey: new PublicKey(source.source),
1687
- isWritable: false,
1688
- isSigner: false
1689
- });
1690
- const branchLength = branches.length;
1691
- for (const branch of branches) {
1692
- remainingAccounts.push({
1693
- pubkey: getBranch(vaultId, branch),
1694
- isWritable: true,
1695
- isSigner: false
1696
- });
1697
- }
1698
- const tickHasDebtLength = tickHasDebt.length;
1699
- for (const tickHasDebtArray of tickHasDebt)
1700
- remainingAccounts.push({
1701
- pubkey: tickHasDebtArray,
1702
- isWritable: true,
1703
- isSigner: false
1704
- });
1705
- const remainingAccountsIndices = [
1706
- sourceLength,
1707
- branchLength,
1708
- tickHasDebtLength
1709
- ];
1710
- return {
1711
- remainingAccounts,
1712
- remainingAccountsIndices
1713
- };
1714
- }
1715
- async function getOperateContext({
1716
- vaultId,
1717
- positionId,
1718
- program,
1719
- connection,
1720
- signer,
1721
- positionOwner = signer,
1722
- colAmount: newCol,
1723
- debtAmount: newDebt,
1724
- recipient
1725
- }) {
1726
- program = program ?? getVaultsProgram({ connection, signer });
1727
- const [vaultState, vaultConfig, vaultMetadata] = await Promise.all([
1728
- program.account.vaultState.fetch(getVaultState(vaultId)),
1729
- program.account.vaultConfig.fetch(getVaultConfig(vaultId)),
1730
- program.account.vaultMetadata.fetch(getVaultMetadata(vaultId))
1731
- ]);
1732
- const [supplyTokenProgram, borrowTokenProgram] = await Promise.all([
1733
- getAccountOwner(vaultConfig.supplyToken, connection),
1734
- getAccountOwner(vaultConfig.borrowToken, connection)
1735
- ]);
1736
- const vaultSupplyDecimals = vaultMetadata.supplyMintDecimals;
1737
- const vaultBorrowDecimals = vaultMetadata.borrowMintDecimals;
1738
- if (newCol.gt(MIN_I128)) {
1739
- const decimalsDelta = vaultSupplyDecimals < 9 ? 9 - vaultSupplyDecimals : 0;
1740
- newCol = newCol.mul(new BN(10).pow(new BN(decimalsDelta)));
1741
- }
1742
- if (newDebt.gt(MIN_I128)) {
1743
- const decimalsDelta = vaultBorrowDecimals < 9 ? 9 - vaultBorrowDecimals : 0;
1744
- newDebt = newDebt.mul(new BN(10).pow(new BN(decimalsDelta)));
1745
- }
1746
- const positionData = positionId === 0 ? {
1747
- nftId: vaultState.nextPositionId,
1748
- positionMint: new PublicKey(0),
1749
- isSupplyOnlyPosition: 1,
1750
- tick: -2147483648,
1751
- tickId: 0,
1752
- lastUpdateTimestamp: new BN(0),
1753
- supplyAmount: new BN(0),
1754
- dustDebtAmount: new BN(0)} : await program.account.position.fetch(
1755
- getPosition(vaultId, positionId)
1756
- );
1757
- let existingPositionTick = positionData.tick;
1758
- let existingPositionTickId = positionData.tickId;
1759
- const currentPosition = await getCurrentPositionState({
1760
- vaultId,
1761
- position: positionData,
1762
- program
1763
- });
1764
- if (existingPositionTick === -2147483648) {
1765
- existingPositionTick = currentPosition.tick;
1766
- existingPositionTickId = 0;
1767
- }
1768
- const currentPositionTickPda = getTick(
1769
- vaultId,
1770
- existingPositionTick
1771
- );
1772
- const finalPosition = await getFinalPosition({
1773
- vaultId,
1774
- currentPosition,
1775
- newColAmount: newCol,
1776
- newDebtAmount: newDebt,
1777
- program,
1778
- connection,
1779
- signer
1780
- });
1781
- const { otherIxs, newBranchPda, currentTickIdDataPda, finalTickIdDataPda } = await getOtherInstructionsOperate(
1782
- vaultId,
1783
- vaultState,
1784
- currentPosition,
1785
- finalPosition,
1786
- existingPositionTick,
1787
- existingPositionTickId,
1788
- program,
1789
- signer
1790
- );
1791
- const { remainingAccounts, remainingAccountsIndices } = await getRemainingAccountsOperate(
1792
- vaultId,
1793
- vaultState,
1794
- vaultConfig,
1795
- finalPosition.tick,
1796
- existingPositionTick,
1797
- currentPosition.userLiquidationStatus,
1798
- currentPosition.postLiquidationBranchId,
1799
- program
1800
- );
1801
- const accounts = {
1802
- signer,
1803
- signerSupplyTokenAccount: getAssociatedTokenAddressSync(
1804
- vaultConfig.supplyToken,
1805
- signer,
1806
- true,
1807
- supplyTokenProgram
1808
- ),
1809
- signerBorrowTokenAccount: getAssociatedTokenAddressSync(
1810
- vaultConfig.borrowToken,
1811
- signer,
1812
- true,
1813
- borrowTokenProgram
1814
- ),
1815
- recipient: recipient ?? null,
1816
- recipientSupplyTokenAccount: recipient ? getAssociatedTokenAddressSync(
1817
- vaultConfig.supplyToken,
1818
- recipient,
1819
- true,
1820
- supplyTokenProgram
1821
- ) : null,
1822
- recipientBorrowTokenAccount: recipient ? getAssociatedTokenAddressSync(
1823
- vaultConfig.borrowToken,
1824
- recipient,
1825
- true,
1826
- borrowTokenProgram
1827
- ) : null,
1828
- vaultConfig: getVaultConfig(vaultId),
1829
- vaultState: getVaultState(vaultId),
1830
- supplyToken: vaultConfig.supplyToken,
1831
- borrowToken: vaultConfig.borrowToken,
1832
- oracle: new PublicKey(vaultConfig.oracle),
1833
- position: getPosition(vaultId, positionData.nftId),
1834
- positionTokenAccount: getPositionTokenAccount(
1835
- vaultId,
1836
- positionData.nftId,
1837
- positionOwner
1838
- ),
1839
- currentPositionTick: currentPositionTickPda,
1840
- finalPositionTick: getTick(vaultId, finalPosition.tick),
1841
- currentPositionTickId: currentTickIdDataPda,
1842
- finalPositionTickId: finalTickIdDataPda,
1843
- newBranch: newBranchPda,
1844
- supplyTokenReservesLiquidity: getLiquidityReserve(
1845
- vaultConfig.supplyToken
1846
- ),
1847
- borrowTokenReservesLiquidity: getLiquidityReserve(
1848
- vaultConfig.borrowToken
1849
- ),
1850
- vaultSupplyPositionOnLiquidity: getUserSupplyPosition(
1851
- vaultConfig.supplyToken,
1852
- getVaultConfig(vaultId)
1853
- ),
1854
- vaultBorrowPositionOnLiquidity: getUserBorrowPosition(
1855
- vaultConfig.borrowToken,
1856
- getVaultConfig(vaultId)
1857
- ),
1858
- supplyRateModel: getRateModel(vaultConfig.supplyToken),
1859
- borrowRateModel: getRateModel(vaultConfig.borrowToken),
1860
- supplyTokenClaimAccount: null,
1861
- borrowTokenClaimAccount: null,
1862
- liquidity: getLiquidity(),
1863
- liquidityProgram: LIQUIDITY_PROGRAM_ID,
1864
- vaultSupplyTokenAccount: getAssociatedTokenAddressSync(
1865
- vaultConfig.supplyToken,
1866
- getLiquidity(),
1867
- true,
1868
- supplyTokenProgram
1869
- ),
1870
- vaultBorrowTokenAccount: getAssociatedTokenAddressSync(
1871
- vaultConfig.borrowToken,
1872
- getLiquidity(),
1873
- true,
1874
- borrowTokenProgram
1875
- ),
1876
- oracleProgram: new PublicKey(vaultConfig.oracleProgram),
1877
- supplyTokenProgram,
1878
- borrowTokenProgram,
1879
- associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
1880
- systemProgram: SystemProgram.programId
1881
- };
1882
- return {
1883
- nftId: positionData.nftId,
1884
- accounts,
1885
- remainingAccounts,
1886
- initPositionIx: positionId === 0 ? await program.methods.initPosition(vaultId, positionData.nftId).accounts(
1887
- getInitPositionContext(vaultId, positionData.nftId, signer)
1888
- ).instruction() : null,
1889
- otherIxs,
1890
- remainingAccountsIndices,
1891
- lookupTable: vaultMetadata.lookupTable
1892
- };
1893
- }
1894
- async function getInitPositionIx({
1895
- vaultId,
1896
- connection,
1897
- signer
1898
- }) {
1899
- const program = getVaultsProgram({ connection, signer });
1900
- const vaultState = await program.account.vaultState.fetch(
1901
- getVaultState(vaultId)
1902
- );
1903
- return {
1904
- ix: await program.methods.initPosition(vaultId, vaultState.nextPositionId).accounts(
1905
- getInitPositionContext(vaultId, vaultState.nextPositionId, signer)
1906
- ).instruction(),
1907
- nftId: vaultState.nextPositionId
1908
- };
1909
- }
1910
- function getInitPositionContext(vaultId, positionId, signer) {
1911
- return {
1912
- signer,
1913
- vaultAdmin: getVaultAdmin(),
1914
- vaultState: getVaultState(vaultId),
1915
- position: getPosition(vaultId, positionId),
1916
- positionMint: getPositionMint(vaultId, positionId),
1917
- positionTokenAccount: getPositionTokenAccount(
1918
- vaultId,
1919
- positionId,
1920
- signer
1921
- ),
1922
- tokenProgram: TOKEN_PROGRAM_ID,
1923
- metadataAccount: getPositionMetadata(vaultId, positionId),
1924
- associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
1925
- systemProgram: SystemProgram.programId,
1926
- sysvarInstruction: SYSVAR_INSTRUCTIONS_PUBKEY,
1927
- metadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID,
1928
- rent: SYSVAR_RENT_PUBKEY
1929
- };
1930
- }
1931
- const getOperateIx = async ({
1932
- vaultId,
1933
- positionId,
1934
- colAmount,
1935
- debtAmount,
1936
- connection,
1937
- signer,
1938
- recipient,
1939
- positionOwner
1940
- }) => {
1941
- const program = getVaultsProgram({ connection, signer });
1942
- const {
1943
- accounts,
1944
- remainingAccounts,
1945
- remainingAccountsIndices,
1946
- initPositionIx,
1947
- otherIxs,
1948
- lookupTable,
1949
- nftId
1950
- } = await getOperateContext({
1951
- vaultId,
1952
- positionId,
1953
- colAmount,
1954
- debtAmount,
1955
- signer,
1956
- positionOwner,
1957
- connection,
1958
- recipient,
1959
- program
1960
- });
1961
- if (accounts.borrowToken.toString() !== NATIVE_MINT.toString() && debtAmount.lt(new BN(0))) {
1962
- try {
1963
- const userDebtTokenBalance = await connection.getTokenAccountBalance(
1964
- accounts.signerBorrowTokenAccount
1965
- );
1966
- if (userDebtTokenBalance.value.amount === debtAmount.abs().toString()) {
1967
- debtAmount = debtAmount.add(new BN(1));
1968
- }
1969
- } catch (error) {
1970
- }
1971
- }
1972
- const [operateIx, addressLookupTable] = await Promise.all([
1973
- program.methods.operate(
1974
- colAmount,
1975
- debtAmount,
1976
- { direct: {} },
1977
- Buffer.from(remainingAccountsIndices)
1978
- ).accounts(accounts).remainingAccounts(remainingAccounts).instruction(),
1979
- connection.getAddressLookupTable(lookupTable)
1980
- ]);
1981
- return {
1982
- nftId,
1983
- accounts,
1984
- remainingAccounts,
1985
- remainingAccountsIndices,
1986
- addressLookupTableAddresses: lookupTable ? [lookupTable] : [],
1987
- addressLookupTableAccounts: addressLookupTable.value ? [addressLookupTable.value] : [],
1988
- ixs: initPositionIx ? [initPositionIx, ...otherIxs, operateIx] : [...otherIxs, operateIx]
1989
- };
1990
- };
1991
- function getInitBranchContext(vaultId, branchId, signer) {
1992
- return {
1993
- signer,
1994
- vaultConfig: getVaultConfig(vaultId),
1995
- branch: getBranch(vaultId, branchId),
1996
- systemProgram: SystemProgram.programId
1997
- };
1998
- }
1999
- function getInitTickContext(vaultId, tick, signer) {
2000
- return {
2001
- signer,
2002
- vaultConfig: getVaultConfig(vaultId),
2003
- tickData: getTick(vaultId, tick),
2004
- systemProgram: SystemProgram.programId
2005
- };
2006
- }
2007
- async function getInitTickIdLiquidationContext(vaultId, tick, signer, program) {
2008
- const tickData = await program.account.tick.fetch(getTick(vaultId, tick)).catch(() => null);
2009
- if (!tickData) {
2010
- return {
2011
- signer,
2012
- vaultConfig: getVaultConfig(vaultId),
2013
- tickIdLiquidation: getTickIdLiquidation(vaultId, tick, 0),
2014
- tickData: getTick(vaultId, tick),
2015
- systemProgram: SystemProgram.programId
2016
- };
2017
- }
2018
- return {
2019
- signer,
2020
- vaultConfig: getVaultConfig(vaultId),
2021
- tickIdLiquidation: getTickIdLiquidation(
2022
- vaultId,
2023
- tick,
2024
- tickData.totalIds
2025
- ),
2026
- tickData: getTick(vaultId, tick),
2027
- systemProgram: SystemProgram.programId
2028
- };
2029
- }
2030
- async function getLiquidateContext({
2031
- vaultId,
2032
- to,
2033
- program,
2034
- connection,
2035
- signer
2036
- }) {
2037
- program = program ?? getVaultsProgram({ connection, signer });
2038
- const [vaultState, vaultConfig, vaultMetadata] = await Promise.all([
2039
- program.account.vaultState.fetch(getVaultState(vaultId)),
2040
- program.account.vaultConfig.fetch(getVaultConfig(vaultId)),
2041
- program.account.vaultMetadata.fetch(getVaultMetadata(vaultId))
2042
- ]);
2043
- const [supplyTokenProgram, borrowTokenProgram] = await Promise.all([
2044
- getAccountOwner(vaultConfig.supplyToken, connection),
2045
- getAccountOwner(vaultConfig.borrowToken, connection)
2046
- ]);
2047
- const { arrayIndex } = getTickIndices(vaultState.topmostTick);
2048
- let { otherIxs, newBranchPda } = await getOtherInstructionsLiquidate(
2049
- vaultId,
2050
- vaultState,
2051
- program,
2052
- signer
2053
- );
2054
- const {
2055
- remainingAccounts,
2056
- remainingAccountsIndices,
2057
- otherIxs: finalOtherIxs
2058
- } = await getRemainingAccountsLiquidate(
2059
- vaultId,
2060
- vaultState,
2061
- vaultConfig,
2062
- otherIxs,
2063
- program,
2064
- connection,
2065
- signer
2066
- );
2067
- return {
2068
- accounts: {
2069
- signer,
2070
- signerTokenAccount: getAssociatedTokenAddressSync(
2071
- vaultConfig.borrowToken,
2072
- signer,
2073
- false,
2074
- borrowTokenProgram
2075
- ),
2076
- to,
2077
- toTokenAccount: getAssociatedTokenAddressSync(
2078
- vaultConfig.supplyToken,
2079
- to,
2080
- false,
2081
- supplyTokenProgram
2082
- ),
2083
- vaultAdmin: getVaultAdmin(),
2084
- vaultConfig: getVaultConfig(vaultId),
2085
- vaultState: getVaultState(vaultId),
2086
- supplyToken: vaultConfig.supplyToken,
2087
- borrowToken: vaultConfig.borrowToken,
2088
- oracle: new PublicKey(vaultConfig.oracle),
2089
- tickHasDebt: getTickHasDebt(vaultId, arrayIndex),
2090
- newBranch: newBranchPda,
2091
- supplyTokenReservesLiquidity: getLiquidityReserve(
2092
- vaultConfig.supplyToken
2093
- ),
2094
- borrowTokenReservesLiquidity: getLiquidityReserve(
2095
- vaultConfig.borrowToken
2096
- ),
2097
- vaultSupplyPositionOnLiquidity: getUserSupplyPosition(
2098
- vaultConfig.supplyToken,
2099
- getVaultConfig(vaultId)
2100
- ),
2101
- vaultBorrowPositionOnLiquidity: getUserBorrowPosition(
2102
- vaultConfig.borrowToken,
2103
- getVaultConfig(vaultId)
2104
- ),
2105
- supplyRateModel: getRateModel(vaultConfig.supplyToken),
2106
- borrowRateModel: getRateModel(vaultConfig.borrowToken),
2107
- supplyTokenClaimAccount: getClaimAccount(
2108
- vaultConfig.supplyToken,
2109
- getVaultConfig(vaultId)
2110
- ),
2111
- borrowTokenClaimAccount: getClaimAccount(
2112
- vaultConfig.borrowToken,
2113
- getVaultConfig(vaultId)
2114
- ),
2115
- liquidity: getLiquidity(),
2116
- liquidityProgram: LIQUIDITY_PROGRAM_ID,
2117
- vaultSupplyTokenAccount: getAssociatedTokenAddressSync(
2118
- vaultConfig.supplyToken,
2119
- getLiquidity(),
2120
- true,
2121
- supplyTokenProgram
2122
- ),
2123
- vaultBorrowTokenAccount: getAssociatedTokenAddressSync(
2124
- vaultConfig.borrowToken,
2125
- getLiquidity(),
2126
- true,
2127
- borrowTokenProgram
2128
- ),
2129
- oracleProgram: new PublicKey(vaultConfig.oracleProgram),
2130
- supplyTokenProgram,
2131
- borrowTokenProgram,
2132
- systemProgram: SystemProgram.programId,
2133
- associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID
2134
- },
2135
- remainingAccounts,
2136
- otherIxs: finalOtherIxs,
2137
- remainingAccountsIndices,
2138
- lookupTable: vaultMetadata.lookupTable
2139
- };
2140
- }
2141
- const getLiquidateIx = async ({
2142
- vaultId,
2143
- debtAmount,
2144
- colPerUnitDebt = new BN(0),
2145
- absorb = false,
2146
- signer,
2147
- to = signer,
2148
- connection
2149
- }) => {
2150
- const program = getVaultsProgram({ connection, signer });
2151
- const {
2152
- accounts,
2153
- remainingAccounts,
2154
- remainingAccountsIndices,
2155
- otherIxs,
2156
- lookupTable
2157
- } = await getLiquidateContext({
2158
- vaultId,
2159
- to,
2160
- program,
2161
- signer,
2162
- connection
2163
- });
2164
- const ixs = [];
2165
- if (otherIxs.length > 0) {
2166
- ixs.push(...otherIxs);
2167
- }
2168
- const [ix, addressLookupTable] = await Promise.all([
2169
- program.methods.liquidate(
2170
- debtAmount,
2171
- colPerUnitDebt,
2172
- absorb,
2173
- { direct: {} },
2174
- Buffer.from(remainingAccountsIndices)
2175
- ).accounts(accounts).remainingAccounts(remainingAccounts).instruction(),
2176
- connection.getAddressLookupTable(lookupTable)
2177
- ]);
2178
- ixs.push(ix);
2179
- return {
2180
- accounts,
2181
- remainingAccounts,
2182
- remainingAccountsIndices,
2183
- ixs,
2184
- addressLookupTableAddresses: lookupTable ? [lookupTable] : [],
2185
- addressLookupTableAccounts: addressLookupTable.value ? [addressLookupTable.value] : []
2186
- };
2187
- };
2188
- async function getOtherInstructionsLiquidate(vaultId, vaultState, program, signer) {
2189
- const otherIxs = [];
2190
- let newBranchId = vaultState.branchLiquidated === 1 ? vaultState.totalBranchId + 1 : vaultState.currentBranchId;
2191
- let newBranchPda = getBranch(vaultId, newBranchId);
2192
- const [newBranchData, tickData] = await Promise.all([
2193
- program.account.branch.fetch(newBranchPda).catch(() => null),
2194
- // might be possible that liquidation ends on a tick that is not initialized
2195
- program.account.tick.fetch(getTick(vaultId, vaultState.topmostTick)).catch(() => null)
2196
- ]);
2197
- if (!newBranchData) {
2198
- const ix = await program.methods.initBranch(vaultId, newBranchId).accounts(getInitBranchContext(vaultId, newBranchId, signer)).instruction();
2199
- otherIxs.push(ix);
2200
- }
2201
- if (!tickData) {
2202
- const ix = await program.methods.initTick(vaultId, vaultState.topmostTick).accounts(getInitTickContext(vaultId, vaultState.topmostTick, signer)).instruction();
2203
- otherIxs.push(ix);
2204
- }
2205
- return {
2206
- otherIxs,
2207
- newBranchPda
2208
- };
2209
- }
2210
- async function loadRelevantTicksForLiquidate(vaultId, vaultState, liquidationTick, program) {
2211
- const ticks = [];
2212
- let topTick = vaultState.topmostTick;
2213
- if (topTick > liquidationTick)
2214
- try {
2215
- const topTickData = await program.account.tick.fetch(
2216
- getTick(vaultId, topTick)
2217
- );
2218
- if (topTickData) ticks.push({ ...topTickData, tick: topTick });
2219
- } catch {
2220
- }
2221
- let nextTick = MIN_TICK$1;
2222
- try {
2223
- nextTick = await findNextTickWithDebt(vaultId, topTick, program);
2224
- } catch {
2225
- }
2226
- const doesTickExist = (tick) => ticks.some((t) => t.tick === tick);
2227
- while (nextTick > liquidationTick && !doesTickExist(nextTick)) {
2228
- try {
2229
- const nextTickData = await program.account.tick.fetch(
2230
- getTick(vaultId, nextTick)
2231
- );
2232
- if (nextTickData) ticks.push({ ...nextTickData, tick: nextTick });
2233
- else throw new Error("Tick not found to load");
2234
- nextTick = await findNextTickWithDebt(vaultId, nextTick, program);
2235
- } catch {
2236
- }
2237
- }
2238
- return { ticks, nextTick };
2239
- }
2240
- async function getRemainingAccountsLiquidate(vaultId, vaultState, vaultConfig, otherIxs, program, connection, signer) {
2241
- const remainingAccounts = [];
2242
- const { oraclePriceLiquidate, oracleSources } = await readOraclePrice({
2243
- oracle: vaultConfig.oracle,
2244
- connection
2245
- // signer,
2246
- });
2247
- const liquidationRatio = new BN(oraclePriceLiquidate).mul(new BN(281474976710656)).div(new BN(10).pow(new BN(15)));
2248
- const liquidationThresholdRatio = liquidationRatio.mul(new BN(vaultConfig.liquidationThreshold)).div(new BN(10).pow(new BN(3)));
2249
- const liquidationTick = getTickAtRatio(liquidationThresholdRatio);
2250
- for (const source of oracleSources) {
2251
- remainingAccounts.push({
2252
- pubkey: source.source,
2253
- isWritable: false,
2254
- isSigner: false
2255
- });
2256
- }
2257
- const [branches, { ticks: tickAccounts, nextTick }] = await Promise.all([
2258
- loadRelevantBranchesForLiquidate(vaultId, vaultState, program),
2259
- loadRelevantTicksForLiquidate(
2260
- vaultId,
2261
- vaultState,
2262
- liquidationTick,
2263
- program
2264
- )
2265
- ]);
2266
- const tickHasDebt = await loadRelevantTicksHasDebtArraysLiquidate(
2267
- vaultId,
2268
- vaultState.topmostTick,
2269
- nextTick,
2270
- program
2271
- );
2272
- for (const branch of branches) {
2273
- remainingAccounts.push({
2274
- pubkey: getBranch(vaultId, branch.branchId),
2275
- isWritable: true,
2276
- isSigner: false
2277
- });
2278
- }
2279
- const tickToInit = [];
2280
- const existingTicks = await Promise.all(
2281
- tickAccounts.map(
2282
- (tickData) => program.account.tick.fetch(getTick(vaultId, tickData.tick)).catch(() => null)
2283
- )
2284
- );
2285
- const initInstructions = await Promise.all(
2286
- tickAccounts.map(async (tickData, index) => {
2287
- const existingTick = existingTicks[index];
2288
- if (!existingTick && !tickToInit.includes(tickData.tick)) {
2289
- tickToInit.push(tickData.tick);
2290
- return program.methods.initTick(vaultId, tickData.tick).accounts(getInitTickContext(vaultId, tickData.tick, signer)).instruction();
2291
- }
2292
- return null;
2293
- })
2294
- );
2295
- for (const ix of initInstructions) {
2296
- if (ix) {
2297
- otherIxs.push(ix);
2298
- }
2299
- }
2300
- for (const tickData of tickAccounts) {
2301
- remainingAccounts.push({
2302
- pubkey: getTick(vaultId, tickData.tick),
2303
- isWritable: true,
2304
- isSigner: false
2305
- });
2306
- }
2307
- for (const tickHasDebtArray of tickHasDebt) {
2308
- remainingAccounts.push({
2309
- pubkey: getTickHasDebt(vaultId, tickHasDebtArray.index),
2310
- isWritable: true,
2311
- isSigner: false
2312
- });
2313
- }
2314
- const remainingAccountsIndices = [
2315
- oracleSources.length,
2316
- branches.length,
2317
- tickAccounts.length,
2318
- tickHasDebt.length
2319
- ];
2320
- return {
2321
- remainingAccounts,
2322
- otherIxs,
2323
- remainingAccountsIndices
2324
- };
2325
- }
2326
-
2327
- export { getFirstTickForIndex as A, getTickIndices as B, readTickHasDebtArray as C, findNextTickWithDebt as D, INIT_TICK as I, MIN_I128 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, MAX_REPAY_AMOUNT as h, MAX_WITHDRAW_AMOUNT as i, getAccountOwner as j, getCurrentPosition as k, getCurrentPositionState as l, getFinalPosition as m, loadRelevantBranches as n, loadRelevantTicksHasDebtArrays as o, loadRelevantTicksHasDebtArraysLiquidate as p, loadRelevantBranchesForLiquidate as q, readOraclePrice as r, MIN_TICK$1 as s, MAX_TICK$1 as t, TICKS_PER_TICK_HAS_DEBT as u, TICK_HAS_DEBT_CHILDREN_SIZE as v, TICK_HAS_DEBT_CHILDREN_SIZE_IN_BITS as w, TOTAL_INDICES_NEEDED as x, getRatioAtTick as y, getTickAtRatio as z };