@kamino-finance/klend-sdk 5.11.3-beta.0 → 5.11.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/classes/action.d.ts +23 -23
  2. package/dist/classes/action.d.ts.map +1 -1
  3. package/dist/classes/action.js +149 -69
  4. package/dist/classes/action.js.map +1 -1
  5. package/dist/classes/manager.d.ts +1 -1
  6. package/dist/classes/manager.js +1 -1
  7. package/dist/classes/market.d.ts +3 -3
  8. package/dist/classes/market.d.ts.map +1 -1
  9. package/dist/classes/market.js +16 -30
  10. package/dist/classes/market.js.map +1 -1
  11. package/dist/classes/obligation.d.ts +0 -2
  12. package/dist/classes/obligation.d.ts.map +1 -1
  13. package/dist/classes/obligation.js +0 -5
  14. package/dist/classes/obligation.js.map +1 -1
  15. package/dist/classes/vault.js +14 -14
  16. package/dist/classes/vault.js.map +1 -1
  17. package/dist/idl_codegen_kamino_vault/accounts/VaultState.d.ts +3 -3
  18. package/dist/idl_codegen_kamino_vault/accounts/VaultState.d.ts.map +1 -1
  19. package/dist/idl_codegen_kamino_vault/accounts/VaultState.js +6 -6
  20. package/dist/idl_codegen_kamino_vault/accounts/VaultState.js.map +1 -1
  21. package/dist/idl_codegen_kamino_vault/instructions/giveUpPendingFees.d.ts +1 -1
  22. package/dist/idl_codegen_kamino_vault/instructions/giveUpPendingFees.d.ts.map +1 -1
  23. package/dist/idl_codegen_kamino_vault/instructions/giveUpPendingFees.js +1 -1
  24. package/dist/idl_codegen_kamino_vault/instructions/giveUpPendingFees.js.map +1 -1
  25. package/dist/idl_codegen_kamino_vault/instructions/initializeSharesMetadata.d.ts +1 -1
  26. package/dist/idl_codegen_kamino_vault/instructions/initializeSharesMetadata.d.ts.map +1 -1
  27. package/dist/idl_codegen_kamino_vault/instructions/initializeSharesMetadata.js +1 -1
  28. package/dist/idl_codegen_kamino_vault/instructions/initializeSharesMetadata.js.map +1 -1
  29. package/dist/idl_codegen_kamino_vault/instructions/updateSharesMetadata.d.ts +1 -1
  30. package/dist/idl_codegen_kamino_vault/instructions/updateSharesMetadata.d.ts.map +1 -1
  31. package/dist/idl_codegen_kamino_vault/instructions/updateSharesMetadata.js +1 -1
  32. package/dist/idl_codegen_kamino_vault/instructions/updateSharesMetadata.js.map +1 -1
  33. package/dist/idl_codegen_kamino_vault/instructions/updateVaultConfig.d.ts +1 -1
  34. package/dist/idl_codegen_kamino_vault/instructions/updateVaultConfig.d.ts.map +1 -1
  35. package/dist/idl_codegen_kamino_vault/instructions/updateVaultConfig.js +1 -1
  36. package/dist/idl_codegen_kamino_vault/instructions/updateVaultConfig.js.map +1 -1
  37. package/dist/idl_codegen_kamino_vault/instructions/withdrawPendingFees.d.ts +1 -1
  38. package/dist/idl_codegen_kamino_vault/instructions/withdrawPendingFees.d.ts.map +1 -1
  39. package/dist/idl_codegen_kamino_vault/instructions/withdrawPendingFees.js +1 -1
  40. package/dist/idl_codegen_kamino_vault/instructions/withdrawPendingFees.js.map +1 -1
  41. package/dist/lending_operations/repay_with_collateral_operations.d.ts +4 -4
  42. package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
  43. package/dist/lending_operations/repay_with_collateral_operations.js +8 -10
  44. package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
  45. package/dist/lending_operations/swap_collateral_operations.d.ts +2 -2
  46. package/dist/lending_operations/swap_collateral_operations.d.ts.map +1 -1
  47. package/dist/lending_operations/swap_collateral_operations.js +6 -11
  48. package/dist/lending_operations/swap_collateral_operations.js.map +1 -1
  49. package/dist/leverage/calcs.d.ts +10 -5
  50. package/dist/leverage/calcs.d.ts.map +1 -1
  51. package/dist/leverage/calcs.js +13 -6
  52. package/dist/leverage/calcs.js.map +1 -1
  53. package/dist/leverage/operations.d.ts +7 -9
  54. package/dist/leverage/operations.d.ts.map +1 -1
  55. package/dist/leverage/operations.js +72 -78
  56. package/dist/leverage/operations.js.map +1 -1
  57. package/dist/leverage/types.d.ts +4 -4
  58. package/dist/leverage/types.d.ts.map +1 -1
  59. package/dist/utils/ObligationType.d.ts +1 -1
  60. package/dist/utils/ObligationType.d.ts.map +1 -1
  61. package/dist/utils/managerTypes.d.ts.map +1 -1
  62. package/dist/utils/managerTypes.js +52 -7
  63. package/dist/utils/managerTypes.js.map +1 -1
  64. package/dist/utils/oracle.d.ts +3 -3
  65. package/dist/utils/oracle.d.ts.map +1 -1
  66. package/package.json +2 -2
  67. package/src/classes/action.ts +162 -75
  68. package/src/classes/manager.ts +1 -1
  69. package/src/classes/market.ts +25 -34
  70. package/src/classes/obligation.ts +0 -6
  71. package/src/classes/vault.ts +14 -14
  72. package/src/client.ts +3 -8
  73. package/src/idl_codegen_kamino_vault/accounts/VaultState.ts +8 -8
  74. package/src/idl_codegen_kamino_vault/instructions/giveUpPendingFees.ts +2 -2
  75. package/src/idl_codegen_kamino_vault/instructions/initializeSharesMetadata.ts +2 -2
  76. package/src/idl_codegen_kamino_vault/instructions/updateSharesMetadata.ts +2 -2
  77. package/src/idl_codegen_kamino_vault/instructions/updateVaultConfig.ts +2 -2
  78. package/src/idl_codegen_kamino_vault/instructions/withdrawPendingFees.ts +2 -2
  79. package/src/idl_kamino_vault.json +7 -7
  80. package/src/lending_operations/repay_with_collateral_operations.ts +11 -15
  81. package/src/lending_operations/swap_collateral_operations.ts +7 -19
  82. package/src/leverage/calcs.ts +18 -2
  83. package/src/leverage/operations.ts +72 -114
  84. package/src/leverage/types.ts +4 -4
  85. package/src/utils/ObligationType.ts +1 -1
  86. package/src/utils/managerTypes.ts +52 -10
  87. package/src/utils/oracle.ts +2 -2
