@haven-fi/solauto-sdk 1.0.127 → 1.0.129
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/clients/solautoMarginfiClient.js +2 -3
- package/dist/transactions/transactionUtils.d.ts.map +1 -1
- package/dist/transactions/transactionUtils.js +1 -2
- package/dist/transactions/transactionsManager.js +2 -2
- package/dist/utils/generalUtils.d.ts +3 -2
- package/dist/utils/generalUtils.d.ts.map +1 -1
- package/dist/utils/generalUtils.js +9 -2
- package/dist/utils/marginfiUtils.js +3 -4
- package/dist/utils/numberUtils.js +2 -2
- package/dist/utils/solauto/generalUtils.js +1 -1
- package/dist/utils/solauto/rebalanceUtils.js +5 -5
- package/package.json +1 -1
- package/src/clients/solautoMarginfiClient.ts +3 -3
- package/src/transactions/transactionUtils.ts +3 -2
- package/src/transactions/transactionsManager.ts +5 -5
- package/src/utils/generalUtils.ts +9 -2
- package/src/utils/marginfiUtils.ts +4 -4
- package/src/utils/numberUtils.ts +2 -2
- package/src/utils/solauto/generalUtils.ts +2 -2
- package/src/utils/solauto/rebalanceUtils.ts +6 -6
- package/tests/transactions/solautoMarginfi.ts +33 -43
- package/tests/unit/rebalanceCalculations.ts +6 -5
@@ -12,7 +12,6 @@ const generalUtils_1 = require("../utils/generalUtils");
|
|
12
12
|
const marginfi_sdk_1 = require("../marginfi-sdk");
|
13
13
|
const marginfiUtils_1 = require("../utils/marginfiUtils");
|
14
14
|
const numberUtils_1 = require("../utils/numberUtils");
|
15
|
-
const constants_1 = require("../constants");
|
16
15
|
const utils_1 = require("../utils");
|
17
16
|
class SolautoMarginfiClient extends solautoClient_1.SolautoClient {
|
18
17
|
constructor() {
|
@@ -418,8 +417,8 @@ class SolautoMarginfiClient extends solautoClient_1.SolautoClient {
|
|
418
417
|
const freshState = await (0, marginfiUtils_1.getMarginfiAccountPositionState)(this.umi, this.marginfiAccountPk, this.supplyMint, this.debtMint, this.livePositionUpdates);
|
419
418
|
if (freshState) {
|
420
419
|
this.log("Fresh state", freshState);
|
421
|
-
const supplyPrice =
|
422
|
-
const debtPrice =
|
420
|
+
const supplyPrice = (0, generalUtils_1.safeGetPrice)(freshState?.supply.mint);
|
421
|
+
const debtPrice = (0, generalUtils_1.safeGetPrice)(freshState?.debt.mint);
|
423
422
|
this.log("Supply price: ", supplyPrice);
|
424
423
|
this.log("Debt price: ", debtPrice);
|
425
424
|
this.log("Liq threshold bps:", freshState.liqThresholdBps);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"transactionUtils.d.ts","sourceRoot":"","sources":["../../src/transactions/transactionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAClB,GAAG,EAGJ,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,SAAS,EAA8B,MAAM,iBAAiB,CAAC;AAKxE,OAAO,EAEL,aAAa,EASd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
1
|
+
{"version":3,"file":"transactionUtils.d.ts","sourceRoot":"","sources":["../../src/transactions/transactionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAClB,GAAG,EAGJ,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,SAAS,EAA8B,MAAM,iBAAiB,CAAC;AAKxE,OAAO,EAEL,aAAa,EASd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA8MzD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,EAAE,EAAE,kBAAkB,EACtB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA+G7B;AAmLD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,EAAE,EAAE,kBAAkB,GACrB,OAAO,CAAC,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC,CA4BnD;AAED,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,aAAa,EACrB,2BAA2B,CAAC,EAAE,MAAM,EACpC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CACN;IACE,EAAE,EAAE,kBAAkB,CAAC;IACvB,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC,GACD,SAAS,CACZ,CA4HA;AAED,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,SAAS,GACtB,OAAO,CAAC,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,CAmCrD"}
|
@@ -17,7 +17,6 @@ const numberUtils_1 = require("../utils/numberUtils");
|
|
17
17
|
const generalUtils_2 = require("../utils/solauto/generalUtils");
|
18
18
|
const accountUtils_1 = require("../utils/accountUtils");
|
19
19
|
const marginfi_sdk_1 = require("../marginfi-sdk");
|
20
|
-
const constants_1 = require("../constants");
|
21
20
|
function getWSolUsage(client, solautoActions, initiatingDcaIn, cancellingDcaIn) {
|
22
21
|
const supplyIsWsol = client.supplyMint.equals(spl_token_1.NATIVE_MINT);
|
23
22
|
const debtIsWsol = client.debtMint.equals(spl_token_1.NATIVE_MINT);
|
@@ -331,7 +330,7 @@ async function buildSolautoRebalanceTransaction(client, targetLiqUtilizationRate
|
|
331
330
|
client.log("Not eligible for a rebalance");
|
332
331
|
return undefined;
|
333
332
|
}
|
334
|
-
const values = (0, rebalanceUtils_1.getRebalanceValues)(client.solautoPositionState, client.solautoPositionSettings(), client.solautoPositionActiveDca(), (0, generalUtils_1.currentUnixSeconds)(),
|
333
|
+
const values = (0, rebalanceUtils_1.getRebalanceValues)(client.solautoPositionState, client.solautoPositionSettings(), client.solautoPositionActiveDca(), (0, generalUtils_1.currentUnixSeconds)(), (0, generalUtils_1.safeGetPrice)(client.supplyMint), (0, generalUtils_1.safeGetPrice)(client.debtMint), targetLiqUtilizationRateBps);
|
335
334
|
client.log("Rebalance values: ", values);
|
336
335
|
const swapDetails = (0, rebalanceUtils_1.getJupSwapRebalanceDetails)(client, values, targetLiqUtilizationRateBps, attemptNum);
|
337
336
|
const { jupQuote, lookupTableAddresses, setupInstructions, tokenLedgerIx, swapIx, } = await (0, jupiterUtils_1.getJupSwapTransaction)(client.signer, swapDetails, attemptNum);
|
@@ -211,13 +211,13 @@ class TransactionsManager {
|
|
211
211
|
choresBefore.prepend(updateLookupTable.updateLutTx);
|
212
212
|
}
|
213
213
|
if (choresBefore.getInstructions().length > 0) {
|
214
|
-
const chore = new TransactionItem(async () => ({ tx: choresBefore })
|
214
|
+
const chore = new TransactionItem(async () => ({ tx: choresBefore }));
|
215
215
|
await chore.initialize();
|
216
216
|
items.unshift(chore);
|
217
217
|
this.txHandler.log("Chores before: ", choresBefore.getInstructions().length);
|
218
218
|
}
|
219
219
|
if (choresAfter.getInstructions().length > 0) {
|
220
|
-
const chore = new TransactionItem(async () => ({ tx: choresAfter }));
|
220
|
+
const chore = new TransactionItem(async () => ({ tx: choresAfter }), "closing temp accounts");
|
221
221
|
await chore.initialize();
|
222
222
|
items.push(chore);
|
223
223
|
this.txHandler.log("Chores after: ", choresAfter.getInstructions().length);
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
2
|
-
import { MaybeRpcAccount, Umi } from "@metaplex-foundation/umi";
|
2
|
+
import { MaybeRpcAccount, Umi, PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
|
3
3
|
export declare function generateRandomU8(): number;
|
4
4
|
export declare function generateRandomU64(): bigint;
|
5
5
|
export declare function currentUnixSeconds(): number;
|
6
6
|
export declare function getSolanaAccountCreated(umi: Umi, pk: PublicKey): Promise<boolean>;
|
7
7
|
export declare function rpcAccountCreated(account: MaybeRpcAccount): boolean;
|
8
8
|
export declare function arraysAreEqual(arrayA: number[], arrayB: number[]): boolean;
|
9
|
-
export declare function
|
9
|
+
export declare function fetchTokenPrices(mints: PublicKey[]): Promise<number[]>;
|
10
|
+
export declare function safeGetPrice(mint: PublicKey | UmiPublicKey): number | undefined;
|
10
11
|
export type ErrorsToThrow = Array<new (...args: any[]) => Error>;
|
11
12
|
export declare function retryWithExponentialBackoff<T>(fn: (attemptNum: number) => Promise<T>, retries?: number, delay?: number, errorsToThrow?: ErrorsToThrow): Promise<T>;
|
12
13
|
//# sourceMappingURL=generalUtils.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../src/utils/generalUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAa,GAAG,EAAE,MAAM,0BAA0B,CAAC;
|
1
|
+
{"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../src/utils/generalUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAa,GAAG,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKtG,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,SAAS,GACZ,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAU1E;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA+C5E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,CAK/E;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC;AAEjE,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,EAAE,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,OAAO,GAAE,MAAU,EACnB,KAAK,GAAE,MAAY,EACnB,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
|
@@ -6,7 +6,8 @@ exports.currentUnixSeconds = currentUnixSeconds;
|
|
6
6
|
exports.getSolanaAccountCreated = getSolanaAccountCreated;
|
7
7
|
exports.rpcAccountCreated = rpcAccountCreated;
|
8
8
|
exports.arraysAreEqual = arraysAreEqual;
|
9
|
-
exports.
|
9
|
+
exports.fetchTokenPrices = fetchTokenPrices;
|
10
|
+
exports.safeGetPrice = safeGetPrice;
|
10
11
|
exports.retryWithExponentialBackoff = retryWithExponentialBackoff;
|
11
12
|
const umi_1 = require("@metaplex-foundation/umi");
|
12
13
|
const pythConstants_1 = require("../constants/pythConstants");
|
@@ -44,7 +45,7 @@ function arraysAreEqual(arrayA, arrayB) {
|
|
44
45
|
}
|
45
46
|
return true;
|
46
47
|
}
|
47
|
-
async function
|
48
|
+
async function fetchTokenPrices(mints) {
|
48
49
|
const currentTime = currentUnixSeconds();
|
49
50
|
if (!mints.some((mint) => !(mint.toString() in solautoConstants_1.PRICES) ||
|
50
51
|
currentTime - solautoConstants_1.PRICES[mint.toString()].time > 3)) {
|
@@ -79,6 +80,12 @@ async function getTokenPrices(mints) {
|
|
79
80
|
}
|
80
81
|
return prices;
|
81
82
|
}
|
83
|
+
function safeGetPrice(mint) {
|
84
|
+
if (mint.toString() in solautoConstants_1.PRICES) {
|
85
|
+
return solautoConstants_1.PRICES[mint.toString()].price;
|
86
|
+
}
|
87
|
+
return undefined;
|
88
|
+
}
|
82
89
|
function retryWithExponentialBackoff(fn, retries = 5, delay = 150, errorsToThrow) {
|
83
90
|
return new Promise((resolve, reject) => {
|
84
91
|
const attempt = (attemptNum) => {
|
@@ -11,7 +11,6 @@ const umi_web3js_adapters_1 = require("@metaplex-foundation/umi-web3js-adapters"
|
|
11
11
|
const marginfi_sdk_1 = require("../marginfi-sdk");
|
12
12
|
const generalUtils_1 = require("./generalUtils");
|
13
13
|
const numberUtils_1 = require("./numberUtils");
|
14
|
-
const solautoConstants_1 = require("../constants/solautoConstants");
|
15
14
|
const marginfiAccounts_1 = require("../constants/marginfiAccounts");
|
16
15
|
const generalAccounts_1 = require("../constants/generalAccounts");
|
17
16
|
const solanaUtils_1 = require("./solanaUtils");
|
@@ -36,7 +35,7 @@ async function getMaxLtvAndLiqThreshold(umi, supply, debt, supplyPrice) {
|
|
36
35
|
debt.bank = await (0, marginfi_sdk_1.safeFetchBank)(umi, (0, umi_1.publicKey)(marginfiAccounts_1.MARGINFI_ACCOUNTS[debt.mint.toString()].bank));
|
37
36
|
}
|
38
37
|
if (!supplyPrice) {
|
39
|
-
const [price] = await (0, generalUtils_1.
|
38
|
+
const [price] = await (0, generalUtils_1.fetchTokenPrices)([
|
40
39
|
(0, umi_web3js_adapters_1.toWeb3JsPublicKey)(supply.bank.mint),
|
41
40
|
]);
|
42
41
|
supplyPrice = price;
|
@@ -101,7 +100,7 @@ async function getTokenUsage(umi, bank, isAsset, shares, amountUsedAdjustment) {
|
|
101
100
|
let amountCanBeUsed = 0;
|
102
101
|
let marketPrice = 0;
|
103
102
|
if (bank !== null) {
|
104
|
-
[marketPrice] = await (0, generalUtils_1.
|
103
|
+
[marketPrice] = await (0, generalUtils_1.fetchTokenPrices)([(0, umi_web3js_adapters_1.toWeb3JsPublicKey)(bank.mint)]);
|
105
104
|
const [assetShareValue, liabilityShareValue] = await getUpToDateShareValues(umi, bank);
|
106
105
|
const shareValue = isAsset ? assetShareValue : liabilityShareValue;
|
107
106
|
amountUsed = shares * shareValue + Number(amountUsedAdjustment ?? 0);
|
@@ -181,7 +180,7 @@ async function getMarginfiAccountPositionState(umi, marginfiAccountPk, supplyMin
|
|
181
180
|
if (!debtUsage) {
|
182
181
|
debtUsage = await getTokenUsage(umi, debtBank, false, 0, livePositionUpdates?.debtAdjustment);
|
183
182
|
}
|
184
|
-
const supplyPrice =
|
183
|
+
const supplyPrice = (0, generalUtils_1.safeGetPrice)(supplyMint);
|
185
184
|
let [maxLtv, liqThreshold] = await getMaxLtvAndLiqThreshold(umi, {
|
186
185
|
mint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(supplyBank.mint),
|
187
186
|
bank: supplyBank,
|
@@ -69,9 +69,9 @@ function getDebtAdjustmentUsd(liqThresholdBps, supplyUsd, debtUsd, targetLiqUtil
|
|
69
69
|
function getSolautoFeesBps(isReferred, targetLiqUtilizationRateBps, positionNetWorthUsd) {
|
70
70
|
const minSize = 10000; // Minimum position size
|
71
71
|
const maxSize = 500000; // Maximum position size
|
72
|
-
const maxFeeBps =
|
72
|
+
const maxFeeBps = 200; // Fee in basis points for minSize (2%)
|
73
73
|
const minFeeBps = 50; // Fee in basis points for maxSize (0.5%)
|
74
|
-
const k =
|
74
|
+
const k = 1.5;
|
75
75
|
let feeBps = 0;
|
76
76
|
if (targetLiqUtilizationRateBps !== undefined) {
|
77
77
|
feeBps = minFeeBps;
|
@@ -213,7 +213,7 @@ async function getAllPositionsByAuthority(umi, user) {
|
|
213
213
|
}
|
214
214
|
async function positionStateWithLatestPrices(state, supplyPrice, debtPrice) {
|
215
215
|
if (!supplyPrice || !debtPrice) {
|
216
|
-
[supplyPrice, debtPrice] = await (0, generalUtils_1.
|
216
|
+
[supplyPrice, debtPrice] = await (0, generalUtils_1.fetchTokenPrices)([
|
217
217
|
(0, umi_web3js_adapters_1.toWeb3JsPublicKey)(state.supply.mint),
|
218
218
|
(0, umi_web3js_adapters_1.toWeb3JsPublicKey)(state.debt.mint),
|
219
219
|
]);
|
@@ -138,11 +138,11 @@ function getFlashLoanDetails(client, values, jupQuote) {
|
|
138
138
|
let flashLoanTokenPrice = 0;
|
139
139
|
if (values.increasingLeverage) {
|
140
140
|
flashLoanToken = client.solautoPositionState.debt;
|
141
|
-
flashLoanTokenPrice =
|
141
|
+
flashLoanTokenPrice = (0, generalUtils_2.safeGetPrice)(client.debtMint);
|
142
142
|
}
|
143
143
|
else {
|
144
144
|
flashLoanToken = client.solautoPositionState.supply;
|
145
|
-
flashLoanTokenPrice =
|
145
|
+
flashLoanTokenPrice = (0, generalUtils_2.safeGetPrice)(client.supplyMint);
|
146
146
|
}
|
147
147
|
const exactAmountBaseUnit = jupQuote && jupQuote.swapMode === "ExactOut"
|
148
148
|
? BigInt(parseInt(jupQuote.inAmount))
|
@@ -166,15 +166,15 @@ function getJupSwapRebalanceDetails(client, values, targetLiqUtilizationRateBps,
|
|
166
166
|
: client.solautoPositionState.debt;
|
167
167
|
const usdToSwap = Math.abs(values.debtAdjustmentUsd) + values.amountUsdToDcaIn;
|
168
168
|
const inputPrice = values.increasingLeverage
|
169
|
-
?
|
170
|
-
:
|
169
|
+
? (0, generalUtils_2.safeGetPrice)(client.debtMint)
|
170
|
+
: (0, generalUtils_2.safeGetPrice)(client.supplyMint);
|
171
171
|
const inputAmount = (0, numberUtils_1.toBaseUnit)(usdToSwap / inputPrice, input.decimals);
|
172
172
|
const rebalancingToZero = targetLiqUtilizationRateBps === 0;
|
173
173
|
return {
|
174
174
|
inputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(input.mint),
|
175
175
|
outputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(output.mint),
|
176
176
|
destinationWallet: client.solautoPosition,
|
177
|
-
slippageBpsIncFactor: 0.
|
177
|
+
slippageBpsIncFactor: 0.5 + (attemptNum ?? 0) * 0.2,
|
178
178
|
amount: rebalancingToZero
|
179
179
|
? client.solautoPositionState.debt.amountUsed.baseUnit +
|
180
180
|
BigInt(Math.round(Number(client.solautoPositionState.debt.amountUsed.baseUnit) *
|
package/package.json
CHANGED
@@ -32,7 +32,7 @@ import {
|
|
32
32
|
marginfiRefreshData,
|
33
33
|
} from "../generated";
|
34
34
|
import { getMarginfiAccountPDA, getTokenAccount } from "../utils/accountUtils";
|
35
|
-
import { generateRandomU64 } from "../utils/generalUtils";
|
35
|
+
import { generateRandomU64, safeGetPrice } from "../utils/generalUtils";
|
36
36
|
import {
|
37
37
|
MARGINFI_PROGRAM_ID,
|
38
38
|
MarginfiAccount,
|
@@ -630,8 +630,8 @@ export class SolautoMarginfiClient extends SolautoClient {
|
|
630
630
|
|
631
631
|
if (freshState) {
|
632
632
|
this.log("Fresh state", freshState);
|
633
|
-
const supplyPrice =
|
634
|
-
const debtPrice =
|
633
|
+
const supplyPrice = safeGetPrice(freshState?.supply.mint)!;
|
634
|
+
const debtPrice = safeGetPrice(freshState?.debt.mint)!;
|
635
635
|
this.log("Supply price: ", supplyPrice);
|
636
636
|
this.log("Debt price: ", debtPrice);
|
637
637
|
this.log("Liq threshold bps:", freshState.liqThresholdBps);
|
@@ -39,6 +39,7 @@ import {
|
|
39
39
|
currentUnixSeconds,
|
40
40
|
getSolanaAccountCreated,
|
41
41
|
rpcAccountCreated,
|
42
|
+
safeGetPrice,
|
42
43
|
} from "../utils/generalUtils";
|
43
44
|
import { SolautoMarginfiClient } from "../clients/solautoMarginfiClient";
|
44
45
|
import {
|
@@ -586,8 +587,8 @@ export async function buildSolautoRebalanceTransaction(
|
|
586
587
|
client.solautoPositionSettings(),
|
587
588
|
client.solautoPositionActiveDca(),
|
588
589
|
currentUnixSeconds(),
|
589
|
-
|
590
|
-
|
590
|
+
safeGetPrice(client.supplyMint)!,
|
591
|
+
safeGetPrice(client.debtMint)!,
|
591
592
|
targetLiqUtilizationRateBps
|
592
593
|
);
|
593
594
|
client.log("Rebalance values: ", values);
|
@@ -320,10 +320,7 @@ export class TransactionsManager {
|
|
320
320
|
choresBefore.prepend(updateLookupTable.updateLutTx);
|
321
321
|
}
|
322
322
|
if (choresBefore.getInstructions().length > 0) {
|
323
|
-
const chore = new TransactionItem(
|
324
|
-
async () => ({ tx: choresBefore }),
|
325
|
-
"create account(s)"
|
326
|
-
);
|
323
|
+
const chore = new TransactionItem(async () => ({ tx: choresBefore }));
|
327
324
|
await chore.initialize();
|
328
325
|
items.unshift(chore);
|
329
326
|
this.txHandler.log(
|
@@ -332,7 +329,10 @@ export class TransactionsManager {
|
|
332
329
|
);
|
333
330
|
}
|
334
331
|
if (choresAfter.getInstructions().length > 0) {
|
335
|
-
const chore = new TransactionItem(
|
332
|
+
const chore = new TransactionItem(
|
333
|
+
async () => ({ tx: choresAfter }),
|
334
|
+
"closing temp accounts"
|
335
|
+
);
|
336
336
|
await chore.initialize();
|
337
337
|
items.push(chore);
|
338
338
|
this.txHandler.log(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
2
|
-
import { MaybeRpcAccount, publicKey, Umi } from "@metaplex-foundation/umi";
|
2
|
+
import { MaybeRpcAccount, publicKey, Umi, PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
|
3
3
|
import { PYTH_PRICE_FEED_IDS } from "../constants/pythConstants";
|
4
4
|
import { fromBaseUnit, toBaseUnit } from "./numberUtils";
|
5
5
|
import { PRICES } from "../constants/solautoConstants";
|
@@ -45,7 +45,7 @@ export function arraysAreEqual(arrayA: number[], arrayB: number[]): boolean {
|
|
45
45
|
return true;
|
46
46
|
}
|
47
47
|
|
48
|
-
export async function
|
48
|
+
export async function fetchTokenPrices(mints: PublicKey[]): Promise<number[]> {
|
49
49
|
const currentTime = currentUnixSeconds();
|
50
50
|
if (
|
51
51
|
!mints.some(
|
@@ -94,6 +94,13 @@ export async function getTokenPrices(mints: PublicKey[]): Promise<number[]> {
|
|
94
94
|
return prices;
|
95
95
|
}
|
96
96
|
|
97
|
+
export function safeGetPrice(mint: PublicKey | UmiPublicKey): number | undefined {
|
98
|
+
if (mint.toString() in PRICES) {
|
99
|
+
return PRICES[mint.toString()].price;
|
100
|
+
}
|
101
|
+
return undefined;
|
102
|
+
}
|
103
|
+
|
97
104
|
export type ErrorsToThrow = Array<new (...args: any[]) => Error>;
|
98
105
|
|
99
106
|
export function retryWithExponentialBackoff<T>(
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
safeFetchBank,
|
9
9
|
safeFetchMarginfiAccount,
|
10
10
|
} from "../marginfi-sdk";
|
11
|
-
import { currentUnixSeconds,
|
11
|
+
import { currentUnixSeconds, fetchTokenPrices, safeGetPrice } from "./generalUtils";
|
12
12
|
import {
|
13
13
|
bytesToI80F48,
|
14
14
|
fromBaseUnit,
|
@@ -72,7 +72,7 @@ export async function getMaxLtvAndLiqThreshold(
|
|
72
72
|
}
|
73
73
|
|
74
74
|
if (!supplyPrice) {
|
75
|
-
const [price] = await
|
75
|
+
const [price] = await fetchTokenPrices([
|
76
76
|
toWeb3JsPublicKey(supply.bank!.mint),
|
77
77
|
]);
|
78
78
|
supplyPrice = price;
|
@@ -177,7 +177,7 @@ async function getTokenUsage(
|
|
177
177
|
let marketPrice = 0;
|
178
178
|
|
179
179
|
if (bank !== null) {
|
180
|
-
[marketPrice] = await
|
180
|
+
[marketPrice] = await fetchTokenPrices([toWeb3JsPublicKey(bank.mint)]);
|
181
181
|
const [assetShareValue, liabilityShareValue] = await getUpToDateShareValues(
|
182
182
|
umi,
|
183
183
|
bank
|
@@ -335,7 +335,7 @@ export async function getMarginfiAccountPositionState(
|
|
335
335
|
);
|
336
336
|
}
|
337
337
|
|
338
|
-
const supplyPrice =
|
338
|
+
const supplyPrice = safeGetPrice(supplyMint!)!;
|
339
339
|
let [maxLtv, liqThreshold] = await getMaxLtvAndLiqThreshold(
|
340
340
|
umi,
|
341
341
|
{
|
package/src/utils/numberUtils.ts
CHANGED
@@ -97,9 +97,9 @@ export function getSolautoFeesBps(
|
|
97
97
|
} {
|
98
98
|
const minSize = 10_000; // Minimum position size
|
99
99
|
const maxSize = 500_000; // Maximum position size
|
100
|
-
const maxFeeBps =
|
100
|
+
const maxFeeBps = 200; // Fee in basis points for minSize (2%)
|
101
101
|
const minFeeBps = 50; // Fee in basis points for maxSize (0.5%)
|
102
|
-
const k =
|
102
|
+
const k = 1.5;
|
103
103
|
|
104
104
|
let feeBps: number = 0;
|
105
105
|
|
@@ -13,7 +13,7 @@ import {
|
|
13
13
|
getSolautoPositionAccountDataSerializer,
|
14
14
|
getSolautoPositionSize,
|
15
15
|
} from "../../generated";
|
16
|
-
import { currentUnixSeconds,
|
16
|
+
import { currentUnixSeconds, fetchTokenPrices } from "../generalUtils";
|
17
17
|
import {
|
18
18
|
fromBaseUnit,
|
19
19
|
getLiqUtilzationRateBps,
|
@@ -323,7 +323,7 @@ export async function positionStateWithLatestPrices(
|
|
323
323
|
debtPrice?: number
|
324
324
|
): Promise<PositionState> {
|
325
325
|
if (!supplyPrice || !debtPrice) {
|
326
|
-
[supplyPrice, debtPrice] = await
|
326
|
+
[supplyPrice, debtPrice] = await fetchTokenPrices([
|
327
327
|
toWeb3JsPublicKey(state.supply.mint),
|
328
328
|
toWeb3JsPublicKey(state.debt.mint),
|
329
329
|
]);
|
@@ -14,7 +14,7 @@ import {
|
|
14
14
|
import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
15
15
|
import { QuoteResponse } from "@jup-ag/api";
|
16
16
|
import { JupSwapDetails } from "../jupiterUtils";
|
17
|
-
import { currentUnixSeconds } from "../generalUtils";
|
17
|
+
import { currentUnixSeconds, safeGetPrice } from "../generalUtils";
|
18
18
|
import {
|
19
19
|
fromBaseUnit,
|
20
20
|
fromBps,
|
@@ -300,10 +300,10 @@ export function getFlashLoanDetails(
|
|
300
300
|
let flashLoanTokenPrice = 0;
|
301
301
|
if (values.increasingLeverage) {
|
302
302
|
flashLoanToken = client.solautoPositionState!.debt;
|
303
|
-
flashLoanTokenPrice =
|
303
|
+
flashLoanTokenPrice = safeGetPrice(client.debtMint)!;
|
304
304
|
} else {
|
305
305
|
flashLoanToken = client.solautoPositionState!.supply;
|
306
|
-
flashLoanTokenPrice =
|
306
|
+
flashLoanTokenPrice = safeGetPrice(client.supplyMint)!;
|
307
307
|
}
|
308
308
|
|
309
309
|
const exactAmountBaseUnit =
|
@@ -346,8 +346,8 @@ export function getJupSwapRebalanceDetails(
|
|
346
346
|
Math.abs(values.debtAdjustmentUsd) + values.amountUsdToDcaIn;
|
347
347
|
|
348
348
|
const inputPrice = values.increasingLeverage
|
349
|
-
?
|
350
|
-
:
|
349
|
+
? safeGetPrice(client.debtMint)
|
350
|
+
: safeGetPrice(client.supplyMint);
|
351
351
|
const inputAmount = toBaseUnit(usdToSwap / inputPrice!, input.decimals);
|
352
352
|
|
353
353
|
const rebalancingToZero = targetLiqUtilizationRateBps === 0;
|
@@ -355,7 +355,7 @@ export function getJupSwapRebalanceDetails(
|
|
355
355
|
inputMint: toWeb3JsPublicKey(input.mint),
|
356
356
|
outputMint: toWeb3JsPublicKey(output.mint),
|
357
357
|
destinationWallet: client.solautoPosition,
|
358
|
-
slippageBpsIncFactor: 0.
|
358
|
+
slippageBpsIncFactor: 0.5 + (attemptNum ?? 0) * 0.2,
|
359
359
|
amount: rebalancingToZero
|
360
360
|
? client.solautoPositionState!.debt.amountUsed.baseUnit +
|
361
361
|
BigInt(
|
@@ -1,22 +1,17 @@
|
|
1
1
|
import { describe, it } from "mocha";
|
2
2
|
import { none, publicKey, some } from "@metaplex-foundation/umi";
|
3
3
|
import { setupTest } from "../shared";
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
SolautoMarginfiClient,
|
6
|
+
} from "../../src/clients/solautoMarginfiClient";
|
5
7
|
import {
|
6
8
|
solautoAction,
|
7
9
|
SolautoSettingsParametersInpArgs,
|
8
10
|
} from "../../src/generated";
|
9
11
|
import { buildSolautoRebalanceTransaction } from "../../src/transactions/transactionUtils";
|
10
|
-
import {
|
11
|
-
getDebtAdjustmentUsd,
|
12
|
-
getLiqUtilzationRateBps,
|
13
|
-
maxBoostToBps,
|
14
|
-
maxRepayFromBps,
|
15
|
-
maxRepayToBps,
|
16
|
-
toBaseUnit,
|
17
|
-
} from "../../src/utils/numberUtils";
|
12
|
+
import { maxBoostToBps, maxRepayFromBps, maxRepayToBps, toBaseUnit } from "../../src/utils/numberUtils";
|
18
13
|
import { NATIVE_MINT } from "@solana/spl-token";
|
19
|
-
import {
|
14
|
+
import { fetchTokenPrices } from "../../src/utils/generalUtils";
|
20
15
|
import {
|
21
16
|
TransactionItem,
|
22
17
|
TransactionsManager,
|
@@ -33,22 +28,25 @@ describe("Solauto Marginfi tests", async () => {
|
|
33
28
|
const positionId = 1;
|
34
29
|
|
35
30
|
it("open - deposit - borrow - rebalance to 0 - withdraw - close", async () => {
|
31
|
+
|
36
32
|
const client = new SolautoMarginfiClient(process.env.HELIUS_API_KEY!, true);
|
37
33
|
|
38
34
|
const supply = NATIVE_MINT;
|
39
35
|
const supplyDecimals = 9;
|
40
36
|
const debtDecimals = 6;
|
41
37
|
|
42
|
-
await client.initialize(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
await client.initialize(
|
39
|
+
{
|
40
|
+
signer,
|
41
|
+
positionId,
|
42
|
+
authority: new PublicKey("AprYCPiVeKMCgjQ2ZufwChMzvQ5kFjJo2ekTLSkXsQDm")
|
43
|
+
// marginfiAccount: new PublicKey(
|
44
|
+
// "4nNvUXF5YqHFcH2nGweSiuvy1ct7V5FXfoCLKFYUN36z"
|
45
|
+
// ),
|
46
|
+
// supplyMint: NATIVE_MINT,
|
47
|
+
// debtMint: new PublicKey(USDC_MINT),
|
48
|
+
}
|
49
|
+
);
|
52
50
|
|
53
51
|
const transactionItems: TransactionItem[] = [];
|
54
52
|
// const settingParams: SolautoSettingsParametersInpArgs = {
|
@@ -72,7 +70,7 @@ describe("Solauto Marginfi tests", async () => {
|
|
72
70
|
// const initialSupplyUsd = 150;
|
73
71
|
// transactionItems.push(
|
74
72
|
// new TransactionItem(async () => {
|
75
|
-
// const [supplyPrice] = await
|
73
|
+
// const [supplyPrice] = await fetchTokenPrices([supply]);
|
76
74
|
// return {
|
77
75
|
// tx: client.protocolInteraction(
|
78
76
|
// solautoAction("Deposit", [
|
@@ -111,7 +109,7 @@ describe("Solauto Marginfi tests", async () => {
|
|
111
109
|
// const initialSupplyUsd = 50;
|
112
110
|
// transactionItems.push(
|
113
111
|
// new TransactionItem(async () => {
|
114
|
-
// const [supplyPrice] = await
|
112
|
+
// const [supplyPrice] = await fetchTokenPrices([supply]);
|
115
113
|
// return {
|
116
114
|
// tx: client.protocolInteraction(
|
117
115
|
// solautoAction("Deposit", [
|
@@ -122,13 +120,13 @@ describe("Solauto Marginfi tests", async () => {
|
|
122
120
|
// }, "deposit")
|
123
121
|
// );
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
123
|
+
transactionItems.push(
|
124
|
+
new TransactionItem(
|
125
|
+
async (attemptNum) =>
|
126
|
+
await buildSolautoRebalanceTransaction(client, undefined, attemptNum),
|
127
|
+
"rebalance"
|
128
|
+
)
|
129
|
+
);
|
132
130
|
|
133
131
|
// transactionItems.push(
|
134
132
|
// new TransactionItem(
|
@@ -157,19 +155,11 @@ describe("Solauto Marginfi tests", async () => {
|
|
157
155
|
// )
|
158
156
|
// );
|
159
157
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
// const debtAdjustment = getDebtAdjustmentUsd(8696, 366, 165, 7000);
|
168
|
-
// const newLiqUtilizationRate = getLiqUtilzationRateBps(366 + debtAdjustment, 165 + debtAdjustment, 8696);
|
169
|
-
// console.log(newLiqUtilizationRate);
|
170
|
-
|
171
|
-
console.log("CURRENT", Number(client.solautoPositionState?.supply.amountUsed.baseUnit));
|
172
|
-
const freshState = await client.getFreshPositionState();
|
173
|
-
console.log("FRESH", Number(freshState!.supply.amountUsed.baseUnit));
|
158
|
+
await new TransactionsManager(
|
159
|
+
client,
|
160
|
+
undefined,
|
161
|
+
!payForTransactions ? "only-simulate" : "normal",
|
162
|
+
useJitoBundle
|
163
|
+
).clientSend(transactionItems);
|
174
164
|
});
|
175
165
|
});
|
@@ -31,7 +31,8 @@ import {
|
|
31
31
|
} from "../../src/utils/solauto/generalUtils";
|
32
32
|
import {
|
33
33
|
currentUnixSeconds,
|
34
|
-
|
34
|
+
fetchTokenPrices,
|
35
|
+
safeGetPrice,
|
35
36
|
} from "../../src/utils/generalUtils";
|
36
37
|
import { USDC_MINT } from "../../src/constants/tokenConstants";
|
37
38
|
import { PRICES } from "../../src/constants";
|
@@ -50,8 +51,8 @@ function assertAccurateRebalance(
|
|
50
51
|
client.solautoPositionSettings(),
|
51
52
|
client.solautoPositionActiveDca(),
|
52
53
|
currentUnixSeconds(),
|
53
|
-
|
54
|
-
|
54
|
+
safeGetPrice(client.supplyMint)!,
|
55
|
+
safeGetPrice(client.debtMint)!,
|
55
56
|
targetLiqUtilizationRateBps
|
56
57
|
);
|
57
58
|
|
@@ -124,7 +125,7 @@ async function getFakePosition(
|
|
124
125
|
createFakePositionState(
|
125
126
|
{
|
126
127
|
amountUsed: supplyUsd / supplyPrice,
|
127
|
-
price:
|
128
|
+
price: safeGetPrice(NATIVE_MINT)!,
|
128
129
|
mint: NATIVE_MINT,
|
129
130
|
},
|
130
131
|
{
|
@@ -282,7 +283,7 @@ describe("Rebalance tests", async () => {
|
|
282
283
|
let supplyPrice: number, debtPrice: number;
|
283
284
|
|
284
285
|
before(async () => {
|
285
|
-
[supplyPrice, debtPrice] = await
|
286
|
+
[supplyPrice, debtPrice] = await fetchTokenPrices([
|
286
287
|
NATIVE_MINT,
|
287
288
|
new PublicKey(USDC_MINT),
|
288
289
|
]);
|