@haven-fi/solauto-sdk 1.0.660 → 1.0.662

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 (35) hide show
  1. package/dist/services/rebalance/rebalanceTxBuilder.d.ts +0 -1
  2. package/dist/services/rebalance/rebalanceTxBuilder.d.ts.map +1 -1
  3. package/dist/services/rebalance/rebalanceTxBuilder.js +2 -7
  4. package/dist/services/solauto/solautoClient.d.ts +0 -2
  5. package/dist/services/solauto/solautoClient.d.ts.map +1 -1
  6. package/dist/services/solauto/solautoClient.js +5 -8
  7. package/dist/services/solauto/solautoMarginfiClient.js +6 -6
  8. package/dist/services/transactions/transactionUtils.js +1 -1
  9. package/dist/solautoPosition/marginfiSolautoPositionEx.d.ts.map +1 -1
  10. package/dist/solautoPosition/marginfiSolautoPositionEx.js +1 -4
  11. package/dist/solautoPosition/positionUtils.d.ts +1 -1
  12. package/dist/solautoPosition/positionUtils.d.ts.map +1 -1
  13. package/dist/solautoPosition/positionUtils.js +17 -16
  14. package/dist/solautoPosition/solautoPositionEx.d.ts +17 -7
  15. package/dist/solautoPosition/solautoPositionEx.d.ts.map +1 -1
  16. package/dist/solautoPosition/solautoPositionEx.js +62 -49
  17. package/dist/utils/instructionUtils.js +1 -1
  18. package/dist/utils/marginfiUtils.d.ts.map +1 -1
  19. package/dist/utils/marginfiUtils.js +8 -5
  20. package/dist/utils/numberUtils.d.ts +2 -0
  21. package/dist/utils/numberUtils.d.ts.map +1 -1
  22. package/dist/utils/numberUtils.js +7 -0
  23. package/local/logPositions.ts +0 -2
  24. package/local/txSandbox.ts +3 -0
  25. package/package.json +1 -1
  26. package/src/services/rebalance/rebalanceTxBuilder.ts +7 -20
  27. package/src/services/solauto/solautoClient.ts +7 -17
  28. package/src/services/solauto/solautoMarginfiClient.ts +6 -6
  29. package/src/services/transactions/transactionUtils.ts +1 -1
  30. package/src/solautoPosition/marginfiSolautoPositionEx.ts +1 -5
  31. package/src/solautoPosition/positionUtils.ts +31 -26
  32. package/src/solautoPosition/solautoPositionEx.ts +124 -72
  33. package/src/utils/instructionUtils.ts +1 -1
  34. package/src/utils/marginfiUtils.ts +20 -13
  35. package/src/utils/numberUtils.ts +13 -1
@@ -15,6 +15,7 @@ import {
15
15
  getTokenAccount,
16
16
  hasFirstRebalance,
17
17
  hasLastRebalance,
18
+ realtimeUsdToEmaUsd,
18
19
  safeGetPrice,
19
20
  tokenInfo,
20
21
  } from "../../utils";
@@ -202,31 +203,17 @@ export class RebalanceTxBuilder {
202
203
  }
203
204
  }
204
205
 
