@kamino-finance/klend-sdk 5.0.3 → 5.0.4

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 (111) hide show
  1. package/dist/classes/fraction.d.ts.map +1 -1
  2. package/dist/classes/fraction.js.map +1 -1
  3. package/dist/classes/manager.d.ts.map +1 -1
  4. package/dist/classes/manager.js +1 -14
  5. package/dist/classes/manager.js.map +1 -1
  6. package/dist/classes/market.d.ts +0 -4
  7. package/dist/classes/market.d.ts.map +1 -1
  8. package/dist/classes/market.js +0 -15
  9. package/dist/classes/market.js.map +1 -1
  10. package/dist/classes/obligation.d.ts.map +1 -1
  11. package/dist/classes/obligation.js +1 -2
  12. package/dist/classes/obligation.js.map +1 -1
  13. package/dist/classes/reserve.d.ts +0 -1
  14. package/dist/classes/reserve.d.ts.map +1 -1
  15. package/dist/classes/reserve.js +27 -22
  16. package/dist/classes/reserve.js.map +1 -1
  17. package/dist/classes/utils.d.ts +0 -3
  18. package/dist/classes/utils.d.ts.map +1 -1
  19. package/dist/classes/utils.js +0 -30
  20. package/dist/classes/utils.js.map +1 -1
  21. package/dist/client_kamino_manager.js +1 -1
  22. package/dist/client_kamino_manager.js.map +1 -1
  23. package/dist/idl.json +2 -27
  24. package/dist/idl_codegen/accounts/LendingMarket.d.ts +0 -6
  25. package/dist/idl_codegen/accounts/LendingMarket.d.ts.map +1 -1
  26. package/dist/idl_codegen/accounts/LendingMarket.js +1 -8
  27. package/dist/idl_codegen/accounts/LendingMarket.js.map +1 -1
  28. package/dist/idl_codegen/accounts/Obligation.d.ts +12 -3
  29. package/dist/idl_codegen/accounts/Obligation.d.ts.map +1 -1
  30. package/dist/idl_codegen/accounts/Obligation.js +4 -1
  31. package/dist/idl_codegen/accounts/Obligation.js.map +1 -1
  32. package/dist/idl_codegen/types/UpdateLendingMarketConfigValue.d.ts +0 -20
  33. package/dist/idl_codegen/types/UpdateLendingMarketConfigValue.d.ts.map +1 -1
  34. package/dist/idl_codegen/types/UpdateLendingMarketConfigValue.js +1 -33
  35. package/dist/idl_codegen/types/UpdateLendingMarketConfigValue.js.map +1 -1
  36. package/dist/idl_codegen/types/UpdateLendingMarketMode.d.ts +0 -13
  37. package/dist/idl_codegen/types/UpdateLendingMarketMode.d.ts.map +1 -1
  38. package/dist/idl_codegen/types/UpdateLendingMarketMode.js +1 -25
  39. package/dist/idl_codegen/types/UpdateLendingMarketMode.js.map +1 -1
  40. package/dist/idl_codegen/types/index.d.ts +4 -4
  41. package/dist/idl_codegen/types/index.d.ts.map +1 -1
  42. package/dist/idl_codegen/types/index.js.map +1 -1
  43. package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
  44. package/dist/lending_operations/repay_with_collateral_operations.js +6 -0
  45. package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
  46. package/dist/leverage/calcs.d.ts +28 -1
  47. package/dist/leverage/calcs.d.ts.map +1 -1
  48. package/dist/leverage/calcs.js +204 -8
  49. package/dist/leverage/calcs.js.map +1 -1
  50. package/dist/leverage/index.d.ts +1 -0
  51. package/dist/leverage/index.d.ts.map +1 -1
  52. package/dist/leverage/index.js +1 -0
  53. package/dist/leverage/index.js.map +1 -1
  54. package/dist/leverage/operations.d.ts +14 -241
  55. package/dist/leverage/operations.d.ts.map +1 -1
  56. package/dist/leverage/operations.js +508 -776
  57. package/dist/leverage/operations.js.map +1 -1
  58. package/dist/leverage/types.d.ts +173 -0
  59. package/dist/leverage/types.d.ts.map +1 -0
  60. package/dist/leverage/types.js +3 -0
  61. package/dist/leverage/types.js.map +1 -0
  62. package/dist/leverage/utils.d.ts +5 -5
  63. package/dist/leverage/utils.d.ts.map +1 -1
  64. package/dist/leverage/utils.js +68 -33
  65. package/dist/leverage/utils.js.map +1 -1
  66. package/dist/utils/ObligationType.d.ts.map +1 -1
  67. package/dist/utils/ObligationType.js.map +1 -1
  68. package/dist/utils/constants.d.ts +1 -0
  69. package/dist/utils/constants.d.ts.map +1 -1
  70. package/dist/utils/constants.js +2 -1
  71. package/dist/utils/constants.js.map +1 -1
  72. package/dist/utils/fuzz.d.ts +3 -0
  73. package/dist/utils/fuzz.d.ts.map +1 -0
  74. package/dist/utils/fuzz.js +11 -0
  75. package/dist/utils/fuzz.js.map +1 -0
  76. package/dist/utils/index.d.ts +1 -0
  77. package/dist/utils/index.d.ts.map +1 -1
  78. package/dist/utils/index.js +1 -0
  79. package/dist/utils/index.js.map +1 -1
  80. package/dist/utils/managerTypes.d.ts.map +1 -1
  81. package/dist/utils/managerTypes.js.map +1 -1
  82. package/dist/utils/pubkey.d.ts.map +1 -1
  83. package/dist/utils/pubkey.js.map +1 -1
  84. package/dist/utils/rpc.d.ts.map +1 -1
  85. package/dist/utils/rpc.js.map +1 -1
  86. package/package.json +1 -1
  87. package/src/classes/fraction.ts +0 -5
  88. package/src/classes/manager.ts +1 -14
  89. package/src/classes/market.ts +1 -18
  90. package/src/classes/obligation.ts +1 -2
  91. package/src/classes/reserve.ts +39 -55
  92. package/src/classes/utils.ts +0 -30
  93. package/src/client_kamino_manager.ts +1 -1
  94. package/src/idl_codegen/accounts/LendingMarket.ts +1 -12
  95. package/src/idl_codegen/accounts/Obligation.ts +12 -3
  96. package/src/idl_codegen/types/UpdateLendingMarketConfigValue.ts +0 -43
  97. package/src/idl_codegen/types/UpdateLendingMarketMode.ts +0 -30
  98. package/src/idl_codegen/types/index.ts +0 -4
  99. package/src/lending_operations/repay_with_collateral_operations.ts +2 -0
  100. package/src/leverage/calcs.ts +315 -8
  101. package/src/leverage/index.ts +1 -0
  102. package/src/leverage/operations.ts +1079 -1331
  103. package/src/leverage/types.ts +211 -0
  104. package/src/leverage/utils.ts +103 -64
  105. package/src/utils/ObligationType.ts +0 -6
  106. package/src/utils/constants.ts +2 -0
  107. package/src/utils/fuzz.ts +5 -0
  108. package/src/utils/index.ts +1 -0
  109. package/src/utils/managerTypes.ts +0 -1
  110. package/src/utils/pubkey.ts +0 -2
  111. package/src/utils/rpc.ts +0 -1
