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