205
- private realtimeUsdToEmaUsd(realtimeAmountUsd: number, mint: PublicKey) {
206
- return (
207
- (realtimeAmountUsd / safeGetPrice(mint, PriceType.Realtime)!) *
208
- safeGetPrice(mint, PriceType.Ema)!
209
- );
210
- }
211
-
212
206
  private getInitialRebalanceValues() {
213
207
  let rebalanceValues = this.getRebalanceValues();
214
208
  if (!rebalanceValues) {
215
209
  return undefined;
216
210
  }
217
211
 
218
- const postRebalanceEmaUtilRateBps = getLiqUtilzationRateBps(
219
- this.realtimeUsdToEmaUsd(
220
- rebalanceValues.endResult.supplyUsd,
221
- this.client.pos.supplyMint
222
- ),
223
- this.realtimeUsdToEmaUsd(
224
- rebalanceValues.endResult.debtUsd,
225
- this.client.pos.debtMint
226
- ),
227
- this.client.pos.state.liqThresholdBps
228
- );
229
- if (postRebalanceEmaUtilRateBps > this.client.pos.maxBoostToBps) {
212
+ if (
213
+ !this.client.pos.rebalanceHelper.validRealtimePricesBoost(
214
+ rebalanceValues.debtAdjustmentUsd
215
+ )
216
+ ) {
230
217
  this.priceType = PriceType.Ema;
231
218
  rebalanceValues = this.getRebalanceValues();
232
219
  if (!rebalanceValues) {
@@ -263,7 +250,7 @@ export class RebalanceTxBuilder {
263
250
 
264
251
  private async refreshBeforeRebalance() {
265
252
  if (
266
- this.client.selfManaged ||
253
+ this.client.pos.selfManaged ||
267
254
  this.client.contextUpdates.supplyAdjustment > BigInt(0) ||
268
255
  this.client.contextUpdates.debtAdjustment > BigInt(0) ||
269
256
  !this.client.pos.exists
@@ -55,8 +55,6 @@ export abstract class SolautoClient extends ReferralStateManager {
55
55
 
56
56
  public authority!: PublicKey;
57
57
 
58
- public positionId!: number;
59
- public selfManaged!: boolean;
60
58
  public pos!: SolautoPositionEx;
61
59
 
62
60
  public positionSupplyTa!: PublicKey;
@@ -79,23 +77,15 @@ export abstract class SolautoClient extends ReferralStateManager {
79
77
  async initialize(args: SolautoClientArgs) {
80
78
  await super.initialize(args);
81
79
 
82
- this.positionId = args.positionId ?? 0;
83
- this.selfManaged = this.positionId === 0;
84
- if (
85
- this.selfManaged &&
86
- (!args.supplyMint || !args.debtMint || !args.lpUserAccount)
87
- ) {
80
+ const positionId = args.positionId ?? 0;
81
+ if (positionId === 0 && !args.lpUserAccount) {
88
82
  throw new Error("Self managed position is missing arguments");
89
83
  }
90
-
91
- const positionPk = getSolautoPositionAccount(
92
- this.authority,
93
- this.positionId,
94
- this.programId
95
- );
96
84
  this.pos = await getOrCreatePositionEx(
97
85
  this.umi,
98
- positionPk,
86
+ this.authority,
87
+ positionId,
88
+ this.programId,
99
89
  {
100
90
  supplyMint: args.supplyMint,
101
91
  debtMint: args.debtMint,
@@ -106,7 +96,7 @@ export abstract class SolautoClient extends ReferralStateManager {
106
96
  },
107
97
  this.contextUpdates
108
98
  );
109
- if (this.pos.selfManaged && (!args.supplyMint || !args.debtMint)) {
99
+ if (this.pos.selfManaged) {
110
100
  await this.pos.refreshPositionState();
111
101
  }
112
102
 
@@ -441,7 +431,7 @@ export abstract class SolautoClient extends ReferralStateManager {
441
431
  protocolInteractionIx(args: SolautoActionArgs): TransactionBuilder {
442
432
  let tx = transactionBuilder();
443
433
 
444
- if (!this.selfManaged) {
434
+ if (!this.pos.selfManaged) {
445
435
  if (args.__kind === "Deposit") {
446
436
  tx = tx.add(
447
437
  splTokenTransferUmiIx(
@@ -65,7 +65,7 @@ export class SolautoMarginfiClient extends SolautoClient {
65
65
 
66
66
  this.marginfiGroup = await this.pos.lendingPool();
67
67
 
68
- if (this.selfManaged) {
68
+ if (this.pos.selfManaged) {
69
69
  this.marginfiAccount =
70
70
  args.lpUserAccount ??
71
71
  createSignerFromKeypair(this.umi, this.umi.eddsa.generateKeypair());
@@ -187,7 +187,7 @@ export class SolautoMarginfiClient extends SolautoClient {
187
187
  signerDebtTa: signerDebtTa,
188
188
  positionType: positionType ?? PositionType.Leverage,
189
189
  positionData: {
190
- positionId: this.positionId!,
190
+ positionId: this.pos.positionId,
191
191
  settings: settings ?? null,
192
192
  dca: dca ?? null,
193
193
  },
@@ -224,7 +224,7 @@ export class SolautoMarginfiClient extends SolautoClient {
224
224
  protocolInteractionIx(args: SolautoActionArgs): TransactionBuilder {
225
225
  let tx = super.protocolInteractionIx(args);
226
226
 
227
- if (this.selfManaged) {
227
+ if (this.pos.selfManaged) {
228
228
  return tx.add(this.marginfiProtocolInteractionIx(args));
229
229
  } else {
230
230
  return tx.add(this.marginfiSolautoProtocolInteractionIx(args));
@@ -306,7 +306,7 @@ export class SolautoMarginfiClient extends SolautoClient {
306
306
  let supplyVaultAuthority: UmiPublicKey | undefined = undefined;
307
307
  if (args.__kind === "Deposit" || args.__kind === "Withdraw") {
308
308
  positionSupplyTa = publicKey(
309
- args.__kind === "Withdraw" || this.selfManaged
309
+ args.__kind === "Withdraw" || this.pos.selfManaged
310
310
  ? this.signerSupplyTa
311
311
  : this.positionSupplyTa
312
312
  );
@@ -321,7 +321,7 @@ export class SolautoMarginfiClient extends SolautoClient {
321
321
  let debtVaultAuthority: UmiPublicKey | undefined = undefined;
322
322
  if (args.__kind === "Borrow" || args.__kind === "Repay") {
323
323
  positionDebtTa = publicKey(
324
- args.__kind === "Borrow" || this.selfManaged
324
+ args.__kind === "Borrow" || this.pos.selfManaged
325
325
  ? this.signerDebtTa
326
326
  : this.positionDebtTa
327
327
  );
@@ -369,7 +369,7 @@ export class SolautoMarginfiClient extends SolautoClient {
369
369
  data.rebalanceType === SolautoRebalanceType.FLSwapThenRebalance);
370
370
 
371
371
  const addAuthorityTas =
372
- this.selfManaged || data.values.tokenBalanceChange !== undefined;
372
+ this.pos.selfManaged || data.values.tokenBalanceChange !== undefined;
373
373
 
374
374
  return marginfiRebalance(this.umi, {
375
375
  signer: this.signer,
@@ -136,7 +136,7 @@ async function transactionChoresBefore(
136
136
  );
137
137
  }
138
138
 
139
- if (client.selfManaged) {
139
+ if (client.pos.selfManaged) {
140
140
  if (
141
141
  isMarginfiClient(client) &&
142
142
  !(await getSolanaAccountCreated(client.umi, client.marginfiAccountPk))
@@ -97,11 +97,7 @@ export class MarginfiSolautoPositionEx extends SolautoPositionEx {
97
97
  }
98
98
 
99
99
  async refreshPositionState(priceType?: PriceType): Promise<void> {
100
- if (!this.canRefreshPositionState()) {
101
- return;
102
- }
103
-
104
- const useDesignatedMint = !this._data.position || !this._data.selfManaged;
100
+ const useDesignatedMint = !this._data.position || !this.selfManaged;
105
101
  const resp = await getMarginfiAccountPositionState(
106
102
  this.umi,
107
103
  { pk: this.lpUserAccount },
@@ -17,12 +17,17 @@ import {
17
17
  currentUnixSeconds,
18
18
  getBatches,
19
19
  getLiqUtilzationRateBps,
20
+ getSolautoPositionAccount,
20
21
  retryWithExponentialBackoff,
21
22
  toBaseUnit,
22
23
  tokenInfo,
23
24
  toRoundedUsdValue,
24
25
  } from "../utils";
25
- import { PositionCustomArgs, SolautoPositionEx } from "./solautoPositionEx";
26
+ import {
27
+ PositionCustomArgs,
28
+ PositionExArgs,
29
+ SolautoPositionEx,
30
+ } from "./solautoPositionEx";
26
31
  import { MarginfiSolautoPositionEx } from "./marginfiSolautoPositionEx";
27
32
  import { assert } from "console";
28
33
 
@@ -73,45 +78,45 @@ export async function getPositionExBulk(
73
78
 
74
79
  export async function getOrCreatePositionEx(
75
80
  umi: Umi,
76
- publicKey: PublicKey,
81
+ authority: PublicKey,
82
+ positionId: number,
83
+ programId: PublicKey,
77
84
  customArgs?: PositionCustomArgs,
78
85
  contextUpdates?: ContextUpdates
79
86
  ): Promise<SolautoPositionEx> {
87
+ const publicKey = getSolautoPositionAccount(authority, positionId, programId);
80
88
  const data = await safeFetchSolautoPosition(
81
89
  umi,
82
90
  fromWeb3JsPublicKey(publicKey)
83
91
  );
84
92
 
85
- if (!data && (!customArgs?.supplyMint || !customArgs.debtMint)) {
86
- throw new Error(
87
- "Must provide a supply & debt mint if creating a new position"
88
- );
89
- }
90
-
91
- const placeholderState = createFakePositionState(
92
- {
93
- mint: customArgs?.supplyMint ?? PublicKey.default,
94
- },
95
- { mint: customArgs?.debtMint ?? PublicKey.default },
96
- 0,
97
- 0
98
- );
99
-
100
93
  const lendingPlatform = data
101
94
  ? data.position.lendingPlatform
102
95
  : customArgs!.lendingPlatform;
103
96
 
97
+ const args: PositionExArgs = {
98
+ umi,
99
+ publicKey,
100
+ authority,
101
+ positionId,
102
+ programId,
103
+ data: data ?? {
104
+ state: createFakePositionState(
105
+ {
106
+ mint: customArgs?.supplyMint ?? PublicKey.default,
107
+ },
108
+ { mint: customArgs?.debtMint ?? PublicKey.default },
109
+ 0,
110
+ 0
111
+ ),
112
+ },
113
+ customArgs,
114
+ contextUpdates,
115
+ };
116
+
104
117
  switch (lendingPlatform) {
105
118
  case LendingPlatform.Marginfi:
106
- return new MarginfiSolautoPositionEx({
107
- umi,
108
- publicKey,
109
- data: data ?? {
110
- state: placeholderState!,
111
- },
112
- customArgs,
113
- contextUpdates,
114
- });
119
+ return new MarginfiSolautoPositionEx(args);
115
120
  // TODO: PF
116
121
  }
117
122
  }
@@ -25,10 +25,12 @@ import {
25
25
  debtLiquidityAvailable,
26
26
  debtLiquidityUsdAvailable,
27
27
  getLiqUtilzationRateBps,
28
+ getSolautoPositionAccount,
28
29
  maxBoostToBps,
29
30
  maxRepayFromBps,
30
31
  maxRepayToBps,
31
32
  positionStateWithLatestPrices,
33
+ realtimeUsdToEmaUsd,
32
34
  safeGetPrice,
33
35
  solautoStrategyName,
34
36
  supplyLiquidityDepositable,
@@ -58,9 +60,12 @@ interface SolautoPositionExData extends Partial<SolautoPosition> {
58
60
  state: PositionState;
59
61
  }
60
62
 
61
- interface PositionExArgs {
63
+ export interface PositionExArgs {
62
64
  umi: Umi;
63
- publicKey: PublicKey;
65
+ publicKey?: PublicKey;
66
+ programId?: PublicKey;
67
+ authority?: PublicKey;
68
+ positionId?: number;
64
69
  data: SolautoPositionExData;
65
70
  customArgs?: PositionCustomArgs;
66
71
  contextUpdates?: ContextUpdates;
@@ -72,20 +77,33 @@ export abstract class SolautoPositionEx {
72
77
 
73
78
  public publicKey!: PublicKey;
74
79
  public lendingPlatform!: LendingPlatform;
80
+ public positionId!: number;
81
+ public authority!: PublicKey;
75
82
  protected _data!: SolautoPositionExData;
76
83
  protected lp?: PublicKey = undefined;
77
- protected lpEnv!: ProgramEnv;
78
84
  public lpUserAccount?: PublicKey = undefined;
85
+ protected lpEnv!: ProgramEnv;
79
86
 
80
87
  private readonly firstState!: PositionState;
81
88
  protected _supplyPrice?: number;
82
89
  protected _debtPrice?: number;
83
90
 
91
+ public rebalanceHelper!: PositionRebalanceHelper;
92
+
84
93
  constructor(args: PositionExArgs) {
85
94
  this.umi = args.umi;
86
- this.publicKey = args.publicKey;
87
95
  this.contextUpdates = args.contextUpdates;
88
96
 
97
+ this.publicKey =
98
+ args.publicKey ??
99
+ getSolautoPositionAccount(
100
+ args.authority!,
101
+ args.positionId!,
102
+ args.programId!
103
+ );
104
+ this.positionId = args.positionId ?? args.data.positionId![0];
105
+ this.authority = args.authority ?? toWeb3JsPublicKey(args.data.authority!);
106
+
89
107
  this.lp = args.customArgs?.lendingPool;
90
108
  this.lpUserAccount =
91
109
  args.customArgs?.lpUserAccount ??
@@ -96,6 +114,8 @@ export abstract class SolautoPositionEx {
96
114
 
97
115
  this._data = args.data;
98
116
  this.firstState = { ...args.data.state };
117
+
118
+ this.rebalanceHelper = new PositionRebalanceHelper(this);
99
119
  }
100
120
 
101
121
  abstract lendingPool(): Promise<PublicKey>;
@@ -104,16 +124,6 @@ export abstract class SolautoPositionEx {
104
124
  return this._data.position !== undefined;
105
125
  }
106
126
 
107
- get authority() {
108
- return this._data.authority
109
- ? toWeb3JsPublicKey(this._data.authority)
110
- : PublicKey.default;
111
- }
112
-
113
- get positionId() {
114
- return this._data.positionId ? this._data.positionId[0] : undefined;
115
- }
116
-
117
127
  get selfManaged() {
118
128
  return this.positionId === 0;
119
129
  }
@@ -272,74 +282,22 @@ export abstract class SolautoPositionEx {
272
282
  return tokenInfo(this.supplyMint).isMeme || tokenInfo(this.debtMint).isMeme;
273
283
  }
274
284
 
275
- private sufficientLiquidityToBoost() {
276
- const limitsUpToDate =
277
- this.debtLiquidityUsdAvailable !== 0 ||
278
- this.supplyLiquidityUsdDepositable !== 0;
279
-
280
- if (limitsUpToDate) {
281
- const { debtAdjustmentUsd } = getDebtAdjustment(
282
- this.state.liqThresholdBps,
283
- { supplyUsd: this.supplyUsd(), debtUsd: this.debtUsd() },
284
- this.boostToBps,
285
- { solauto: 50, lpBorrow: 50, flashLoan: 50 } // TODO: get true data here instead of magic numbers
286
- );
287
-
288
- const sufficientLiquidity =
289
- this.debtLiquidityUsdAvailable * 0.95 > debtAdjustmentUsd &&
290
- this.supplyLiquidityUsdDepositable * 0.95 > debtAdjustmentUsd;
291
-
292
- if (!sufficientLiquidity) {
293
- consoleLog("Insufficient liquidity to further boost");
294
- }
295
- return sufficientLiquidity;
296
- }
297
-
298
- return true;
299
- }
300
-
301
- eligibleForRebalance(bpsDistanceThreshold = 0): RebalanceAction | undefined {
302
- if (!this.settings || !this.supplyUsd()) {
303
- return undefined;
304
- }
305
-
306
- const realtimeLiqUtilRateBps = this.liqUtilizationRateBps(
307
- PriceType.Realtime
285
+ eligibleForRebalance(
286
+ bpsDistanceThreshold: number = 0
287
+ ): RebalanceAction | undefined {
288
+ return this.rebalanceHelper.eligibleForRebalance(
289
+ bpsDistanceThreshold
308
290
  );
309
- const emaLiqUtilRateBps = this.liqUtilizationRateBps(PriceType.Ema);
310
-
311
- if (this.repayFromBps - realtimeLiqUtilRateBps <= bpsDistanceThreshold) {
312
- return "repay";
313
- } else if (
314
- realtimeLiqUtilRateBps - this.boostFromBps <= bpsDistanceThreshold ||
315
- emaLiqUtilRateBps - this.boostFromBps <= bpsDistanceThreshold
316
- ) {
317
- const sufficientLiquidity = this.sufficientLiquidityToBoost();
318
- return sufficientLiquidity ? "boost" : undefined;
319
- }
320
-
321
- return undefined;
322
291
  }
323
292
 
324
293
  eligibleForRefresh(): boolean {
325
- if (this._data.selfManaged) return false;
294
+ if (this.selfManaged) return false;
326
295
 
327
296
  return (
328
297
  currentUnixSeconds() - Number(this.state.lastRefreshed) > 60 * 60 * 24 * 7
329
298
  );
330
299
  }
331
300
 
332
- protected canRefreshPositionState() {
333
- if (
334
- Number(this.state.lastRefreshed) >
335
- currentUnixSeconds() - MIN_POSITION_STATE_FRESHNESS_SECS &&
336
- !this.contextUpdates?.positionUpdates()
337
- ) {
338
- return false;
339
- }
340
- return true;
341
- }
342
-
343
301
  abstract refreshPositionState(priceType?: PriceType): Promise<void>;
344
302
 
345
303
  async utilizationRateBpsDrift(priceType?: PriceType) {
@@ -444,3 +402,97 @@ export abstract class SolautoPositionEx {
444
402
  );
445
403
  }
446
404
  }
405
+
406
+ class PositionRebalanceHelper {
407
+ constructor(private pos: SolautoPositionEx) {}
408
+
409
+ private sufficientLiquidityToBoost() {
410
+ const limitsUpToDate =
411
+ this.pos.debtLiquidityUsdAvailable !== 0 ||
412
+ this.pos.supplyLiquidityUsdDepositable !== 0;
413
+
414
+ if (limitsUpToDate) {
415
+ const { debtAdjustmentUsd } = getDebtAdjustment(
416
+ this.pos.state.liqThresholdBps,
417
+ { supplyUsd: this.pos.supplyUsd(), debtUsd: this.pos.debtUsd() },
418
+ this.pos.boostToBps,
419
+ { solauto: 50, lpBorrow: 50, flashLoan: 50 } // Overshoot fees
420
+ );
421
+
422
+ const sufficientLiquidity =
423
+ this.pos.debtLiquidityUsdAvailable * 0.95 > debtAdjustmentUsd &&
424
+ this.pos.supplyLiquidityUsdDepositable * 0.95 > debtAdjustmentUsd;
425
+
426
+ if (!sufficientLiquidity) {
427
+ consoleLog("Insufficient liquidity to further boost");
428
+ }
429
+ return sufficientLiquidity;
430
+ }
431
+
432
+ return true;
433
+ }
434
+
435
+ validRealtimePricesBoost(debtAdjustmentUsd: number) {
436
+ if (this.pos.lendingPlatform !== LendingPlatform.Marginfi) {
437
+ // TODO: LP
438
+ return true;
439
+ }
440
+
441
+ const postRebalanceLiqUtilRate = getLiqUtilzationRateBps(
442
+ realtimeUsdToEmaUsd(
443
+ this.pos.supplyUsd() + debtAdjustmentUsd,
444
+ this.pos.supplyMint
445
+ ),
446
+ realtimeUsdToEmaUsd(
447
+ this.pos.debtUsd() + debtAdjustmentUsd,
448
+ this.pos.debtMint
449
+ ),
450
+ this.pos.state.liqThresholdBps
451
+ );
452
+
453
+ return postRebalanceLiqUtilRate <= this.pos.maxBoostToBps;
454
+ }
455
+
456
+ private validBoostFromHere() {
457
+ const { debtAdjustmentUsd } = getDebtAdjustment(
458
+ this.pos.state.liqThresholdBps,
459
+ {
460
+ supplyUsd: this.pos.supplyUsd(PriceType.Realtime),
461
+ debtUsd: this.pos.debtUsd(PriceType.Realtime),
462
+ },
463
+ this.pos.boostToBps,
464
+ { solauto: 25, lpBorrow: 0, flashLoan: 0 } // Undershoot fees
465
+ );
466
+
467
+ return this.validRealtimePricesBoost(debtAdjustmentUsd);
468
+ }
469
+
470
+ eligibleForRebalance(
471
+ bpsDistanceThreshold: number
472
+ ): RebalanceAction | undefined {
473
+ if (!this.pos.settings || !this.pos.supplyUsd()) {
474
+ return undefined;
475
+ }
476
+
477
+ const realtimeLiqUtilRateBps = this.pos.liqUtilizationRateBps(
478
+ PriceType.Realtime
479
+ );
480
+ const emaLiqUtilRateBps = this.pos.liqUtilizationRateBps(PriceType.Ema);
481
+
482
+ if (
483
+ this.pos.repayFromBps - realtimeLiqUtilRateBps <=
484
+ bpsDistanceThreshold
485
+ ) {
486
+ return "repay";
487
+ } else if (
488
+ (realtimeLiqUtilRateBps - this.pos.boostFromBps <= bpsDistanceThreshold ||
489
+ emaLiqUtilRateBps - this.pos.boostFromBps <= bpsDistanceThreshold) &&
490
+ this.validBoostFromHere()
491
+ ) {
492
+ const sufficientLiquidity = this.sufficientLiquidityToBoost();
493
+ return sufficientLiquidity ? "boost" : undefined;
494
+ }
495
+
496
+ return undefined;
497
+ }
498
+ }
@@ -44,7 +44,7 @@ export function updateSolautoPosition(
44
44
  return new TransactionItem(
45
45
  async () => ({
46
46
  tx: client.updatePositionIx({
47
- positionId: client.positionId,
47
+ positionId: client.pos.positionId,
48
48
  settings,
49
49
  dca,
50
50
  }),
@@ -93,7 +93,6 @@ export async function getAllBankRelatedAccounts(
93
93
  getPythPushOracleAddress(oracleKey, MARGINFI_SPONSORED_SHARD_ID),
94
94
  ]
95
95
  : [oracleKey];
96
-
97
96
  })
98
97
  .flat()
99
98
  .map((x) => x.toString());
@@ -416,7 +415,10 @@ async function getTokenUsage(
416
415
  let originationFee = 0;
417
416
 
418
417
  if (bank !== null) {
419
- [marketPrice] = await fetchTokenPrices([toWeb3JsPublicKey(bank.mint)], priceType);
418
+ [marketPrice] = await fetchTokenPrices(
419
+ [toWeb3JsPublicKey(bank.mint)],
420
+ priceType
421
+ );
420
422
  const [assetShareValue, liabilityShareValue] = getUpToDateShareValues(bank);
421
423
  const shareValue = isAsset ? assetShareValue : liabilityShareValue;
422
424
  amountUsed = shares * shareValue + Number(amountUsedAdjustment ?? 0);
@@ -466,17 +468,22 @@ type BanksCache = { [group: string]: { [mint: string]: Bank } };
466
468
  async function getBank(
467
469
  umi: Umi,
468
470
  data: BankSelection,
469
- marginfiGroup?: PublicKey
471
+ marginfiGroup: PublicKey
470
472
  ) {
471
- return data?.banksCache && data.mint && marginfiGroup
472
- ? data.banksCache[marginfiGroup!.toString()][data?.mint?.toString()]
473
- : data?.mint && data?.mint !== PublicKey.default
473
+ const mint =
474
+ data?.mint && !data.mint.equals(PublicKey.default)
475
+ ? data.mint.toString()
476
+ : undefined;
477
+
478
+ return data?.banksCache && mint
479
+ ? data.banksCache[marginfiGroup.toString()][mint]
480
+ : mint && mint !== PublicKey.default.toString()
474
481
  ? await safeFetchBank(
475
482
  umi,
476
483
  publicKey(
477
484
  getMarginfiAccounts(undefined, marginfiGroup).bankAccounts[
478
- marginfiGroup?.toString() ?? ""
479
- ][data?.mint.toString()].bank
485
+ marginfiGroup.toString()
486
+ ][mint].bank
480
487
  ),
481
488
  { commitment: "confirmed" }
482
489
  )
@@ -515,8 +522,8 @@ export async function getMarginfiAccountPositionState(
515
522
  marginfiGroup = toWeb3JsPublicKey(marginfiAccount.group);
516
523
  }
517
524
 
518
- let supplyBank: Bank | null = await getBank(umi, supply, marginfiGroup);
519
- let debtBank: Bank | null = await getBank(umi, debt, marginfiGroup);
525
+ let supplyBank: Bank | null = await getBank(umi, supply, marginfiGroup!);
526
+ let debtBank: Bank | null = await getBank(umi, debt, marginfiGroup!);
520
527
 
521
528
  let supplyUsage: PositionTokenState | undefined = undefined;
522
529
  let debtUsage: PositionTokenState | undefined = undefined;
@@ -585,7 +592,7 @@ export async function getMarginfiAccountPositionState(
585
592
  supplyBank,
586
593
  true,
587
594
  0,
588
- contextUpdates?.supplyAdjustment,
595
+ contextUpdates?.supplyAdjustment
589
596
  );
590
597
  }
591
598
 
@@ -613,11 +620,11 @@ export async function getMarginfiAccountPositionState(
613
620
  debtBank,
614
621
  false,
615
622
  0,
616
- contextUpdates?.debtAdjustment,
623
+ contextUpdates?.debtAdjustment
617
624
  );
618
625
  }
619
626
 
620
- const supplyPrice = safeGetPrice(supply.mint!)!;
627
+ const supplyPrice = safeGetPrice(toWeb3JsPublicKey(supplyBank.mint))!;
621
628
  let [maxLtvBps, liqThresholdBps] = await getMarginfiMaxLtvAndLiqThresholdBps(
622
629
  umi,
623
630
  marginfiGroup ?? getMarginfiAccounts(programEnv).defaultGroup,
@@ -1,11 +1,13 @@
1
+ import { PublicKey } from "@solana/web3.js";
1
2
  import {
2
3
  BASIS_POINTS,
3
4
  MIN_REPAY_GAP_BPS,
4
5
  OFFSET_FROM_MAX_LTV,
5
6
  USD_DECIMALS,
6
7
  } from "../constants";
7
- import { PositionState } from "../generated";
8
+ import { PositionState, PriceType } from "../generated";
8
9
  import { RoundAction } from "../types";
10
+ import { safeGetPrice } from "./priceUtils";
9
11
 
10
12
  export function calcNetWorthUsd(state?: PositionState) {
11
13
  return fromRoundedUsdValue(state?.netWorth.baseAmountUsdValue ?? BigInt(0));
@@ -203,3 +205,13 @@ export function maxBoostToBps(maxLtvBps: number, liqThresholdBps: number) {
203
205
  getMaxLiqUtilizationRateBps(maxLtvBps, liqThresholdBps, OFFSET_FROM_MAX_LTV)
204
206
  );
205
207
  }
208
+
209
+ export function realtimeUsdToEmaUsd(
210
+ realtimeAmountUsd: number,
211
+ mint: PublicKey
212
+ ) {
213
+ return (
214
+ (realtimeAmountUsd / safeGetPrice(mint, PriceType.Realtime)!) *
215
+ safeGetPrice(mint, PriceType.Ema)!
216
+ );
217
+ }