@@ -142,29 +142,6 @@ export const parseTokenSymbol = (tokenSymbol: number[]): string => {
142
142
  return String.fromCharCode(...tokenSymbol.filter((x) => x > 0));
143
143
  };
144
144
 
145
- export function parseZeroPaddedUtf8(utf8Array: number[]): string {
146
- for (let last = utf8Array.length - 1; last >= 0; last--) {
147
- const trailing_zero = utf8Array[last];
148
- if (trailing_zero != 0) {
149
- const encoding = new Uint8Array(last + 1);
150
- for (let i = 0; i <= last; i++) {
151
- encoding[i] = utf8Array[i];
152
- }
153
- break;
154
- }
155
- }
156
- return new TextDecoder().decode();
157
- }
158
-
159
- export function renderZeroPaddedUtf8(str: string, utf8ArrayLength: number): number[] {
160
- const encoding = new TextEncoder().encode(str);
161
- const result = new Array<number>(utf8ArrayLength);
162
- for (let i = 0; i < result.length; i++) {
163
- result[i] = i < encoding.length ? encoding[i] : 0;
164
- }
165
- return result;
166
- }
167
-
168
145
  export function sleep(ms: number) {
169
146
  return new Promise((resolve) => setTimeout(resolve, ms));
170
147
  }
@@ -213,10 +190,3 @@ export function calculateAPRFromAPY(apy: Decimal.Value) {
213
190
  .minus(1)
214
191
  .times(SLOTS_PER_YEAR);
215
192
  }