@@ -61,11 +61,11 @@ import {
61
61
  isNotNullPubkey,
62
62
  PublicKeySet,
63
63
  getAssociatedTokenAddress,
64
- ScopePriceRefreshConfig,
64
+ ScopeRefresh,
65
65
  createAtasIdempotent,
66
66
  obligationFarmStatePda,
67
67
  } from '../utils';
68
- import { getTokenIdsForScopeRefresh, KaminoMarket } from './market';
68
+ import { KaminoMarket } from './market';
69
69
  import { KaminoObligation } from './obligation';
70
70
  import { KaminoReserve } from './reserve';
71
71
  import { ReserveFarmKind } from '../idl_codegen/types';
@@ -73,7 +73,7 @@ import { farmsId } from '@kamino-finance/farms-sdk';
73
73
  import { Reserve } from '../idl_codegen/accounts';
74
74
  import { VanillaObligation } from '../utils/ObligationType';
75
75
  import { PROGRAM_ID } from '../lib';
76
- import { Scope } from '@kamino-finance/scope-sdk';
76
+ import { U16_MAX } from '@kamino-finance/scope-sdk';
77
77
 
78
78
  const SOL_PADDING_FOR_INTEREST = new BN('1000000');
79
79
 
@@ -411,7 +411,6 @@ export class KaminoAction {
411
411
  owner: PublicKey,
412
412
  obligation: KaminoObligation | ObligationType,
413
413
  useV2Ixs: boolean,
414
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
415
414
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
416
415
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
417
416
  requestElevationGroup: boolean = false, // to be requested *before* the deposit
@@ -419,6 +418,7 @@ export class KaminoAction {
419
418
  createLookupTable: boolean = true,
420
419
  referrer: PublicKey = PublicKey.default,
421
420
  currentSlot: number = 0,
421
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' },
422
422
  overrideElevationGroupRequest: number | undefined = undefined // if set, when an elevationgroup request is made, it will use this value
423
423
  ) {
424
424
  const axn = await KaminoAction.initialize(
@@ -437,6 +437,16 @@ export class KaminoAction {
437
437
  axn.addComputeBudgetIxn(extraComputeBudget);
438
438
  }
439
439
 
440
+ const allReserves = new PublicKeySet<PublicKey>([
441
+ ...axn.depositReserves,
442
+ ...axn.borrowReserves,
443
+ axn.reserve.address,
444
+ ]).toArray();
445
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
446
+
447
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
448
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
449
+ }
440
450
  await axn.addSupportIxs(
441
451
  'deposit',
442
452
  includeAtaIxns,
@@ -444,7 +454,6 @@ export class KaminoAction {
444
454
  includeUserMetadata,
445
455
  addInitObligationForFarm,
446
456
  useV2Ixs,
447
- scopeRefreshConfig,
448
457
  createLookupTable,
449
458
  undefined,
450
459
  overrideElevationGroupRequest
@@ -459,10 +468,36 @@ export class KaminoAction {
459
468
  return axn;
460
469
  }
461
470
 
462
- async addScopeRefreshIxs(scope: Scope, tokens: number[], feed: string = 'hubble') {
463
- this.setupIxsLabels.unshift(`refreshScopePrices`);
464
- this.setupIxs.unshift(
465
- await scope.refreshPriceListIx(
471
+ getTokenIdsForScopeRefresh(kaminoMarket: KaminoMarket, reserves: PublicKey[]): number[] {
472
+ const tokenIds: number[] = [];
473
+
474
+ for (const reserveAddress of reserves) {
475
+ const reserve = kaminoMarket.getReserveByAddress(reserveAddress);
476
+ if (!reserve) {
477
+ throw new Error(`Reserve not found for reserve ${reserveAddress.toBase58()}`);
478
+ }
479
+
480
+ if (!reserve.state.config.tokenInfo.scopeConfiguration.priceFeed.equals(PublicKey.default)) {
481
+ reserve.state.config.tokenInfo.scopeConfiguration.priceChain.map((x) => {
482
+ if (x !== U16_MAX) {
483
+ tokenIds.push(x);
484
+ }
485
+ });
486
+ reserve.state.config.tokenInfo.scopeConfiguration.twapChain.map((x) => {
487
+ if (x !== U16_MAX) {
488
+ tokenIds.push(x);
489
+ }
490
+ });
491
+ }
492
+ }
493
+
494
+ return tokenIds;
495
+ }
496
+
497
+ async addScopeRefreshIxs(tokens: number[], feed: string = 'hubble') {
498
+ this.preTxnIxsLabels.unshift(`refreshScopePrices`);
499
+ this.preTxnIxs.unshift(
500
+ await this.kaminoMarket.scope.refreshPriceListIx(
466
501
  {
467
502
  feed: feed,
468
503
  },
@@ -478,7 +513,6 @@ export class KaminoAction {
478
513
  owner: PublicKey,
479
514
  obligation: KaminoObligation | ObligationType,
480
515
  useV2Ixs: boolean,
481
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
482
516
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
483
517
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
484
518
  requestElevationGroup: boolean = false,
@@ -486,6 +520,7 @@ export class KaminoAction {
486
520
  createLookupTable: boolean = true,
487
521
  referrer: PublicKey = PublicKey.default,
488
522
  currentSlot: number = 0,
523
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' },
489
524
  overrideElevationGroupRequest: number | undefined = undefined // if set, when an elevationgroup request is made, it will use this value
490
525
  ) {
491
526
  const axn = await KaminoAction.initialize(
@@ -503,6 +538,17 @@ export class KaminoAction {
503
538
  axn.addComputeBudgetIxn(extraComputeBudget);
504
539
  }
505
540
 
541
+ const allReserves = new PublicKeySet<PublicKey>([
542
+ ...axn.depositReserves,
543
+ ...axn.borrowReserves,
544
+ axn.reserve.address,
545
+ ]).toArray();
546
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
547
+
548
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
549
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
550
+ }
551
+
506
552
  await axn.addSupportIxs(
507
553
  'borrow',
508
554
  includeAtaIxns,
@@ -510,7 +556,6 @@ export class KaminoAction {
510
556
  includeUserMetadata,
511
557
  addInitObligationForFarm,
512
558
  useV2Ixs,
513
- scopeRefreshConfig,
514
559
  createLookupTable,
515
560
  undefined,
516
561
  overrideElevationGroupRequest
@@ -531,12 +576,12 @@ export class KaminoAction {
531
576
  mint: PublicKey,
532
577
  owner: PublicKey,
533
578
  obligation: KaminoObligation | ObligationType,
534
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
535
579
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
536
580
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas
537
581
  requestElevationGroup: boolean = false,
538
582
  referrer: PublicKey = PublicKey.default,
539
- currentSlot: number = 0
583
+ currentSlot: number = 0,
584
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
540
585
  ) {
541
586
  const axn = await KaminoAction.initialize(
542
587
  'mint',
@@ -554,6 +599,17 @@ export class KaminoAction {
554
599
  axn.addComputeBudgetIxn(extraComputeBudget);
555
600
  }
556
601
 
602
+ const allReserves = new PublicKeySet<PublicKey>([
603
+ ...axn.depositReserves,
604
+ ...axn.borrowReserves,
605
+ axn.reserve.address,
606
+ ]).toArray();
607
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
608
+
609
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
610
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
611
+ }
612
+
557
613
  await axn.addSupportIxs(
558
614
  'mint',
559
615
  includeAtaIxns,
@@ -561,7 +617,6 @@ export class KaminoAction {
561
617
  false,
562
618
  addInitObligationForFarm,
563
619
  false,
564
- scopeRefreshConfig,
565
620
  false
566
621
  );
567
622
  axn.addDepositReserveLiquidityIx();
@@ -575,12 +630,12 @@ export class KaminoAction {
575
630
  mint: PublicKey,
576
631
  owner: PublicKey,
577
632
  obligation: KaminoObligation | ObligationType,
578
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
579
633
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
580
634
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas
581
635
  requestElevationGroup: boolean = false,
582
636
  referrer: PublicKey = PublicKey.default,
583
- currentSlot: number = 0
637
+ currentSlot: number = 0,
638
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
584
639
  ) {
585
640
  const axn = await KaminoAction.initialize(
586
641
  'redeem',
@@ -598,6 +653,17 @@ export class KaminoAction {
598
653
  axn.addComputeBudgetIxn(extraComputeBudget);
599
654
  }
600
655
 
656
+ const allReserves = new PublicKeySet<PublicKey>([
657
+ ...axn.depositReserves,
658
+ ...axn.borrowReserves,
659
+ axn.reserve.address,
660
+ ]).toArray();
661
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
662
+
663
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
664
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
665
+ }
666
+
601
667
  await axn.addSupportIxs(
602
668
  'redeem',
603
669
  includeAtaIxns,
@@ -605,7 +671,6 @@ export class KaminoAction {
605
671
  false,
606
672
  addInitObligationForFarm,
607
673
  false,
608
- scopeRefreshConfig,
609
674
  false
610
675
  );
611
676
  axn.addRedeemReserveCollateralIx();
@@ -620,14 +685,14 @@ export class KaminoAction {
620
685
  owner: PublicKey,
621
686
  obligation: KaminoObligation | ObligationType,
622
687
  useV2Ixs: boolean,
623
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
624
688
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
625
689
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas
626
690
  requestElevationGroup: boolean = false,
627
691
  includeUserMetadata: boolean = true, // if true it includes user metadata
628
692
  createLookupTable: boolean = true,
629
693
  referrer: PublicKey = PublicKey.default,
630
- currentSlot: number = 0
694
+ currentSlot: number = 0,
695
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
631
696
  ) {
632
697
  const axn = await KaminoAction.initialize(
633
698
  'depositCollateral',
@@ -645,6 +710,17 @@ export class KaminoAction {
645
710
  axn.addComputeBudgetIxn(extraComputeBudget);
646
711
  }
647
712
 
713
+ const allReserves = new PublicKeySet<PublicKey>([
714
+ ...axn.depositReserves,
715
+ ...axn.borrowReserves,
716
+ axn.reserve.address,
717
+ ]).toArray();
718
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
719
+
720
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
721
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
722
+ }
723
+
648
724
  await axn.addSupportIxs(
649
725
  'depositCollateral',
650
726
  includeAtaIxns,
@@ -652,7 +728,6 @@ export class KaminoAction {
652
728
  includeUserMetadata,
653
729
  addInitObligationForFarm,
654
730
  useV2Ixs,
655
- scopeRefreshConfig,
656
731
  createLookupTable
657
732
  );
658
733
  if (useV2Ixs) {
@@ -673,14 +748,14 @@ export class KaminoAction {
673
748
  payer: PublicKey,
674
749
  obligation: KaminoObligation | ObligationType,
675
750
  useV2Ixs: boolean,
676
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
677
751
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
678
752
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
679
753
  requestElevationGroup: boolean = false,
680
754
  includeUserMetadata: boolean = true, // if true it includes user metadata,
681
755
  createLookupTable: boolean = true,
682
756
  referrer: PublicKey = PublicKey.default,
683
- currentSlot: number = 0
757
+ currentSlot: number = 0,
758
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
684
759
  ) {
685
760
  const axn = await KaminoAction.initializeMultiTokenAction(
686
761
  kaminoMarket,
@@ -703,6 +778,18 @@ export class KaminoAction {
703
778
  axn.addComputeBudgetIxn(extraComputeBudget);
704
779
  }
705
780
 
781
+ const allReserves = new PublicKeySet<PublicKey>([
782
+ ...axn.depositReserves,
783
+ ...axn.borrowReserves,
784
+ axn.reserve.address,
785
+ axn.outflowReserve!.address,
786
+ ]).toArray();
787
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
788
+
789
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
790
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
791
+ }
792
+
706
793
  await axn.addSupportIxs(
707
794
  'deposit',
708
795
  includeAtaIxns,
@@ -710,7 +797,6 @@ export class KaminoAction {
710
797
  includeUserMetadata,
711
798
  addInitObligationForFarmForDeposit,
712
799
  useV2Ixs,
713
- undefined,
714
800
  createLookupTable,
715
801
  twoTokenAction
716
802
  );
@@ -728,20 +814,6 @@ export class KaminoAction {
728
814
  useV2Ixs
729
815
  );
730
816
  axn.addRefreshFarmsCleanupTxnIxsToCleanupIxs();
731
-
732
- // Create the scope refresh ixn in here to ensure it's the first ixn in the txn
733
- const allReserves = new PublicKeySet<PublicKey>([
734
- ...axn.depositReserves,
735
- ...axn.borrowReserves,
736
- axn.reserve.address,
737
- ...(axn.outflowReserve ? [axn.outflowReserve.address] : []),
738
- ...(axn.preLoadedDepositReservesSameTx ? axn.preLoadedDepositReservesSameTx : []),
739
- ]).toArray();
740
- const tokenIds = getTokenIdsForScopeRefresh(axn.kaminoMarket, allReserves);
741
-
742
- if (tokenIds.length > 0 && scopeRefreshConfig) {
743
- await axn.addScopeRefreshIxs(scopeRefreshConfig.scope, tokenIds, scopeRefreshConfig.scopeFeed);
744
- }
745
817
  return axn;
746
818
  }
747
819
 
@@ -755,13 +827,13 @@ export class KaminoAction {
755
827
  currentSlot: number,
756
828
  obligation: KaminoObligation | ObligationType,
757
829
  useV2Ixs: boolean,
758
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
759
830
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
760
831
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
761
832
  requestElevationGroup: boolean = false,
762
833
  includeUserMetadata: boolean = true, // if true it includes user metadata,
763
834
  createLookupTable: boolean = true,
764
- referrer: PublicKey = PublicKey.default
835
+ referrer: PublicKey = PublicKey.default,
836
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
765
837
  ) {
766
838
  const axn = await KaminoAction.initializeMultiTokenAction(
767
839
  kaminoMarket,
@@ -783,6 +855,18 @@ export class KaminoAction {
783
855
  axn.addComputeBudgetIxn(extraComputeBudget);
784
856
  }
785
857
 
858
+ const allReserves = new PublicKeySet<PublicKey>([
859
+ ...axn.depositReserves,
860
+ ...axn.borrowReserves,
861
+ axn.reserve.address,
862
+ axn.outflowReserve!.address,
863
+ ]).toArray();
864
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
865
+
866
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
867
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
868
+ }
869
+
786
870
  await axn.addSupportIxs(
787
871
  'repay',
788
872
  includeAtaIxns,
@@ -790,7 +874,6 @@ export class KaminoAction {
790
874
  includeUserMetadata,
791
875
  addInitObligationForFarmForRepay,
792
876
  useV2Ixs,
793
- undefined,
794
877
  createLookupTable,
795
878
  twoTokenAction
796
879
  );
@@ -810,19 +893,6 @@ export class KaminoAction {
810
893
  useV2Ixs
811
894
  );
812
895
  axn.addRefreshFarmsCleanupTxnIxsToCleanupIxs();
813
- // Create the scope refresh ixn in here to ensure it's the first ixn in the txn
814
- const allReserves = new PublicKeySet<PublicKey>([
815
- ...axn.depositReserves,
816
- ...axn.borrowReserves,
817
- axn.reserve.address,
818
- ...(axn.outflowReserve ? [axn.outflowReserve.address] : []),
819
- ...(axn.preLoadedDepositReservesSameTx ? axn.preLoadedDepositReservesSameTx : []),
820
- ]).toArray();
821
- const tokenIds = getTokenIdsForScopeRefresh(axn.kaminoMarket, allReserves);
822
-
823
- if (tokenIds.length > 0 && scopeRefreshConfig) {
824
- await axn.addScopeRefreshIxs(scopeRefreshConfig.scope, tokenIds, scopeRefreshConfig.scopeFeed);
825
- }
826
896
  return axn;
827
897
  }
828
898
 
@@ -833,7 +903,6 @@ export class KaminoAction {
833
903
  owner: PublicKey,
834
904
  obligation: KaminoObligation | ObligationType,
835
905
  useV2Ixs: boolean,
836
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
837
906
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
838
907
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
839
908
  requestElevationGroup: boolean = false, // to be requested *after* the withdraw
@@ -841,6 +910,7 @@ export class KaminoAction {
841
910
  createLookupTable: boolean = true,
842
911
  referrer: PublicKey = PublicKey.default,
843
912
  currentSlot: number = 0,
913
+ scopeRefresh: ScopeRefresh | undefined = undefined,
844
914
  overrideElevationGroupRequest?: number,
845
915
  // Optional customizations which may be needed if the obligation was mutated by some previous ixn.
846
916
  obligationCustomizations?: {
@@ -866,6 +936,17 @@ export class KaminoAction {
866
936
 
867
937
  axn.depositReserves.push(...(obligationCustomizations?.addedDepositReserves || []));
868
938
 
939
+ const allReserves = new PublicKeySet<PublicKey>([
940
+ ...axn.depositReserves,
941
+ ...axn.borrowReserves,
942
+ axn.reserve.address,
943
+ ]).toArray();
944
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
945
+
946
+ if (tokenIds.length > 0 && scopeRefresh && scopeRefresh.includeScopeRefresh) {
947
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
948
+ }
949
+
869
950
  await axn.addSupportIxs(
870
951
  'withdraw',
871
952
  includeAtaIxns,
@@ -873,7 +954,6 @@ export class KaminoAction {
873
954
  includeUserMetadata,
874
955
  addInitObligationForFarm,
875
956
  useV2Ixs,
876
- scopeRefreshConfig,
877
957
  createLookupTable,
878
958
  false,
879
959
  overrideElevationGroupRequest
@@ -913,7 +993,6 @@ export class KaminoAction {
913
993
  owner: PublicKey,
914
994
  obligation: KaminoObligation | ObligationType,
915
995
  useV2Ixs: boolean,
916
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
917
996
  currentSlot: number,
918
997
  payer: PublicKey | undefined = undefined,
919
998
  extraComputeBudget: number = 1_000_000,
@@ -921,7 +1000,8 @@ export class KaminoAction {
921
1000
  requestElevationGroup: boolean = false,
922
1001
  includeUserMetadata: boolean = true,
923
1002
  createLookupTable: boolean = true,
924
- referrer: PublicKey = PublicKey.default
1003
+ referrer: PublicKey = PublicKey.default,
1004
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
925
1005
  ) {
926
1006
  const axn = await KaminoAction.initialize(
927
1007
  'repay',
@@ -940,6 +1020,17 @@ export class KaminoAction {
940
1020
  axn.addComputeBudgetIxn(extraComputeBudget);
941
1021
  }
942
1022
 
1023
+ const allReserves = new PublicKeySet<PublicKey>([
1024
+ ...axn.depositReserves,
1025
+ ...axn.borrowReserves,
1026
+ axn.reserve.address,
1027
+ ]).toArray();
1028
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
1029
+
1030
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
1031
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
1032
+ }
1033
+
943
1034
  await axn.addSupportIxs(
944
1035
  'repay',
945
1036
  includeAtaIxns,
@@ -947,7 +1038,6 @@ export class KaminoAction {
947
1038
  includeUserMetadata,
948
1039
  addInitObligationForFarm,
949
1040
  useV2Ixs,
950
- scopeRefreshConfig,
951
1041
  createLookupTable
952
1042
  );
953
1043
  if (useV2Ixs) {
@@ -970,7 +1060,6 @@ export class KaminoAction {
970
1060
  obligationOwner: PublicKey,
971
1061
  obligation: KaminoObligation | ObligationType,
972
1062
  useV2Ixs: boolean,
973
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
974
1063
  extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
975
1064
  includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas, and creates all other token atas if they don't exist
976
1065
  requestElevationGroup: boolean = false,
@@ -978,7 +1067,8 @@ export class KaminoAction {
978
1067
  createLookupTable: boolean = true,
979
1068
  referrer: PublicKey = PublicKey.default,
980
1069
  maxAllowedLtvOverridePercent: number = 0,
981
- currentSlot: number = 0
1070
+ currentSlot: number = 0,
1071
+ scopeRefresh: ScopeRefresh = { includeScopeRefresh: false, scopeFeed: 'hubble' }
982
1072
  ) {
983
1073
  const axn = await KaminoAction.initializeMultiTokenAction(
984
1074
  kaminoMarket,
@@ -999,6 +1089,18 @@ export class KaminoAction {
999
1089
  axn.addComputeBudgetIxn(extraComputeBudget);
1000
1090
  }
1001
1091
 
1092
+ const allReserves = new PublicKeySet<PublicKey>([
1093
+ ...axn.depositReserves,
1094
+ ...axn.borrowReserves,
1095
+ axn.reserve.address,
1096
+ axn.outflowReserve!.address,
1097
+ ]).toArray();
1098
+ const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
1099
+
1100
+ if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
1101
+ await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
1102
+ }
1103
+
1002
1104
  await axn.addSupportIxs(
1003
1105
  'liquidate',
1004
1106
  includeAtaIxns,
@@ -1006,7 +1108,6 @@ export class KaminoAction {
1006
1108
  includeUserMetadata,
1007
1109
  addInitObligationForFarm,
1008
1110
  useV2Ixs,
1009
- scopeRefreshConfig,
1010
1111
  createLookupTable
1011
1112
  );
1012
1113
  if (useV2Ixs) {
@@ -2399,7 +2500,6 @@ export class KaminoAction {
2399
2500
  includeUserMetadata: boolean,
2400
2501
  addInitObligationForFarm: boolean,
2401
2502
  useV2Ixs: boolean,
2402
- scopeRefreshConfig: ScopePriceRefreshConfig | undefined,
2403
2503
  createLookupTable: boolean,
2404
2504
  twoTokenAction: boolean = false,
2405
2505
  overrideElevationGroupRequest?: number
@@ -2440,19 +2540,6 @@ export class KaminoAction {
2440
2540
  twoTokenAction,
2441
2541
  overrideElevationGroupRequest
2442
2542
  );
2443
-
2444
- const allReserves = new PublicKeySet<PublicKey>([
2445
- ...this.depositReserves,
2446
- ...this.borrowReserves,
2447
- this.reserve.address,
2448
- ...(this.outflowReserve ? [this.outflowReserve.address] : []),
2449
- ...(this.preLoadedDepositReservesSameTx ? this.preLoadedDepositReservesSameTx : []),
2450
- ]).toArray();
2451
- const tokenIds = getTokenIdsForScopeRefresh(this.kaminoMarket, allReserves);
2452
-
2453
- if (tokenIds.length > 0 && scopeRefreshConfig) {
2454
- await this.addScopeRefreshIxs(scopeRefreshConfig.scope, tokenIds, scopeRefreshConfig.scopeFeed);
2455
- }
2456
2543
  }
2457
2544
 
2458
2545
  private static optionalAccount(pubkey: PublicKey, programId: PublicKey = PROGRAM_ID): PublicKey {
@@ -949,7 +949,7 @@ export class KaminoManager {
949
949
  }
950
950
 
951
951
  /**
952
- * This returns an array of scope oracle configs to be used to set the scope price and twap oracles for a reserve
952
+ * This retruns an array of scope oracle configs to be used to set the scope price and twap oracles for a reserve
953
953
  * @param feed - scope feed to fetch prices from
954
954
  * @param cluster - cluster to fetch from, this should be left unchanged unless working on devnet or locally
955
955
  * @returns - an array of scope oracle configs
@@ -29,7 +29,7 @@ import Decimal from 'decimal.js';
29
29
  import { FarmState } from '@kamino-finance/farms-sdk';
30
30
  import { PROGRAM_ID } from '../idl_codegen/programId';
31
31
  import bs58 from 'bs58';
32
- import { OraclePrices, Scope, U16_MAX } from '@kamino-finance/scope-sdk';
32
+ import { OraclePrices, Scope } from '@kamino-finance/scope-sdk';
33
33
  import { Fraction } from './fraction';
34
34
  import { chunks, KaminoPrices, MintToPriceMap } from '@kamino-finance/kliquidity-sdk';
35
35
  import { parseTokenSymbol, parseZeroPaddedUtf8 } from './utils';
@@ -59,6 +59,8 @@ export class KaminoMarket {
59
59
 
60
60
  readonly programId: PublicKey;
61
61
 
62
+ scope: Scope;
63
+
62
64
  private readonly recentSlotDurationMs: number;
63
65
 
64
66
  private constructor(
@@ -66,6 +68,7 @@ export class KaminoMarket {
66
68
  state: LendingMarket,
67
69
  marketAddress: string,
68
70
  reserves: Map<PublicKey, KaminoReserve>,
71
+ scope: Scope,
69
72
  recentSlotDurationMs: number,
70
73
  programId: PublicKey = PROGRAM_ID
71
74
  ) {
@@ -75,6 +78,7 @@ export class KaminoMarket {
75
78
  this.reserves = reserves;
76
79
  this.reservesActive = getReservesActive(this.reserves);
77
80
  this.programId = programId;
81
+ this.scope = scope;
78
82
  this.recentSlotDurationMs = recentSlotDurationMs;
79
83
  }
80
84
 
@@ -93,6 +97,7 @@ export class KaminoMarket {
93
97
  marketAddress: PublicKey,
94
98
  recentSlotDurationMs: number,
95
99
  programId: PublicKey = PROGRAM_ID,
100
+ setupLocalTest: boolean = false,
96
101
  withReserves: boolean = true
97
102
  ) {
98
103
  const market = await LendingMarket.fetch(connection, marketAddress, programId);
@@ -100,12 +105,26 @@ export class KaminoMarket {
100
105
  if (market === null) {
101
106
  return null;
102
107
  }
108
+ let scope: Scope;
109
+ if (!setupLocalTest) {
110
+ scope = new Scope('mainnet-beta', connection);
111
+ } else {
112
+ scope = new Scope('localnet', connection);
113
+ }
103
114
 
104
115
  const reserves = withReserves
105
116
  ? await getReservesForMarket(marketAddress, connection, programId, recentSlotDurationMs)
106
117
  : new Map<PublicKey, KaminoReserve>();
107
118
 
108
- return new KaminoMarket(connection, market, marketAddress.toString(), reserves, recentSlotDurationMs, programId);
119
+ return new KaminoMarket(
120
+ connection,
121
+ market,
122
+ marketAddress.toString(),
123
+ reserves,
124
+ scope,
125
+ recentSlotDurationMs,
126
+ programId
127
+ );
109
128
  }
110
129
 
111
130
  async reload(): Promise<void> {
@@ -1167,9 +1186,9 @@ export class KaminoMarket {
1167
1186
  /**
1168
1187
  * Get all Scope prices used by all the market reserves
1169
1188
  */
1170
- async getAllScopePrices(scope: Scope, oraclePrices?: OraclePrices): Promise<KaminoPrices> {
1189
+ async getAllScopePrices(oraclePrices?: OraclePrices): Promise<KaminoPrices> {
1171
1190
  if (!oraclePrices) {
1172
- oraclePrices = await scope.getOraclePrices();
1191
+ oraclePrices = await this.scope.getOraclePrices();
1173
1192
  }
1174
1193
  const spot: MintToPriceMap = {};
1175
1194
  const twaps: MintToPriceMap = {};
@@ -1180,11 +1199,11 @@ export class KaminoMarket {
1180
1199
  const chain = reserve.state.config.tokenInfo.scopeConfiguration.priceChain;
1181
1200
  const twapChain = reserve.state.config.tokenInfo.scopeConfiguration.twapChain.filter((x) => x > 0);
1182
1201
  if (oracle && isNotNullPubkey(oracle) && chain && Scope.isScopeChainValid(chain)) {
1183
- const spotPrice = await scope.getPriceFromChain(chain, oraclePrices);
1202
+ const spotPrice = await this.scope.getPriceFromChain(chain, oraclePrices);
1184
1203
  spot[tokenMint] = { price: spotPrice.price, name: tokenName };
1185
1204
  }
1186
1205
  if (oracle && isNotNullPubkey(oracle) && twapChain && Scope.isScopeChainValid(twapChain)) {
1187
- const twap = await scope.getPriceFromChain(twapChain, oraclePrices);
1206
+ const twap = await this.scope.getPriceFromChain(twapChain, oraclePrices);
1188
1207
  twaps[tokenMint] = { price: twap.price, name: tokenName };
1189
1208
  }
1190
1209
  }
@@ -1508,34 +1527,6 @@ export function getReservesActive(reserves: Map<PublicKey, KaminoReserve>): Map<
1508
1527
  return reservesActive;
1509
1528
  }
1510
1529
 
1511
- export function getTokenIdsForScopeRefresh(kaminoMarket: KaminoMarket, reserves: PublicKey[]): number[] {
1512
- const tokenIds: number[] = [];
1513
-
1514
- for (const reserveAddress of reserves) {
1515
- const reserve = kaminoMarket.getReserveByAddress(reserveAddress);
1516
- if (!reserve) {
1517
- throw new Error(`Reserve not found for reserve ${reserveAddress.toBase58()}`);
1518
- }
1519
-
1520
- if (!reserve.state.config.tokenInfo.scopeConfiguration.priceFeed.equals(PublicKey.default)) {
1521
- let x = 0;
1522
-
1523
- while (reserve.state.config.tokenInfo.scopeConfiguration.priceChain[x] !== U16_MAX) {
1524
- tokenIds.push(reserve.state.config.tokenInfo.scopeConfiguration.priceChain[x]);
1525
- x++;
1526
- }
1527
-
1528
- x = 0;
1529
- while (reserve.state.config.tokenInfo.scopeConfiguration.twapChain[x] !== U16_MAX) {
1530
- tokenIds.push(reserve.state.config.tokenInfo.scopeConfiguration.twapChain[x]);
1531
- x++;
1532
- }
1533
- }
1534
- }
1535
-
1536
- return tokenIds;
1537
- }
1538
-
1539
1530
  export async function getReserveFromMintAndMarket(
1540
1531
  connection: Connection,
1541
1532
  market: KaminoMarket,
@@ -17,7 +17,6 @@ import {
17
17
  getObligationPdaWithArgs,
18
18
  getObligationType,
19
19
  isNotNullPubkey,
20
- ObligationType,
21
20
  PubkeyHashMap,
22
21
  TOTAL_NUMBER_OF_IDS_TO_CHECK,
23
22
  U64_MAX,
@@ -1594,8 +1593,3 @@ export class KaminoObligation {
1594
1593
  }
1595
1594
  }
1596
1595
  }
1597
-
1598
- // Create a function that checks if an obligation is of type obligation or obligationType
1599
- export function isKaminoObligation(obligation: KaminoObligation | ObligationType): obligation is KaminoObligation {
1600
- return 'obligationAddress' in obligation;
1601
- }