@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.
- package/dist/services/rebalance/rebalanceTxBuilder.d.ts +0 -1
- package/dist/services/rebalance/rebalanceTxBuilder.d.ts.map +1 -1
- package/dist/services/rebalance/rebalanceTxBuilder.js +2 -7
- package/dist/services/solauto/solautoClient.d.ts +0 -2
- package/dist/services/solauto/solautoClient.d.ts.map +1 -1
- package/dist/services/solauto/solautoClient.js +5 -8
- package/dist/services/solauto/solautoMarginfiClient.js +6 -6
- package/dist/services/transactions/transactionUtils.js +1 -1
- package/dist/solautoPosition/marginfiSolautoPositionEx.d.ts.map +1 -1
- package/dist/solautoPosition/marginfiSolautoPositionEx.js +1 -4
- package/dist/solautoPosition/positionUtils.d.ts +1 -1
- package/dist/solautoPosition/positionUtils.d.ts.map +1 -1
- package/dist/solautoPosition/positionUtils.js +17 -16
- package/dist/solautoPosition/solautoPositionEx.d.ts +17 -7
- package/dist/solautoPosition/solautoPositionEx.d.ts.map +1 -1
- package/dist/solautoPosition/solautoPositionEx.js +62 -49
- package/dist/utils/instructionUtils.js +1 -1
- package/dist/utils/marginfiUtils.d.ts.map +1 -1
- package/dist/utils/marginfiUtils.js +8 -5
- package/dist/utils/numberUtils.d.ts +2 -0
- package/dist/utils/numberUtils.d.ts.map +1 -1
- package/dist/utils/numberUtils.js +7 -0
- package/local/logPositions.ts +0 -2
- package/local/txSandbox.ts +3 -0
- package/package.json +1 -1
- package/src/services/rebalance/rebalanceTxBuilder.ts +7 -20
- package/src/services/solauto/solautoClient.ts +7 -17
- package/src/services/solauto/solautoMarginfiClient.ts +6 -6
- package/src/services/transactions/transactionUtils.ts +1 -1
- package/src/solautoPosition/marginfiSolautoPositionEx.ts +1 -5
- package/src/solautoPosition/positionUtils.ts +31 -26
- package/src/solautoPosition/solautoPositionEx.ts +124 -72
- package/src/utils/instructionUtils.ts +1 -1
- package/src/utils/marginfiUtils.ts +20 -13
- 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
|
-
|
219
|
-
this.
|
220
|
-
rebalanceValues.
|
221
|
-
|
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
|
-
|
83
|
-
|
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
|
-
|
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
|
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,
|
@@ -97,11 +97,7 @@ export class MarginfiSolautoPositionEx extends SolautoPositionEx {
|
|
97
97
|
}
|
98
98
|
|
99
99
|
async refreshPositionState(priceType?: PriceType): Promise<void> {
|
100
|
-
|
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 {
|
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
|
-
|
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
|
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
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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.
|
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
|
+
}
|
@@ -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(
|
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
|
471
|
+
marginfiGroup: PublicKey
|
470
472
|
) {
|
471
|
-
|
472
|
-
|
473
|
-
|
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
|
479
|
-
][
|
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(
|
627
|
+
const supplyPrice = safeGetPrice(toWeb3JsPublicKey(supplyBank.mint))!;
|
621
628
|
let [maxLtvBps, liqThresholdBps] = await getMarginfiMaxLtvAndLiqThresholdBps(
|
622
629
|
umi,
|
623
630
|
marginfiGroup ?? getMarginfiAccounts(programEnv).defaultGroup,
|
package/src/utils/numberUtils.ts
CHANGED
@@ -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
|
+
}
|