216
-
217
- export function sameLengthArrayEquals(left: Array<number>, right: Array<number>): boolean {
218
- if (left.length != right.length) {
219
- throw new Error(`Not same length: ${left.length} != ${left.length}`);
220
- }
221
- return left.every((value, index) => value === right[index]);
222
- }
@@ -87,7 +87,7 @@ async function main() {
87
87
 
88
88
  commands
89
89
  .command('add-asset-to-market')
90
- .requiredOption('--market <string>', 'Market address to add asset to')
90
+ .requiredOption('--market <string>', 'Market addres to add asset to')
91
91
  .requiredOption('--mint <string>', 'Reserve liquidity token mint')
92
92
  .requiredOption('--mint-program-id <string>', 'Reserve liquidity token mint program id')
93
93
  .requiredOption('--reserve-config-path <string>', 'Path for the reserve config')
@@ -51,8 +51,6 @@ export interface LendingMarketFields {
51
51
  /** Min net value accepted to be found in a position after any lending action in an obligation (scaled by quote currency decimals) */
52
52
  minNetValueInObligationSf: BN
53
53
  minValueSkipLiquidationLtvBfChecks: BN
54
- /** Market name, zero-padded. */
55
- name: Array<number>
56
54
  padding1: Array<BN>
57
55
  }
58
56
 
@@ -103,8 +101,6 @@ export interface LendingMarketJSON {
103
101
  /** Min net value accepted to be found in a position after any lending action in an obligation (scaled by quote currency decimals) */
104
102
  minNetValueInObligationSf: string
105
103
  minValueSkipLiquidationLtvBfChecks: string
106
- /** Market name, zero-padded. */
107
- name: Array<number>
108
104
  padding1: Array<string>
109
105
  }
110
106
 
@@ -155,8 +151,6 @@ export class LendingMarket {
155
151
  /** Min net value accepted to be found in a position after any lending action in an obligation (scaled by quote currency decimals) */
156
152
  readonly minNetValueInObligationSf: BN
157
153
  readonly minValueSkipLiquidationLtvBfChecks: BN
158
- /** Market name, zero-padded. */
159
- readonly name: Array<number>
160
154
  readonly padding1: Array<BN>
161
155
 
162
156
  static readonly discriminator = Buffer.from([
@@ -186,8 +180,7 @@ export class LendingMarket {
186
180
  borsh.array(borsh.u64(), 90, "elevationGroupPadding"),
187
181
  borsh.u128("minNetValueInObligationSf"),
188
182
  borsh.u64("minValueSkipLiquidationLtvBfChecks"),
189
- borsh.array(borsh.u8(), 32, "name"),
190
- borsh.array(borsh.u64(), 173, "padding1"),
183
+ borsh.array(borsh.u64(), 177, "padding1"),
191
184
  ])
192
185
 
193
186
  constructor(fields: LendingMarketFields) {
@@ -219,7 +212,6 @@ export class LendingMarket {
219
212
  this.minNetValueInObligationSf = fields.minNetValueInObligationSf
220
213
  this.minValueSkipLiquidationLtvBfChecks =
221
214
  fields.minValueSkipLiquidationLtvBfChecks
222
- this.name = fields.name
223
215
  this.padding1 = fields.padding1
224
216
  }
225
217
 
@@ -295,7 +287,6 @@ export class LendingMarket {
295
287
  minNetValueInObligationSf: dec.minNetValueInObligationSf,
296
288
  minValueSkipLiquidationLtvBfChecks:
297
289
  dec.minValueSkipLiquidationLtvBfChecks,
298
- name: dec.name,
299
290
  padding1: dec.padding1,
300
291
  })
301
292
  }
@@ -329,7 +320,6 @@ export class LendingMarket {
329
320
  minNetValueInObligationSf: this.minNetValueInObligationSf.toString(),
330
321
  minValueSkipLiquidationLtvBfChecks:
331
322
  this.minValueSkipLiquidationLtvBfChecks.toString(),
332
- name: this.name,
333
323
  padding1: this.padding1.map((item) => item.toString()),
334
324
  }
335
325
  }
@@ -368,7 +358,6 @@ export class LendingMarket {
368
358
  minValueSkipLiquidationLtvBfChecks: new BN(
369
359
  obj.minValueSkipLiquidationLtvBfChecks
370
360
  ),
371
- name: obj.name,
372
361
  padding1: obj.padding1.map((item) => new BN(item)),
373
362
  })
374
363
  }
@@ -13,7 +13,10 @@ export interface ObligationFields {
13
13
  lendingMarket: PublicKey
14
14
  /** Owner authority which can borrow liquidity */
15
15
  owner: PublicKey
16
- /** Deposited collateral for the obligation, unique by deposit reserve address */
16
+ /**
17
+ * TODO: Does this break the stack size when copied onto the stack, if too big?
18
+ * Deposited collateral for the obligation, unique by deposit reserve address
19
+ */
17
20
  deposits: Array<types.ObligationCollateralFields>
18
21
  /** Worst LTV for the collaterals backing the loan, represented as a percentage */
19
22
  lowestReserveDepositLiquidationLtv: BN
@@ -57,7 +60,10 @@ export interface ObligationJSON {
57
60
  lendingMarket: string
58
61
  /** Owner authority which can borrow liquidity */
59
62
  owner: string
60
- /** Deposited collateral for the obligation, unique by deposit reserve address */
63
+ /**
64
+ * TODO: Does this break the stack size when copied onto the stack, if too big?
65
+ * Deposited collateral for the obligation, unique by deposit reserve address
66
+ */
61
67
  deposits: Array<types.ObligationCollateralJSON>
62
68
  /** Worst LTV for the collaterals backing the loan, represented as a percentage */
63
69
  lowestReserveDepositLiquidationLtv: string
@@ -102,7 +108,10 @@ export class Obligation {
102
108
  readonly lendingMarket: PublicKey
103
109
  /** Owner authority which can borrow liquidity */
104
110
  readonly owner: PublicKey
105
- /** Deposited collateral for the obligation, unique by deposit reserve address */
111
+ /**
112
+ * TODO: Does this break the stack size when copied onto the stack, if too big?
113
+ * Deposited collateral for the obligation, unique by deposit reserve address
114
+ */
106
115
  readonly deposits: Array<types.ObligationCollateral>
107
116
  /** Worst LTV for the collaterals backing the loan, represented as a percentage */
108
117
  readonly lowestReserveDepositLiquidationLtv: BN
@@ -283,41 +283,6 @@ export class ElevationGroup {
283
283
  }
284
284
  }
285
285
 
286
- export type NameFields = [Array<number>]
287
- export type NameValue = [Array<number>]
288
-
289
- export interface NameJSON {
290
- kind: "Name"
291
- value: [Array<number>]
292
- }
293
-
294
- export class Name {
295
- static readonly discriminator = 8
296
- static readonly kind = "Name"
297
- readonly discriminator = 8
298
- readonly kind = "Name"
299
- readonly value: NameValue
300
-
301
- constructor(value: NameFields) {
302
- this.value = [value[0]]
303
- }
304
-
305
- toJSON(): NameJSON {
306
- return {
307
- kind: "Name",
308
- value: [this.value[0]],
309
- }
310
- }
311
-
312
- toEncodable() {
313
- return {
314
- Name: {
315
- _0: this.value[0],
316
- },
317
- }
318
- }
319
- }
320
-
321
286
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
322
287
  export function fromDecoded(
323
288
  obj: any
@@ -358,10 +323,6 @@ export function fromDecoded(
358
323
  const val = obj["ElevationGroup"]
359
324
  return new ElevationGroup([types.ElevationGroup.fromDecoded(val["_0"])])
360
325
  }
361
- if ("Name" in obj) {
362
- const val = obj["Name"]
363
- return new Name([val["_0"]])
364
- }
365
326
 
366
327
  throw new Error("Invalid enum object")
367
328
  }
@@ -394,9 +355,6 @@ export function fromJSON(
394
355
  case "ElevationGroup": {
395
356
  return new ElevationGroup([types.ElevationGroup.fromJSON(obj.value[0])])
396
357
  }
397
- case "Name": {
398
- return new Name([obj.value[0]])
399
- }
400
358
  }
401
359
  }
402
360
 
@@ -410,7 +368,6 @@ export function layout(property?: string) {
410
368
  borsh.struct([borsh.u128("_0")], "U128"),
411
369
  borsh.struct([borsh.publicKey("_0")], "Pubkey"),
412
370
  borsh.struct([types.ElevationGroup.layout("_0")], "ElevationGroup"),
413
- borsh.struct([borsh.array(borsh.u8(), 32, "_0")], "Name"),
414
371
  ])
