@haven-fi/solauto-sdk 1.0.127 → 1.0.129
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/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
|
]);
|