@haven-fi/solauto-sdk 1.0.505 → 1.0.508
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/utils/jupiterUtils.d.ts +7 -4
- package/dist/utils/jupiterUtils.d.ts.map +1 -1
- package/dist/utils/jupiterUtils.js +18 -16
- package/dist/utils/priceUtils.d.ts +2 -1
- package/dist/utils/priceUtils.d.ts.map +1 -1
- package/dist/utils/priceUtils.js +8 -9
- package/dist/utils/solauto/rebalanceUtils.d.ts.map +1 -1
- package/dist/utils/solauto/rebalanceUtils.js +29 -19
- package/package.json +1 -1
- package/src/utils/jupiterUtils.ts +38 -28
- package/src/utils/priceUtils.ts +12 -17
- package/src/utils/solauto/rebalanceUtils.ts +44 -33
- package/tests/transactions/solautoMarginfi.ts +12 -20
@@ -1,17 +1,20 @@
|
|
1
1
|
import { Signer, TransactionBuilder } from "@metaplex-foundation/umi";
|
2
2
|
import { PublicKey } from "@solana/web3.js";
|
3
3
|
import { QuoteResponse } from "@jup-ag/api";
|
4
|
-
export interface
|
4
|
+
export interface JupSwapInput {
|
5
5
|
inputMint: PublicKey;
|
6
6
|
outputMint: PublicKey;
|
7
|
-
destinationWallet: PublicKey;
|
8
7
|
amount: bigint;
|
9
|
-
slippageIncFactor?: number;
|
10
|
-
exactOut?: boolean;
|
11
8
|
exactIn?: boolean;
|
9
|
+
exactOut?: boolean;
|
10
|
+
}
|
11
|
+
export interface JupSwapDetails extends JupSwapInput {
|
12
|
+
destinationWallet: PublicKey;
|
13
|
+
slippageIncFactor?: number;
|
12
14
|
addPadding?: boolean;
|
13
15
|
jupQuote?: QuoteResponse;
|
14
16
|
}
|
17
|
+
export declare function getJupQuote(swapDetails: JupSwapInput): Promise<QuoteResponse>;
|
15
18
|
export interface JupSwapTransaction {
|
16
19
|
jupQuote: QuoteResponse;
|
17
20
|
priceImpactBps: number;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"jupiterUtils.d.ts","sourceRoot":"","sources":["../../src/utils/jupiterUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,SAAS,EAA0B,MAAM,iBAAiB,CAAC;AAGpE,OAAO,
|
1
|
+
{"version":3,"file":"jupiterUtils.d.ts","sourceRoot":"","sources":["../../src/utils/jupiterUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,SAAS,EAA0B,MAAM,iBAAiB,CAAC;AAGpE,OAAO,EAIL,aAAa,EACd,MAAM,aAAa,CAAC;AAUrB,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,SAAS,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,iBAAiB,EAAE,SAAS,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAgBD,wBAAsB,WAAW,CAAC,WAAW,EAAE,YAAY,0BAsB1D;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,iBAAiB,EAAE,kBAAkB,CAAC;IACtC,aAAa,EAAE,kBAAkB,CAAC;IAClC,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,cAAc,EAC3B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAmF7B;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO;;GA0B5E"}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getJupQuote = getJupQuote;
|
3
4
|
exports.getJupSwapTransaction = getJupSwapTransaction;
|
4
5
|
exports.getJupPriceData = getJupPriceData;
|
5
6
|
const umi_1 = require("@metaplex-foundation/umi");
|
@@ -9,7 +10,6 @@ const numberUtils_1 = require("./numberUtils");
|
|
9
10
|
const api_1 = require("@jup-ag/api");
|
10
11
|
const accountUtils_1 = require("./accountUtils");
|
11
12
|
const generalUtils_1 = require("./generalUtils");
|
12
|
-
const constants_1 = require("../constants");
|
13
13
|
const jupApi = (0, api_1.createJupiterApiClient)();
|
14
14
|
function createTransactionInstruction(instruction) {
|
15
15
|
return new web3_js_1.TransactionInstruction({
|
@@ -22,22 +22,24 @@ function createTransactionInstruction(instruction) {
|
|
22
22
|
data: Buffer.from(instruction.data, "base64"),
|
23
23
|
});
|
24
24
|
}
|
25
|
+
async function getJupQuote(swapDetails) {
|
26
|
+
const memecoinSwap = (0, generalUtils_1.tokenInfo)(swapDetails.inputMint).isMeme ||
|
27
|
+
(0, generalUtils_1.tokenInfo)(swapDetails.outputMint).isMeme;
|
28
|
+
return await (0, generalUtils_1.retryWithExponentialBackoff)(async () => await jupApi.quoteGet({
|
29
|
+
amount: Number(swapDetails.amount),
|
30
|
+
inputMint: swapDetails.inputMint.toString(),
|
31
|
+
outputMint: swapDetails.outputMint.toString(),
|
32
|
+
swapMode: swapDetails.exactIn
|
33
|
+
? "ExactOut"
|
34
|
+
: swapDetails.exactIn
|
35
|
+
? "ExactIn"
|
36
|
+
: undefined,
|
37
|
+
slippageBps: memecoinSwap ? 500 : 200,
|
38
|
+
maxAccounts: !swapDetails.exactOut ? 40 : undefined,
|
39
|
+
}), 4, 200);
|
40
|
+
}
|
25
41
|
async function getJupSwapTransaction(signer, swapDetails, attemptNum) {
|
26
|
-
const
|
27
|
-
constants_1.TOKEN_INFO[swapDetails.outputMint.toString()].isMeme;
|
28
|
-
const quoteResponse = swapDetails.jupQuote ??
|
29
|
-
(await (0, generalUtils_1.retryWithExponentialBackoff)(async () => await jupApi.quoteGet({
|
30
|
-
amount: Number(swapDetails.amount),
|
31
|
-
inputMint: swapDetails.inputMint.toString(),
|
32
|
-
outputMint: swapDetails.outputMint.toString(),
|
33
|
-
swapMode: swapDetails.exactOut
|
34
|
-
? "ExactOut"
|
35
|
-
: swapDetails.exactIn
|
36
|
-
? "ExactIn"
|
37
|
-
: undefined,
|
38
|
-
slippageBps: memecoinSwap ? 500 : 200,
|
39
|
-
maxAccounts: !swapDetails.exactOut ? 40 : undefined,
|
40
|
-
}), 4, 200));
|
42
|
+
const quoteResponse = swapDetails.jupQuote ?? (await getJupQuote(swapDetails));
|
41
43
|
const priceImpactBps = Math.round((0, numberUtils_1.toBps)(parseFloat(quoteResponse.priceImpactPct))) + 1;
|
42
44
|
const finalPriceSlippageBps = Math.round(Math.max(50, quoteResponse.slippageBps, priceImpactBps) *
|
43
45
|
(1 + (swapDetails.slippageIncFactor ?? 0)));
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
2
2
|
import { PublicKey as UmiPublicKey } from "@metaplex-foundation/umi";
|
3
|
+
import { QuoteGetSwapModeEnum } from "@jup-ag/api";
|
3
4
|
export declare function fetchTokenPrices(mints: PublicKey[]): Promise<number[]>;
|
4
5
|
export declare function getPythPrices(mints: PublicKey[]): Promise<number[]>;
|
5
6
|
export declare function getSwitchboardPrices(mints: PublicKey[]): Promise<number[]>;
|
6
7
|
export declare function getJupTokenPrices(mints: PublicKey[]): Promise<number[]>;
|
7
8
|
export declare function safeGetPrice(mint: PublicKey | UmiPublicKey | undefined): number | undefined;
|
8
|
-
export declare function getPriceImpact(inputMint: PublicKey,
|
9
|
+
export declare function getPriceImpact(inputMint: PublicKey, outputMint: PublicKey, amount: bigint, swapMode: QuoteGetSwapModeEnum): Promise<{
|
9
10
|
priceImpact: number;
|
10
11
|
quote: import("@jup-ag/api").QuoteResponse;
|
11
12
|
}>;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"priceUtils.d.ts","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
1
|
+
{"version":3,"file":"priceUtils.d.ts","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAcrE,OAAO,EAA0B,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE3E,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqC5E;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,qBAwCrD;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAgDnB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,qBAQzD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GACzC,MAAM,GAAG,SAAS,CAKpB;AAED,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,SAAS,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,oBAAoB;;;GAc/B"}
|
package/dist/utils/priceUtils.js
CHANGED
@@ -36,7 +36,6 @@ const switchboardConstants_1 = require("../constants/switchboardConstants");
|
|
36
36
|
const generalUtils_1 = require("./generalUtils");
|
37
37
|
const OnDemand = __importStar(require("@switchboard-xyz/on-demand"));
|
38
38
|
const jupiterUtils_1 = require("./jupiterUtils");
|
39
|
-
const api_1 = require("@jup-ag/api");
|
40
39
|
async function fetchTokenPrices(mints) {
|
41
40
|
const currentTime = (0, generalUtils_1.currentUnixSeconds)();
|
42
41
|
if (!mints.some((mint) => !(mint.toString() in solautoConstants_1.PRICES) ||
|
@@ -130,14 +129,14 @@ function safeGetPrice(mint) {
|
|
130
129
|
}
|
131
130
|
return undefined;
|
132
131
|
}
|
133
|
-
async function getPriceImpact(inputMint,
|
134
|
-
const
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
})
|
132
|
+
async function getPriceImpact(inputMint, outputMint, amount, swapMode) {
|
133
|
+
const quoteResponse = await (0, jupiterUtils_1.getJupQuote)({
|
134
|
+
inputMint,
|
135
|
+
outputMint,
|
136
|
+
amount,
|
137
|
+
exactIn: swapMode === "ExactIn",
|
138
|
+
exactOut: swapMode === "ExactOut",
|
139
|
+
});
|
141
140
|
return {
|
142
141
|
priceImpact: parseFloat(quoteResponse.priceImpactPct),
|
143
142
|
quote: quoteResponse,
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"rebalanceUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/solauto/rebalanceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EACL,WAAW,EACX,aAAa,EAEb,kBAAkB,EAClB,yBAAyB,EACzB,SAAS,EACV,MAAM,iBAAiB,CAAC;AAOzB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,
|
1
|
+
{"version":3,"file":"rebalanceUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/solauto/rebalanceUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EACL,WAAW,EACX,aAAa,EAEb,kBAAkB,EAClB,yBAAyB,EACzB,SAAS,EACV,MAAM,iBAAiB,CAAC;AAOzB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAe,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAa5E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAoI9C,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,yBAAyB,GAAG,SAAS,EAC/C,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,2BAA2B,CAAC,EAAE,MAAM,GACnC,eAAe,CAwDjB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,eAAe;;;EAsDxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,aAAa,GACtB,gBAAgB,GAAG,SAAS,CAgC9B;AAED,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,eAAe,EACvB,2BAA2B,CAAC,EAAE,MAAM,EACpC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAwFzB"}
|
@@ -7,6 +7,7 @@ exports.getJupSwapRebalanceDetails = getJupSwapRebalanceDetails;
|
|
7
7
|
const generated_1 = require("../../generated");
|
8
8
|
const generalUtils_1 = require("./generalUtils");
|
9
9
|
const umi_web3js_adapters_1 = require("@metaplex-foundation/umi-web3js-adapters");
|
10
|
+
const jupiterUtils_1 = require("../jupiterUtils");
|
10
11
|
const generalUtils_2 = require("../generalUtils");
|
11
12
|
const numberUtils_1 = require("../numberUtils");
|
12
13
|
const generalAccounts_1 = require("../../constants/generalAccounts");
|
@@ -165,10 +166,11 @@ async function getJupSwapRebalanceDetails(client, values, targetLiqUtilizationRa
|
|
165
166
|
const output = values.rebalanceDirection === generated_1.RebalanceDirection.Boost
|
166
167
|
? client.solautoPositionState.supply
|
167
168
|
: client.solautoPositionState.debt;
|
169
|
+
const rebalanceToZero = targetLiqUtilizationRateBps === 0;
|
168
170
|
const usdToSwap = Math.abs(values.debtAdjustmentUsd) +
|
169
171
|
(values.dcaTokenType === generated_1.TokenType.Debt ? values.amountUsdToDcaIn : 0);
|
170
172
|
let inputAmount = (0, numberUtils_1.toBaseUnit)(usdToSwap / (0, priceUtils_1.safeGetPrice)(input.mint), input.decimals);
|
171
|
-
const outputAmount =
|
173
|
+
const outputAmount = rebalanceToZero
|
172
174
|
? output.amountUsed.baseUnit +
|
173
175
|
BigInt(Math.round(Number(output.amountUsed.baseUnit) *
|
174
176
|
// Add this small percentage to account for the APR on the debt between now and the transaction
|
@@ -177,33 +179,41 @@ async function getJupSwapRebalanceDetails(client, values, targetLiqUtilizationRa
|
|
177
179
|
const repaying = values.rebalanceDirection === generated_1.RebalanceDirection.Repay;
|
178
180
|
const { requiresFlashLoan, useDebtLiquidity } = rebalanceRequiresFlashLoan(client, values);
|
179
181
|
const flashLoanRepayFromDebt = repaying && requiresFlashLoan && useDebtLiquidity;
|
180
|
-
const exactOut =
|
181
|
-
// targetLiqUtilizationRateBps === 0 ||
|
182
|
-
// values.repayingCloseToMaxLtv ||
|
183
|
-
flashLoanRepayFromDebt;
|
182
|
+
const exactOut = rebalanceToZero || flashLoanRepayFromDebt;
|
184
183
|
const exactIn = !exactOut;
|
184
|
+
const jupSwapInput = {
|
185
|
+
inputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(input.mint),
|
186
|
+
outputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(output.mint),
|
187
|
+
exactIn,
|
188
|
+
exactOut,
|
189
|
+
amount: exactOut ? outputAmount : inputAmount,
|
190
|
+
};
|
185
191
|
let jupQuote = undefined;
|
186
|
-
if (
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
priceImpact =
|
192
|
-
|
193
|
-
|
194
|
-
|
192
|
+
if (rebalanceToZero) {
|
193
|
+
try {
|
194
|
+
jupQuote = await (0, jupiterUtils_1.getJupQuote)(jupSwapInput);
|
195
|
+
}
|
196
|
+
catch {
|
197
|
+
let priceImpact = 0;
|
198
|
+
inputAmount += BigInt(Math.round(Number(inputAmount) * 0.001));
|
199
|
+
do {
|
200
|
+
const res = await (0, priceUtils_1.getPriceImpact)((0, umi_web3js_adapters_1.toWeb3JsPublicKey)(input.mint), (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(output.mint), inputAmount + BigInt(Math.round(Number(inputAmount) * priceImpact)), "ExactIn");
|
201
|
+
priceImpact = res.priceImpact;
|
202
|
+
jupQuote = res.quote;
|
203
|
+
inputAmount =
|
204
|
+
BigInt(parseInt(res.quote.inAmount)) +
|
205
|
+
BigInt(Math.round(Number(inputAmount) * 0.001));
|
206
|
+
} while (parseInt(jupQuote.outAmount) < outputAmount &&
|
207
|
+
priceImpact > 0.001);
|
208
|
+
}
|
195
209
|
}
|
196
210
|
const addPadding = exactOut;
|
197
211
|
return {
|
198
|
-
|
199
|
-
outputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(output.mint),
|
212
|
+
...jupSwapInput,
|
200
213
|
destinationWallet: flashLoanRepayFromDebt
|
201
214
|
? (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(client.signer.publicKey)
|
202
215
|
: client.solautoPosition,
|
203
216
|
slippageIncFactor: 0.2 + (attemptNum ?? 0) * 0.25,
|
204
|
-
amount: exactOut ? outputAmount : inputAmount,
|
205
|
-
exactIn,
|
206
|
-
exactOut,
|
207
217
|
addPadding,
|
208
218
|
jupQuote,
|
209
219
|
};
|
package/package.json
CHANGED
@@ -9,22 +9,29 @@ import { fromBps, toBps } from "./numberUtils";
|
|
9
9
|
import {
|
10
10
|
createJupiterApiClient,
|
11
11
|
Instruction,
|
12
|
+
QuoteGetSwapModeEnum,
|
12
13
|
QuoteResponse,
|
13
14
|
} from "@jup-ag/api";
|
14
15
|
import { getTokenAccount } from "./accountUtils";
|
15
|
-
import {
|
16
|
-
|
16
|
+
import {
|
17
|
+
consoleLog,
|
18
|
+
retryWithExponentialBackoff,
|
19
|
+
tokenInfo,
|
20
|
+
} from "./generalUtils";
|
17
21
|
|
18
22
|
const jupApi = createJupiterApiClient();
|
19
23
|
|
20
|
-
export interface
|
24
|
+
export interface JupSwapInput {
|
21
25
|
inputMint: PublicKey;
|
22
26
|
outputMint: PublicKey;
|
23
|
-
destinationWallet: PublicKey;
|
24
27
|
amount: bigint;
|
25
|
-
slippageIncFactor?: number;
|
26
|
-
exactOut?: boolean;
|
27
28
|
exactIn?: boolean;
|
29
|
+
exactOut?: boolean;
|
30
|
+
}
|
31
|
+
|
32
|
+
export interface JupSwapDetails extends JupSwapInput {
|
33
|
+
destinationWallet: PublicKey;
|
34
|
+
slippageIncFactor?: number;
|
28
35
|
addPadding?: boolean;
|
29
36
|
jupQuote?: QuoteResponse;
|
30
37
|
}
|
@@ -43,6 +50,30 @@ function createTransactionInstruction(
|
|
43
50
|
});
|
44
51
|
}
|
45
52
|
|
53
|
+
export async function getJupQuote(swapDetails: JupSwapInput) {
|
54
|
+
const memecoinSwap =
|
55
|
+
tokenInfo(swapDetails.inputMint).isMeme ||
|
56
|
+
tokenInfo(swapDetails.outputMint).isMeme;
|
57
|
+
|
58
|
+
return await retryWithExponentialBackoff(
|
59
|
+
async () =>
|
60
|
+
await jupApi.quoteGet({
|
61
|
+
amount: Number(swapDetails.amount),
|
62
|
+
inputMint: swapDetails.inputMint.toString(),
|
63
|
+
outputMint: swapDetails.outputMint.toString(),
|
64
|
+
swapMode: swapDetails.exactIn
|
65
|
+
? "ExactOut"
|
66
|
+
: swapDetails.exactIn
|
67
|
+
? "ExactIn"
|
68
|
+
: undefined,
|
69
|
+
slippageBps: memecoinSwap ? 500 : 200,
|
70
|
+
maxAccounts: !swapDetails.exactOut ? 40 : undefined,
|
71
|
+
}),
|
72
|
+
4,
|
73
|
+
200
|
74
|
+
);
|
75
|
+
}
|
76
|
+
|
46
77
|
export interface JupSwapTransaction {
|
47
78
|
jupQuote: QuoteResponse;
|
48
79
|
priceImpactBps: number;
|
@@ -57,29 +88,8 @@ export async function getJupSwapTransaction(
|
|
57
88
|
swapDetails: JupSwapDetails,
|
58
89
|
attemptNum?: number
|
59
90
|
): Promise<JupSwapTransaction> {
|
60
|
-
const memecoinSwap =
|
61
|
-
TOKEN_INFO[swapDetails.inputMint.toString()].isMeme ||
|
62
|
-
TOKEN_INFO[swapDetails.outputMint.toString()].isMeme;
|
63
|
-
|
64
91
|
const quoteResponse =
|
65
|
-
swapDetails.jupQuote ??
|
66
|
-
(await retryWithExponentialBackoff(
|
67
|
-
async () =>
|
68
|
-
await jupApi.quoteGet({
|
69
|
-
amount: Number(swapDetails.amount),
|
70
|
-
inputMint: swapDetails.inputMint.toString(),
|
71
|
-
outputMint: swapDetails.outputMint.toString(),
|
72
|
-
swapMode: swapDetails.exactOut
|
73
|
-
? "ExactOut"
|
74
|
-
: swapDetails.exactIn
|
75
|
-
? "ExactIn"
|
76
|
-
: undefined,
|
77
|
-
slippageBps: memecoinSwap ? 500 : 200,
|
78
|
-
maxAccounts: !swapDetails.exactOut ? 40 : undefined,
|
79
|
-
}),
|
80
|
-
4,
|
81
|
-
200
|
82
|
-
));
|
92
|
+
swapDetails.jupQuote ?? (await getJupQuote(swapDetails));
|
83
93
|
|
84
94
|
const priceImpactBps =
|
85
95
|
Math.round(toBps(parseFloat(quoteResponse.priceImpactPct))) + 1;
|
package/src/utils/priceUtils.ts
CHANGED
@@ -12,8 +12,8 @@ import {
|
|
12
12
|
zip,
|
13
13
|
} from "./generalUtils";
|
14
14
|
import * as OnDemand from "@switchboard-xyz/on-demand";
|
15
|
-
import { getJupPriceData } from "./jupiterUtils";
|
16
|
-
import { createJupiterApiClient } from "@jup-ag/api";
|
15
|
+
import { getJupPriceData, getJupQuote } from "./jupiterUtils";
|
16
|
+
import { createJupiterApiClient, QuoteGetSwapModeEnum } from "@jup-ag/api";
|
17
17
|
|
18
18
|
export async function fetchTokenPrices(mints: PublicKey[]): Promise<number[]> {
|
19
19
|
const currentTime = currentUnixSeconds();
|
@@ -169,22 +169,17 @@ export function safeGetPrice(
|
|
169
169
|
|
170
170
|
export async function getPriceImpact(
|
171
171
|
inputMint: PublicKey,
|
172
|
-
|
173
|
-
|
172
|
+
outputMint: PublicKey,
|
173
|
+
amount: bigint,
|
174
|
+
swapMode: QuoteGetSwapModeEnum
|
174
175
|
) {
|
175
|
-
const
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
outputMint: outputMint.toString(),
|
183
|
-
swapMode: "ExactIn",
|
184
|
-
}),
|
185
|
-
4,
|
186
|
-
200
|
187
|
-
);
|
176
|
+
const quoteResponse = await getJupQuote({
|
177
|
+
inputMint,
|
178
|
+
outputMint,
|
179
|
+
amount,
|
180
|
+
exactIn: swapMode === "ExactIn",
|
181
|
+
exactOut: swapMode === "ExactOut",
|
182
|
+
});
|
188
183
|
|
189
184
|
return {
|
190
185
|
priceImpact: parseFloat(quoteResponse.priceImpactPct),
|
@@ -15,7 +15,7 @@ import {
|
|
15
15
|
} from "./generalUtils";
|
16
16
|
import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
17
17
|
import { QuoteResponse } from "@jup-ag/api";
|
18
|
-
import { JupSwapDetails } from "../jupiterUtils";
|
18
|
+
import { getJupQuote, JupSwapDetails, JupSwapInput } from "../jupiterUtils";
|
19
19
|
import { consoleLog, currentUnixSeconds } from "../generalUtils";
|
20
20
|
import {
|
21
21
|
fromBaseUnit,
|
@@ -354,6 +354,7 @@ export async function getJupSwapRebalanceDetails(
|
|
354
354
|
? client.solautoPositionState!.supply
|
355
355
|
: client.solautoPositionState!.debt;
|
356
356
|
|
357
|
+
const rebalanceToZero = targetLiqUtilizationRateBps === 0;
|
357
358
|
const usdToSwap =
|
358
359
|
Math.abs(values.debtAdjustmentUsd) +
|
359
360
|
(values.dcaTokenType === TokenType.Debt ? values.amountUsdToDcaIn : 0);
|
@@ -362,17 +363,16 @@ export async function getJupSwapRebalanceDetails(
|
|
362
363
|
usdToSwap / safeGetPrice(input.mint)!,
|
363
364
|
input.decimals
|
364
365
|
);
|
365
|
-
const outputAmount =
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
0.0001
|
373
|
-
)
|
366
|
+
const outputAmount = rebalanceToZero
|
367
|
+
? output.amountUsed.baseUnit +
|
368
|
+
BigInt(
|
369
|
+
Math.round(
|
370
|
+
Number(output.amountUsed.baseUnit) *
|
371
|
+
// Add this small percentage to account for the APR on the debt between now and the transaction
|
372
|
+
0.0001
|
374
373
|
)
|
375
|
-
|
374
|
+
)
|
375
|
+
: toBaseUnit(usdToSwap / safeGetPrice(output.mint)!, output.decimals);
|
376
376
|
|
377
377
|
const repaying = values.rebalanceDirection === RebalanceDirection.Repay;
|
378
378
|
|
@@ -383,41 +383,52 @@ export async function getJupSwapRebalanceDetails(
|
|
383
383
|
const flashLoanRepayFromDebt =
|
384
384
|
repaying && requiresFlashLoan && useDebtLiquidity;
|
385
385
|
|
386
|
-
const exactOut =
|
387
|
-
// targetLiqUtilizationRateBps === 0 ||
|
388
|
-
// values.repayingCloseToMaxLtv ||
|
389
|
-
flashLoanRepayFromDebt;
|
386
|
+
const exactOut = rebalanceToZero || flashLoanRepayFromDebt;
|
390
387
|
const exactIn = !exactOut;
|
391
388
|
|
389
|
+
const jupSwapInput: JupSwapInput = {
|
390
|
+
inputMint: toWeb3JsPublicKey(input.mint),
|
391
|
+
outputMint: toWeb3JsPublicKey(output.mint),
|
392
|
+
exactIn,
|
393
|
+
exactOut,
|
394
|
+
amount: exactOut ? outputAmount : inputAmount,
|
395
|
+
};
|
396
|
+
|
392
397
|
let jupQuote: QuoteResponse | undefined = undefined;
|
393
|
-
if (
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
398
|
+
if (rebalanceToZero) {
|
399
|
+
try {
|
400
|
+
jupQuote = await getJupQuote(jupSwapInput);
|
401
|
+
} catch {
|
402
|
+
let priceImpact: number = 0;
|
403
|
+
inputAmount += BigInt(Math.round(Number(inputAmount) * 0.001));
|
404
|
+
|
405
|
+
do {
|
406
|
+
const res = await getPriceImpact(
|
407
|
+
toWeb3JsPublicKey(input.mint),
|
408
|
+
toWeb3JsPublicKey(output.mint),
|
409
|
+
inputAmount + BigInt(Math.round(Number(inputAmount) * priceImpact)),
|
410
|
+
"ExactIn"
|
411
|
+
);
|
412
|
+
priceImpact = res.priceImpact;
|
413
|
+
jupQuote = res.quote;
|
414
|
+
inputAmount =
|
415
|
+
BigInt(parseInt(res.quote.inAmount)) +
|
416
|
+
BigInt(Math.round(Number(inputAmount) * 0.001));
|
417
|
+
} while (
|
418
|
+
parseInt(jupQuote.outAmount) < outputAmount &&
|
419
|
+
priceImpact > 0.001
|
402
420
|
);
|
403
|
-
|
404
|
-
jupQuote = res.quote;
|
405
|
-
inputAmount = BigInt(parseInt(res.quote.inAmount)) + BigInt(Math.round(Number(inputAmount) * 0.001));
|
406
|
-
} while (parseInt(jupQuote.outAmount) < outputAmount && priceImpact > 0.001);
|
421
|
+
}
|
407
422
|
}
|
408
423
|
|
409
424
|
const addPadding = exactOut;
|
410
425
|
|
411
426
|
return {
|
412
|
-
|
413
|
-
outputMint: toWeb3JsPublicKey(output.mint),
|
427
|
+
...jupSwapInput,
|
414
428
|
destinationWallet: flashLoanRepayFromDebt
|
415
429
|
? toWeb3JsPublicKey(client.signer.publicKey)
|
416
430
|
: client.solautoPosition,
|
417
431
|
slippageIncFactor: 0.2 + (attemptNum ?? 0) * 0.25,
|
418
|
-
amount: exactOut ? outputAmount : inputAmount,
|
419
|
-
exactIn,
|
420
|
-
exactOut,
|
421
432
|
addPadding,
|
422
433
|
jupQuote,
|
423
434
|
};
|
@@ -21,15 +21,12 @@ import {
|
|
21
21
|
} from "../../src/transactions/transactionsManager";
|
22
22
|
import { PublicKey } from "@solana/web3.js";
|
23
23
|
import {
|
24
|
-
INF,
|
25
24
|
SOLAUTO_PROD_PROGRAM,
|
26
25
|
SOLAUTO_TEST_PROGRAM,
|
27
26
|
USDC,
|
28
27
|
} from "../../src/constants";
|
29
28
|
import {
|
30
29
|
buildHeliusApiUrl,
|
31
|
-
fetchTokenPrices,
|
32
|
-
getJupPriceData,
|
33
30
|
getQnComputeUnitPriceEstimate,
|
34
31
|
getSolautoManagedPositions,
|
35
32
|
} from "../../src/utils";
|
@@ -56,23 +53,18 @@ describe("Solauto Marginfi tests", async () => {
|
|
56
53
|
const supplyDecimals = 6;
|
57
54
|
const debtDecimals = 6;
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
console.log(
|
73
|
-
JSON.stringify(await getJupPriceData([new PublicKey(INF)], true), null, 2)
|
74
|
-
);
|
75
|
-
return;
|
56
|
+
await client.initialize({
|
57
|
+
signer,
|
58
|
+
positionId,
|
59
|
+
authority: new PublicKey("He4ka5Q3N1UvZikZvykdi47xyk5PoVP2tcQL5sVp31Sz"),
|
60
|
+
// new: true,
|
61
|
+
// marginfiAccount: new PublicKey(
|
62
|
+
// ""
|
63
|
+
// ),
|
64
|
+
// marginfiGroup: new PublicKey(""),
|
65
|
+
// supplyMint: new PublicKey(""),
|
66
|
+
// debtMint: new PublicKey(USDC),
|
67
|
+
});
|
76
68
|
|
77
69
|
// console.log(
|
78
70
|
// JSON.stringify(
|