415
372
  if (property !== undefined) {
416
373
  return ret.replicate(property)
@@ -417,29 +417,6 @@ export class UpdatePaddingFields {
417
417
  }
418
418
  }
419
419
 
420
- export interface UpdateNameJSON {
421
- kind: "UpdateName"
422
- }
423
-
424
- export class UpdateName {
425
- static readonly discriminator = 18
426
- static readonly kind = "UpdateName"
427
- readonly discriminator = 18
428
- readonly kind = "UpdateName"
429
-
430
- toJSON(): UpdateNameJSON {
431
- return {
432
- kind: "UpdateName",
433
- }
434
- }
435
-
436
- toEncodable() {
437
- return {
438
- UpdateName: {},
439
- }
440
- }
441
- }
442
-
443
420
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
444
421
  export function fromDecoded(obj: any): types.UpdateLendingMarketModeKind {
445
422
  if (typeof obj !== "object") {
@@ -500,9 +477,6 @@ export function fromDecoded(obj: any): types.UpdateLendingMarketModeKind {
500
477
  if ("UpdatePaddingFields" in obj) {
501
478
  return new UpdatePaddingFields()
502
479
  }
503
- if ("UpdateName" in obj) {
504
- return new UpdateName()
505
- }
506
480
 
507
481
  throw new Error("Invalid enum object")
508
482
  }
@@ -565,9 +539,6 @@ export function fromJSON(
565
539
  case "UpdatePaddingFields": {
566
540
  return new UpdatePaddingFields()
567
541
  }
568
- case "UpdateName": {
569
- return new UpdateName()
570
- }
571
542
  }
572
543
  }
573
544
 
@@ -591,7 +562,6 @@ export function layout(property?: string) {
591
562
  borsh.struct([], "UpdateMinNetValueObligationPostAction"),
592
563
  borsh.struct([], "UpdateMinValueSkipPriorityLiqCheck"),
593
564
  borsh.struct([], "UpdatePaddingFields"),
594
- borsh.struct([], "UpdateName"),
595
565
  ])
596
566
  if (property !== undefined) {
597
567
  return ret.replicate(property)
@@ -116,7 +116,6 @@ export type UpdateLendingMarketConfigValueKind =
116
116
  | UpdateLendingMarketConfigValue.U128
117
117
  | UpdateLendingMarketConfigValue.Pubkey
118
118
  | UpdateLendingMarketConfigValue.ElevationGroup
119
- | UpdateLendingMarketConfigValue.Name
120
119
  export type UpdateLendingMarketConfigValueJSON =
121
120
  | UpdateLendingMarketConfigValue.BoolJSON
122
121
  | UpdateLendingMarketConfigValue.U8JSON
@@ -126,7 +125,6 @@ export type UpdateLendingMarketConfigValueJSON =
126
125
  | UpdateLendingMarketConfigValue.U128JSON
127
126
  | UpdateLendingMarketConfigValue.PubkeyJSON
128
127
  | UpdateLendingMarketConfigValue.ElevationGroupJSON
129
- | UpdateLendingMarketConfigValue.NameJSON
130
128
 
131
129
  export { UpdateLendingMarketMode }
132
130
 
@@ -149,7 +147,6 @@ export type UpdateLendingMarketModeKind =
149
147
  | UpdateLendingMarketMode.UpdateMinNetValueObligationPostAction
150
148
  | UpdateLendingMarketMode.UpdateMinValueSkipPriorityLiqCheck
151
149
  | UpdateLendingMarketMode.UpdatePaddingFields
152
- | UpdateLendingMarketMode.UpdateName
153
150
  export type UpdateLendingMarketModeJSON =
154
151
  | UpdateLendingMarketMode.UpdateOwnerJSON
155
152
  | UpdateLendingMarketMode.UpdateEmergencyModeJSON
@@ -169,7 +166,6 @@ export type UpdateLendingMarketModeJSON =
169
166
  | UpdateLendingMarketMode.UpdateMinNetValueObligationPostActionJSON
170
167
  | UpdateLendingMarketMode.UpdateMinValueSkipPriorityLiqCheckJSON
171
168
  | UpdateLendingMarketMode.UpdatePaddingFieldsJSON
172
- | UpdateLendingMarketMode.UpdateNameJSON
173
169
 
174
170
  export { LastUpdate } from "./LastUpdate"
175
171
  export type { LastUpdateFields, LastUpdateJSON } from "./LastUpdate"
@@ -107,6 +107,7 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
107
107
  inputAmountLamports: withdrawableCollLamports,
108
108
  inputMint: collTokenMint,
109
109
  outputMint: debtTokenMint,
110
+ amountDebtAtaBalance: new Decimal(0), // only used for kTokens
110
111
  };
111
112
 
112
113
  // Build the repay & withdraw collateral tx to get the number of accounts
@@ -143,6 +144,7 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
143
144
  inputAmountLamports: collSwapInLamports,
144
145
  inputMint: collTokenMint,
145
146
  outputMint: debtTokenMint,
147
+ amountDebtAtaBalance: new Decimal(0), // only used for kTokens
146
148
  },
147
149
  initialInputs: {
148
150
  debtRepayAmountLamports: repayAmountLamports,
@@ -1,6 +1,15 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
2
  import Decimal from 'decimal.js';
3
- import { Kamino, StrategyWithAddress, TokenAmounts } from '@kamino-finance/kliquidity-sdk';
3
+ import { collToLamportsDecimal, Kamino, StrategyWithAddress, TokenAmounts } from '@kamino-finance/kliquidity-sdk';
4
+ import { KaminoMarket, KaminoObligation, KaminoReserve } from '../classes';
5
+ import { getExpectedTokenBalanceAfterBorrow } from './utils';
6
+ import {
7
+ AdjustLeverageCalcsResult,
8
+ DepositLeverageCalcsResult,
9
+ PriceAinBProvider,
10
+ WithdrawLeverageCalcsResult,
11
+ } from './types';
12
+ import { fuzzyEqual } from '../utils';
4
13
 
5
14
  export const toJson = (object: any): string => {
6
15
  return JSON.stringify(object, null, 2);
@@ -126,9 +135,13 @@ export async function calculateMultiplyEffects(
126
135
  isClosingPosition =
127
136
  (withdrawModeEstimatedDepositTokenWithdrawn.gte(new Decimal(deposited)) ||
128
137
  withdrawModeEstimatedBorrowTokenWithdrawn.gte(new Decimal(borrowed)) ||
129
- fuzzyEq(withdrawModeEstimatedDepositTokenWithdrawn, new Decimal(deposited), closingPositionDiffTolerance) ||
130
- fuzzyEq(withdrawModeEstimatedBorrowTokenWithdrawn, new Decimal(borrowed), closingPositionDiffTolerance)) &&
131
- !fuzzyEq(withdrawModeEstimatedDepositTokenWithdrawn, new Decimal(0), closingPositionDiffTolerance);
138
+ fuzzyEqual(
139
+ withdrawModeEstimatedDepositTokenWithdrawn,
140
+ new Decimal(deposited),
141
+ closingPositionDiffTolerance
142
+ ) ||
143
+ fuzzyEqual(withdrawModeEstimatedBorrowTokenWithdrawn, new Decimal(borrowed), closingPositionDiffTolerance)) &&
144
+ !fuzzyEqual(withdrawModeEstimatedDepositTokenWithdrawn, new Decimal(0), closingPositionDiffTolerance);
132
145
 
133
146
  totalDeposited = isClosingPosition ? new Decimal(0) : deposited.sub(withdrawModeEstimatedDepositTokenWithdrawn);
134
147
  totalBorrowed = isClosingPosition ? new Decimal(0) : borrowed.sub(withdrawModeEstimatedBorrowTokenWithdrawn);
@@ -270,10 +283,6 @@ export function calcWithdrawAmounts(params: WithdrawParams): WithdrawResult {
270
283
  };
271
284
  }
272
285
 
273
- export const fuzzyEq = (a: Decimal.Value, b: Decimal.Value, epsilon = 0.0001) => {
274
- return new Decimal(a).sub(b).abs().lte(epsilon);
275
- };
276
-
277
286
  interface UseEstimateAdjustAmountsProps {
278
287
  targetLeverage: Decimal;
279
288
  debtTokenMint: PublicKey;
@@ -463,3 +472,301 @@ export async function simulateMintKToken(
463
472
 
464
473
  return [requiredA, requiredB, actualMint];
465
474
  }
475
+
476
+ export const depositLeverageCalcs = (props: {
477
+ depositAmount: Decimal;
478
+ depositTokenIsCollToken: boolean;
479
+ depositTokenIsSol: boolean;
480
+ priceDebtToColl: Decimal;
481
+ targetLeverage: Decimal;
482
+ slippagePct: Decimal;
483
+ flashLoanFee: Decimal;
484
+ }): DepositLeverageCalcsResult => {
485
+ // Initialize local variables from the props object
486
+ const {
487
+ depositAmount,
488
+ depositTokenIsCollToken,
489
+ depositTokenIsSol,
490
+ priceDebtToColl,
491
+ targetLeverage,
492
+ slippagePct,
493
+ flashLoanFee,
494
+ } = props;
495
+ const slippage = slippagePct.div('100');
496
+
497
+ const initDepositInSol = depositTokenIsSol ? depositAmount : new Decimal(0);
498
+
499
+ // Core logic
500
+ if (depositTokenIsCollToken) {
501
+ const y = targetLeverage.mul(priceDebtToColl);
502
+ const x = flashLoanFee.add('1').mul(slippage.add('1')).div(priceDebtToColl);
503
+ const finalColl = depositAmount.mul(x).div(x.sub(targetLeverage.sub('1').div(y)));
504
+ const debt = finalColl.sub(depositAmount).mul(x);
505
+ const flashBorrowColl = finalColl.sub(depositAmount).mul(flashLoanFee.add('1'));
506
+
507
+ return {
508
+ flashBorrowInCollToken: flashBorrowColl,
509
+ initDepositInSol,
510
+ debtTokenToBorrow: debt,
511
+ collTokenToDeposit: finalColl,
512
+ swapDebtTokenIn: debt,
513
+ swapCollTokenExpectedOut: finalColl.sub(depositAmount),
514
+ flashBorrowInDebtTokenKtokenOnly: new Decimal(0),
515
+ singleSidedDepositKtokenOnly: new Decimal(0),
516
+ requiredCollateralKtokenOnly: new Decimal(0),
517
+ };
518
+ } else {
519
+ const y = targetLeverage.mul(priceDebtToColl);
520
+ const x = flashLoanFee.add('1').mul(slippage.add('1')).div(priceDebtToColl);
521
+ const finalColl = depositAmount.div(x.sub(targetLeverage.sub('1').div(y)));
522
+ const flashBorrowColl = finalColl.mul(flashLoanFee.add('1'));
523
+ const debt = targetLeverage.sub('1').mul(finalColl).div(y);
524
+
525
+ return {
526
+ flashBorrowInCollToken: flashBorrowColl,
527
+ initDepositInSol,
528
+ debtTokenToBorrow: debt,
529
+ collTokenToDeposit: finalColl,
530
+ swapDebtTokenIn: debt.add(depositAmount),
531
+ swapCollTokenExpectedOut: finalColl,
532
+ flashBorrowInDebtTokenKtokenOnly: new Decimal(0),
533
+ singleSidedDepositKtokenOnly: new Decimal(0),
534
+ requiredCollateralKtokenOnly: new Decimal(0),
535
+ };
536
+ }
537
+ };
538
+
539
+ export const depositLeverageKtokenCalcs = async (props: {
540
+ kamino: Kamino;
541
+ strategy: StrategyWithAddress;
542
+ debtTokenMint: PublicKey;
543
+ depositAmount: Decimal;
544
+ depositTokenIsCollToken: boolean;
545
+ depositTokenIsSol: boolean;
546
+ priceDebtToColl: Decimal;
547
+ targetLeverage: Decimal;
548
+ slippagePct: Decimal;
549
+ flashLoanFee: Decimal;
550
+ priceAinB: PriceAinBProvider;
551
+ strategyHoldings?: TokenAmounts;
552
+ }): Promise<DepositLeverageCalcsResult> => {
553
+ const {
554
+ kamino,
555
+ strategy,
556
+ debtTokenMint,
557
+ depositAmount,
558
+ depositTokenIsCollToken,
559
+ depositTokenIsSol,
560
+ priceDebtToColl,
561
+ targetLeverage,
562
+ slippagePct,
563
+ flashLoanFee,
564
+ priceAinB,
565
+ strategyHoldings,
566
+ } = props;
567
+ const initDepositInSol = depositTokenIsSol ? depositAmount : new Decimal(0);
568
+ const slippage = slippagePct.div('100');
569
+
570
+ let flashBorrowInDebtToken: Decimal;
571
+ let collTokenToDeposit: Decimal;
572
+ let debtTokenToBorrow: Decimal;
573
+
574
+ if (depositTokenIsCollToken) {
575
+ const x = slippage.add('1').div(priceDebtToColl);
576
+ const y = flashLoanFee.add('1').mul(priceDebtToColl);
577
+ const z = targetLeverage.mul(y).div(targetLeverage.sub(1));
578
+ flashBorrowInDebtToken = depositAmount.div(z.minus(new Decimal(1).div(x)));
579
+ collTokenToDeposit = depositAmount.add(flashBorrowInDebtToken.div(x));
580
+ debtTokenToBorrow = flashBorrowInDebtToken.mul(new Decimal(1).add(flashLoanFee));
581
+
582
+ return {
583
+ flashBorrowInCollToken: new Decimal(0),
584
+ initDepositInSol,
585
+ collTokenToDeposit,
586
+ debtTokenToBorrow,
587
+ swapDebtTokenIn: new Decimal(0),
588
+ swapCollTokenExpectedOut: new Decimal(0),
589
+ flashBorrowInDebtTokenKtokenOnly: flashBorrowInDebtToken,
590
+ requiredCollateralKtokenOnly: collTokenToDeposit.sub(depositAmount), // Assuming netValue is requiredCollateral, adjust as needed
591
+ singleSidedDepositKtokenOnly: flashBorrowInDebtToken,
592
+ };
593
+ } else {
594
+ const y = targetLeverage.mul(priceDebtToColl);
595
+ // although we will only swap ~half of the debt token, we account for the slippage on the entire amount as we are working backwards from the minimum collateral and do not know the exact swap proportion in advance
596
+ // This also allows for some variation in the pool ratios between calculation + submitting the tx
597
+ const x = flashLoanFee.add('1').mul(slippage.add('1')).div(priceDebtToColl);
598
+ // Calculate the amount of collateral tokens we will deposit in order to achieve the desired leverage after swapping a portion of the debt token and flash loan fees
599
+ const finalColl = depositAmount.div(x.sub(targetLeverage.sub('1').div(y)));
600
+ // Calculate how many A and B tokens we will need to actually mint the desired amount of ktoken collateral
601
+ // The actual amount of ktokens received may be less than the finalColl due to smart proportional contract logic
602
+ // So we use the actualColl as the amount we will deposit
603
+ const [estimatedA, estimatedB, actualColl] = await simulateMintKToken(
604
+ kamino!,
605
+ strategy!,
606
+ finalColl,
607
+ strategyHoldings
608
+ );
609
+ const pxAinB = await priceAinB(strategy!.strategy.tokenAMint, strategy!.strategy.tokenBMint);
610
+ const isTokenADeposit = strategy.strategy.tokenAMint.equals(debtTokenMint);
611
+ // Calculate the amount we need to flash borrow by combining value of A and B into the debt token
612
+ const singleSidedDepositAmount = isTokenADeposit
613
+ ? estimatedA.add(estimatedB.div(pxAinB))
614
+ : estimatedB.add(estimatedA.mul(pxAinB));
615
+
616
+ // Add slippage to the entire amount, add flash loan fee to part we will flash borrow
617
+ flashBorrowInDebtToken = singleSidedDepositAmount
618
+ .div(new Decimal('1').sub(slippage))
619
+ .sub(depositAmount)
620
+ .div(new Decimal('1').sub(flashLoanFee));
621
+ // Deposit the min ktoken amount we calculated at the beginning
622
+ // Any slippage will be left in the user's wallet as ktokens
623
+ collTokenToDeposit = actualColl;
624
+ debtTokenToBorrow = flashBorrowInDebtToken.div(new Decimal('1').sub(flashLoanFee));
625
+ // Add slippage to ensure we try to swap/deposit as much as possible after flash loan fees
626
+ const singleSidedDeposit = singleSidedDepositAmount.div(new Decimal('1').sub(slippage));
627
+
628
+ return {
629
+ flashBorrowInCollToken: new Decimal(0),
630
+ initDepositInSol,
631
+ collTokenToDeposit,
632
+ debtTokenToBorrow,
633
+ swapDebtTokenIn: new Decimal(0),
634
+ swapCollTokenExpectedOut: new Decimal(0),
635
+ flashBorrowInDebtTokenKtokenOnly: flashBorrowInDebtToken,
636
+ singleSidedDepositKtokenOnly: singleSidedDeposit,
637
+ requiredCollateralKtokenOnly: collTokenToDeposit, // Assuming collTokenToDeposit is requiredCollateral, adjust as needed
638
+ };
639
+ }
640
+ };
641
+
642
+ export function withdrawLeverageCalcs(
643
+ market: KaminoMarket,
644
+ collReserve: KaminoReserve,
645
+ debtReserve: KaminoReserve,
646
+ priceCollToDebt: Decimal,
647
+ withdrawAmount: Decimal,
648
+ deposited: Decimal,
649
+ borrowed: Decimal,
650
+ currentSlot: number,
651
+ isClosingPosition: boolean,
652
+ selectedTokenIsCollToken: boolean,
653
+ selectedTokenMint: PublicKey,
654
+ obligation: KaminoObligation,
655
+ flashLoanFee: Decimal,
656
+ slippagePct: Decimal
657
+ ): WithdrawLeverageCalcsResult {
658
+ // 1. Calculate coll_amount and debt_amount to repay such that we maintain leverage and we withdraw to
659
+ // the wallet `amountInDepositTokenToWithdrawToWallet` amount of collateral token
660
+ // We need to withdraw withdrawAmountInDepositToken coll tokens
661
+ // and repay repayAmountInBorrowToken debt tokens
662
+ const { adjustDepositPosition: withdrawAmountCalculated, adjustBorrowPosition: initialRepayAmount } =
663
+ isClosingPosition
664
+ ? { adjustDepositPosition: deposited, adjustBorrowPosition: borrowed }
665
+ : calcWithdrawAmounts({
666
+ collTokenMint: collReserve.getLiquidityMint(),
667
+ priceCollToDebt: new Decimal(priceCollToDebt),
668
+ currentDepositPosition: deposited,
669
+ currentBorrowPosition: borrowed,
670
+ withdrawAmount: new Decimal(withdrawAmount),
671
+ selectedTokenMint: selectedTokenMint,
672
+ });
673
+
674
+ // Add slippage for the accrued interest rate amount
675
+ const irSlippageBpsForDebt = obligation!
676
+ .estimateObligationInterestRate(market, debtReserve!, obligation?.state.borrows[0]!, currentSlot)
677
+ .toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
678
+ // add 0.1 to irSlippageBpsForDebt because we don't want to estimate slightly less than SC and end up not reapying enough
679
+ const repayAmount = initialRepayAmount
680
+ .mul(irSlippageBpsForDebt.add('0.1').div('10_000').add('1'))
681
+ .toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
682
+
683
+ // 6. Get swap ixns
684
+ // 5. Get swap estimations to understand how much we need to borrow from borrow reserve
685
+ // prevent withdrawing more then deposited if we close position
686
+ const depositTokenWithdrawAmount = !isClosingPosition
687
+ ? withdrawAmountCalculated.mul(new Decimal(1).plus(flashLoanFee))
688
+ : withdrawAmountCalculated;
689
+
690
+ // We are swapping debt token
691
+ // When withdrawing coll, it means we just need to swap enough to pay for the flash borrow
692
+ const swapAmountIfWithdrawingColl = repayAmount
693
+ .mul(new Decimal(1).plus(flashLoanFee))
694
+ .mul(new Decimal(1).plus(slippagePct.div(100)))
695
+ .div(priceCollToDebt);
696
+
697
+ // When withdrawing debt, it means we need to swap just the collateral we are withdrwaing
698
+ // enough to cover the debt we are repaying, leaving the remaining in the wallet
699
+ const swapAmountIfWithdrawingDebt = withdrawAmountCalculated;
700
+
701
+ const collTokenSwapIn = selectedTokenIsCollToken ? swapAmountIfWithdrawingColl : swapAmountIfWithdrawingDebt;
702
+ const debtTokenExpectedSwapOut = collTokenSwapIn.mul(priceCollToDebt).div(new Decimal(1).add(slippagePct.div(100)));
703
+
704
+ return {
705
+ withdrawAmount: withdrawAmountCalculated,
706
+ repayAmount,
707
+ collTokenSwapIn,
708
+ debtTokenExpectedSwapOut,
709
+ depositTokenWithdrawAmount,
710
+ };
711
+ }
712
+
713
+ export async function adjustDepositLeverageCalcs(
714
+ market: KaminoMarket,
715
+ owner: PublicKey,
716
+ debtReserve: KaminoReserve,
717
+ adjustDepositPosition: Decimal,
718
+ adjustBorrowPosition: Decimal,
719
+ priceDebtToColl: Decimal,
720
+ flashLoanFee: Decimal,
721
+ slippagePct: Decimal,
722
+ collIsKtoken: boolean
723
+ ): Promise<AdjustLeverageCalcsResult> {
724
+ // used if coll is Ktoken and we borrow debt token instead
725
+ const amountToFlashBorrowDebt = adjustDepositPosition
726
+ .div(priceDebtToColl)
727
+ .mul(new Decimal(new Decimal(1).add(slippagePct.div(100))))
728
+ .toDecimalPlaces(debtReserve!.stats.decimals, Decimal.ROUND_UP);
729
+
730
+ const borrowAmount = adjustDepositPosition
731
+ .mul(new Decimal(1).plus(flashLoanFee))
732
+ .mul(new Decimal(new Decimal(1).add(slippagePct.div(100))))
733
+ .div(priceDebtToColl);
734
+
735
+ const expectedDebtTokenAtaBalance = await getExpectedTokenBalanceAfterBorrow(
736
+ market.getConnection(),
737
+ debtReserve.getLiquidityMint(),
738
+ owner,
739
+ collToLamportsDecimal(!collIsKtoken ? borrowAmount : amountToFlashBorrowDebt, debtReserve!.stats.decimals).floor(),
740
+ debtReserve!.state.liquidity.mintDecimals.toNumber()
741
+ );
742
+
743
+ return {
744
+ adjustDepositPosition,
745
+ adjustBorrowPosition,
746
+ amountToFlashBorrowDebt,
747
+ borrowAmount,
748
+ expectedDebtTokenAtaBalance,
749
+ withdrawAmountWithSlippageAndFlashLoanFee: new Decimal(0),
750
+ };
751
+ }
752
+
753
+ export function adjustWithdrawLeverageCalcs(
754
+ adjustDepositPosition: Decimal,
755
+ adjustBorrowPosition: Decimal,
756
+ flashLoanFee: Decimal,
757
+ slippagePct: Decimal
758
+ ): AdjustLeverageCalcsResult {
759
+ // used if coll is Ktoken and we borrow debt token instead
760
+ const withdrawAmountWithSlippageAndFlashLoanFee = Decimal.abs(adjustDepositPosition)
761
+ .mul(new Decimal(1).plus(flashLoanFee))
762
+ .mul(new Decimal(1).add(slippagePct.div(100)));
763
+
764
+ return {
765
+ adjustDepositPosition,
766
+ adjustBorrowPosition,
767
+ amountToFlashBorrowDebt: new Decimal(0),
768
+ borrowAmount: new Decimal(0),
769
+ expectedDebtTokenAtaBalance: new Decimal(0),
770
+ withdrawAmountWithSlippageAndFlashLoanFee,
771
+ };
772
+ }
@@ -2,3 +2,4 @@ export * from './calcs';
2
2
  export * from './instructions';
3
3
  export * from './operations';
4
4
  export * from './utils';
5
+ export * from './types';