@haven-fi/solauto-sdk 1.0.59 → 1.0.60
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/transactions/transactionUtils.d.ts.map +1 -1
- package/dist/transactions/transactionUtils.js +2 -1
- package/dist/utils/solauto/generalUtils.d.ts +19 -4
- package/dist/utils/solauto/generalUtils.d.ts.map +1 -1
- package/dist/utils/solauto/generalUtils.js +68 -9
- package/dist/utils/solauto/rebalanceUtils.d.ts +3 -1
- package/dist/utils/solauto/rebalanceUtils.d.ts.map +1 -1
- package/dist/utils/solauto/rebalanceUtils.js +47 -58
- package/package.json +1 -1
- package/src/transactions/transactionUtils.ts +13 -3
- package/src/utils/solauto/generalUtils.ts +116 -17
- package/src/utils/solauto/rebalanceUtils.ts +91 -80
- package/tests/shared.ts +6 -3
- package/tests/unit/rebalanceCalculations.ts +77 -46
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactionUtils.d.ts","sourceRoot":"","sources":["../../src/transactions/transactionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAClB,GAAG,EAGJ,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAGL,OAAO,IAAI,eAAe,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,
|
|
1
|
+
{"version":3,"file":"transactionUtils.d.ts","sourceRoot":"","sources":["../../src/transactions/transactionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAClB,GAAG,EAGJ,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAGL,OAAO,IAAI,eAAe,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,aAAa,EASd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAuMzD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,EAAE,EAAE,kBAAkB,EACtB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA8G7B;AAkLD,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,CA0HA;AAED,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,eAAe,GAC5B,OAAO,CAAC,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAC,CAAC,CA8BzC"}
|
|
@@ -17,6 +17,7 @@ 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");
|
|
20
21
|
function getWSolUsage(client, solautoActions, initiatingDcaIn, cancellingDcaIn) {
|
|
21
22
|
const supplyIsWsol = client.supplyMint.equals(spl_token_1.NATIVE_MINT);
|
|
22
23
|
const debtIsWsol = client.debtMint.equals(spl_token_1.NATIVE_MINT);
|
|
@@ -328,7 +329,7 @@ async function buildSolautoRebalanceTransaction(client, targetLiqUtilizationRate
|
|
|
328
329
|
client.log("Not eligible for a rebalance");
|
|
329
330
|
return undefined;
|
|
330
331
|
}
|
|
331
|
-
const values = (0, rebalanceUtils_1.getRebalanceValues)(client, targetLiqUtilizationRateBps);
|
|
332
|
+
const values = (0, rebalanceUtils_1.getRebalanceValues)(client.solautoPositionState, client.solautoPositionSettings(), client.solautoPositionActiveDca(), client.solautoPositionData?.feeType ?? generated_1.FeeType.Small, (0, generalUtils_1.currentUnixSeconds)(), constants_1.PRICES[client.supplyMint.toString()].price, constants_1.PRICES[client.debtMint.toString()].price, targetLiqUtilizationRateBps);
|
|
332
333
|
client.log("Rebalance values: ", values);
|
|
333
334
|
const swapDetails = (0, rebalanceUtils_1.getJupSwapRebalanceDetails)(client, values, targetLiqUtilizationRateBps, attemptNum);
|
|
334
335
|
const { jupQuote, lookupTableAddresses, setupInstructions, tokenLedgerIx, swapIx, } = await (0, jupiterUtils_1.getJupSwapTransaction)(client.signer, swapDetails, attemptNum);
|
|
@@ -3,21 +3,36 @@ import { Umi } from "@metaplex-foundation/umi";
|
|
|
3
3
|
import { AutomationSettings, DCASettings, DCASettingsInpArgs, FeeType, LendingPlatform, PositionState, SolautoSettingsParameters, SolautoSettingsParametersInpArgs } from "../../generated";
|
|
4
4
|
import { RebalanceAction, SolautoPositionDetails } from "../../types/solauto";
|
|
5
5
|
export declare function nextAutomationPeriodTimestamp(automation: AutomationSettings): number;
|
|
6
|
-
export declare function eligibleForNextAutomationPeriod(automation: AutomationSettings,
|
|
6
|
+
export declare function eligibleForNextAutomationPeriod(automation: AutomationSettings, currentUnixTime: number): boolean;
|
|
7
7
|
export declare function getUpdatedValueFromAutomation(currValue: number, targetValue: number, automation: AutomationSettings, currentUnixTimestamp: number): number;
|
|
8
|
-
export declare function getAdjustedSettingsFromAutomation(settings: SolautoSettingsParameters,
|
|
8
|
+
export declare function getAdjustedSettingsFromAutomation(settings: SolautoSettingsParameters, currentUnixTime: number): SolautoSettingsParameters;
|
|
9
9
|
export declare function getSolautoFeesBps(isReferred: boolean, feeType: FeeType): {
|
|
10
10
|
solauto: number;
|
|
11
11
|
referrer: number;
|
|
12
12
|
total: number;
|
|
13
13
|
};
|
|
14
14
|
export declare function eligibleForRebalance(positionState: PositionState, positionSettings: SolautoSettingsParameters, positionDca: DCASettings, currentUnixSecs: number): RebalanceAction | undefined;
|
|
15
|
-
export declare function eligibleForRefresh(positionState: PositionState, positionSettings: SolautoSettingsParameters,
|
|
15
|
+
export declare function eligibleForRefresh(positionState: PositionState, positionSettings: SolautoSettingsParameters, currentUnixTime: number): boolean;
|
|
16
16
|
export declare function getSolautoManagedPositions(umi: Umi, authority?: PublicKey): Promise<SolautoPositionDetails[]>;
|
|
17
17
|
export declare function getAllReferralStates(umi: Umi): Promise<PublicKey[]>;
|
|
18
18
|
export declare function getReferralsByUser(umi: Umi, user: PublicKey): Promise<PublicKey[]>;
|
|
19
19
|
export declare function getAllPositionsByAuthority(umi: Umi, user: PublicKey): Promise<SolautoPositionDetails[]>;
|
|
20
|
-
|
|
20
|
+
interface GetLatestStateProps {
|
|
21
|
+
state: PositionState;
|
|
22
|
+
umi?: Umi;
|
|
23
|
+
protocolAccount?: PublicKey;
|
|
24
|
+
lendingPlatform?: LendingPlatform;
|
|
25
|
+
supplyPrice?: number;
|
|
26
|
+
debtPrice?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function positionStateWithPrices({ state, supplyPrice, debtPrice, umi, protocolAccount, lendingPlatform, }: GetLatestStateProps): Promise<PositionState | undefined>;
|
|
29
|
+
interface AssetProps {
|
|
30
|
+
amountUsedBaseUnit: bigint;
|
|
31
|
+
decimals: number;
|
|
32
|
+
price: number;
|
|
33
|
+
mint: PublicKey;
|
|
34
|
+
}
|
|
35
|
+
export declare function createFakePositionState(supply: AssetProps, debt: AssetProps, maxLtvBps: number, liqThresholdBps: number): PositionState;
|
|
21
36
|
type PositionAdjustment = {
|
|
22
37
|
type: "supply";
|
|
23
38
|
value: bigint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/solauto/generalUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"generalUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/solauto/generalUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ exports.getAllReferralStates = getAllReferralStates;
|
|
|
13
13
|
exports.getReferralsByUser = getReferralsByUser;
|
|
14
14
|
exports.getAllPositionsByAuthority = getAllPositionsByAuthority;
|
|
15
15
|
exports.positionStateWithPrices = positionStateWithPrices;
|
|
16
|
+
exports.createFakePositionState = createFakePositionState;
|
|
16
17
|
const web3_js_1 = require("@solana/web3.js");
|
|
17
18
|
const umi_1 = require("@metaplex-foundation/umi");
|
|
18
19
|
const generated_1 = require("../../generated");
|
|
@@ -33,8 +34,8 @@ function nextAutomationPeriodTimestamp(automation) {
|
|
|
33
34
|
: Number(automation.unixStartDate) +
|
|
34
35
|
automation.periodsPassed * Number(automation.intervalSeconds);
|
|
35
36
|
}
|
|
36
|
-
function eligibleForNextAutomationPeriod(automation,
|
|
37
|
-
return
|
|
37
|
+
function eligibleForNextAutomationPeriod(automation, currentUnixTime) {
|
|
38
|
+
return currentUnixTime >= nextAutomationPeriodTimestamp(automation);
|
|
38
39
|
}
|
|
39
40
|
function getUpdatedValueFromAutomation(currValue, targetValue, automation, currentUnixTimestamp) {
|
|
40
41
|
const currRateDiff = currValue - targetValue;
|
|
@@ -44,10 +45,10 @@ function getUpdatedValueFromAutomation(currValue, targetValue, automation, curre
|
|
|
44
45
|
const newValue = currValue - currRateDiff * progressPct;
|
|
45
46
|
return newValue;
|
|
46
47
|
}
|
|
47
|
-
function getAdjustedSettingsFromAutomation(settings,
|
|
48
|
+
function getAdjustedSettingsFromAutomation(settings, currentUnixTime) {
|
|
48
49
|
const boostToBps = settings.automation.targetPeriods > 0 &&
|
|
49
|
-
eligibleForNextAutomationPeriod(settings.automation,
|
|
50
|
-
? getUpdatedValueFromAutomation(settings.boostToBps, settings.targetBoostToBps, settings.automation,
|
|
50
|
+
eligibleForNextAutomationPeriod(settings.automation, currentUnixTime)
|
|
51
|
+
? getUpdatedValueFromAutomation(settings.boostToBps, settings.targetBoostToBps, settings.automation, currentUnixTime)
|
|
51
52
|
: settings.boostToBps;
|
|
52
53
|
return {
|
|
53
54
|
...settings,
|
|
@@ -88,9 +89,9 @@ function eligibleForRebalance(positionState, positionSettings, positionDca, curr
|
|
|
88
89
|
}
|
|
89
90
|
return undefined;
|
|
90
91
|
}
|
|
91
|
-
function eligibleForRefresh(positionState, positionSettings,
|
|
92
|
+
function eligibleForRefresh(positionState, positionSettings, currentUnixTime) {
|
|
92
93
|
if (positionSettings.automation.targetPeriods > 0) {
|
|
93
|
-
return eligibleForNextAutomationPeriod(positionSettings.automation,
|
|
94
|
+
return eligibleForNextAutomationPeriod(positionSettings.automation, currentUnixTime);
|
|
94
95
|
}
|
|
95
96
|
else {
|
|
96
97
|
return ((0, generalUtils_1.currentUnixSeconds)() - Number(positionState.lastUpdated) >
|
|
@@ -211,8 +212,13 @@ async function getAllPositionsByAuthority(umi, user) {
|
|
|
211
212
|
// TODO support other platforms
|
|
212
213
|
return allPositions;
|
|
213
214
|
}
|
|
214
|
-
async function positionStateWithPrices(
|
|
215
|
+
async function positionStateWithPrices({ state, supplyPrice, debtPrice, umi, protocolAccount, lendingPlatform, }) {
|
|
215
216
|
if ((0, generalUtils_1.currentUnixSeconds)() - Number(state.lastUpdated) > 60 * 60 * 24 * 7) {
|
|
217
|
+
if (umi === undefined ||
|
|
218
|
+
protocolAccount === undefined ||
|
|
219
|
+
lendingPlatform === undefined) {
|
|
220
|
+
throw new Error("Missing required parameters");
|
|
221
|
+
}
|
|
216
222
|
if (lendingPlatform === generated_1.LendingPlatform.Marginfi) {
|
|
217
223
|
return await (0, marginfiUtils_1.getMarginfiAccountPositionState)(umi, protocolAccount, (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(state.supply.mint), (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(state.debt.mint));
|
|
218
224
|
}
|
|
@@ -234,7 +240,7 @@ async function positionStateWithPrices(umi, state, protocolAccount, lendingPlatf
|
|
|
234
240
|
...state,
|
|
235
241
|
liqUtilizationRateBps: (0, numberUtils_1.getLiqUtilzationRateBps)(supplyUsd, debtUsd, state.liqThresholdBps),
|
|
236
242
|
netWorth: {
|
|
237
|
-
|
|
243
|
+
baseUnit: (0, numberUtils_1.toBaseUnit)((supplyUsd - debtUsd) / supplyPrice, state.supply.decimals),
|
|
238
244
|
baseAmountUsdValue: (0, numberUtils_1.toBaseUnit)(supplyUsd - debtUsd, constants_1.USD_DECIMALS),
|
|
239
245
|
},
|
|
240
246
|
supply: {
|
|
@@ -253,6 +259,59 @@ async function positionStateWithPrices(umi, state, protocolAccount, lendingPlatf
|
|
|
253
259
|
},
|
|
254
260
|
};
|
|
255
261
|
}
|
|
262
|
+
function createFakePositionState(supply, debt, maxLtvBps, liqThresholdBps) {
|
|
263
|
+
const supplyUsd = (0, numberUtils_1.fromBaseUnit)(supply.amountUsedBaseUnit, supply.decimals) * supply.price;
|
|
264
|
+
const debtUsd = (0, numberUtils_1.fromBaseUnit)(debt.amountUsedBaseUnit, debt.decimals) * debt.price;
|
|
265
|
+
return {
|
|
266
|
+
liqUtilizationRateBps: (0, numberUtils_1.getLiqUtilzationRateBps)(supplyUsd, debtUsd, liqThresholdBps),
|
|
267
|
+
supply: {
|
|
268
|
+
amountUsed: {
|
|
269
|
+
baseUnit: supply.amountUsedBaseUnit,
|
|
270
|
+
baseAmountUsdValue: (0, numberUtils_1.toBaseUnit)(supplyUsd, constants_1.USD_DECIMALS),
|
|
271
|
+
},
|
|
272
|
+
amountCanBeUsed: {
|
|
273
|
+
baseUnit: (0, numberUtils_1.toBaseUnit)(1000000, supply.decimals),
|
|
274
|
+
baseAmountUsdValue: BigInt(Math.round(1000000 * supply.price)),
|
|
275
|
+
},
|
|
276
|
+
baseAmountMarketPriceUsd: (0, numberUtils_1.toBaseUnit)(supply.price, constants_1.USD_DECIMALS),
|
|
277
|
+
borrowFeeBps: 0,
|
|
278
|
+
decimals: supply.decimals,
|
|
279
|
+
flashLoanFeeBps: 0,
|
|
280
|
+
mint: (0, umi_1.publicKey)(supply.mint),
|
|
281
|
+
padding1: [],
|
|
282
|
+
padding2: [],
|
|
283
|
+
padding: new Uint8Array([]),
|
|
284
|
+
},
|
|
285
|
+
debt: {
|
|
286
|
+
amountUsed: {
|
|
287
|
+
baseUnit: debt.amountUsedBaseUnit,
|
|
288
|
+
baseAmountUsdValue: (0, numberUtils_1.toBaseUnit)(debtUsd, constants_1.USD_DECIMALS),
|
|
289
|
+
},
|
|
290
|
+
amountCanBeUsed: {
|
|
291
|
+
baseUnit: (0, numberUtils_1.toBaseUnit)(1000000, debt.decimals),
|
|
292
|
+
baseAmountUsdValue: BigInt(Math.round(1000000 * debt.price)),
|
|
293
|
+
},
|
|
294
|
+
baseAmountMarketPriceUsd: (0, numberUtils_1.toBaseUnit)(debt.price, constants_1.USD_DECIMALS),
|
|
295
|
+
borrowFeeBps: 0,
|
|
296
|
+
decimals: debt.decimals,
|
|
297
|
+
flashLoanFeeBps: 0,
|
|
298
|
+
mint: (0, umi_1.publicKey)(debt.mint),
|
|
299
|
+
padding1: [],
|
|
300
|
+
padding2: [],
|
|
301
|
+
padding: new Uint8Array([]),
|
|
302
|
+
},
|
|
303
|
+
netWorth: {
|
|
304
|
+
baseUnit: (0, numberUtils_1.toBaseUnit)((supplyUsd - debtUsd) / supply.price, supply.decimals),
|
|
305
|
+
baseAmountUsdValue: (0, numberUtils_1.toBaseUnit)(supplyUsd - debtUsd, constants_1.USD_DECIMALS),
|
|
306
|
+
},
|
|
307
|
+
maxLtvBps,
|
|
308
|
+
liqThresholdBps,
|
|
309
|
+
lastUpdated: BigInt((0, generalUtils_1.currentUnixSeconds)()),
|
|
310
|
+
padding1: [],
|
|
311
|
+
padding2: [],
|
|
312
|
+
padding: [],
|
|
313
|
+
};
|
|
314
|
+
}
|
|
256
315
|
class LivePositionUpdates {
|
|
257
316
|
constructor() {
|
|
258
317
|
this.supplyAdjustment = BigInt(0);
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import { SolautoClient } from "../../clients/solautoClient";
|
|
3
|
+
import { DCASettings, FeeType, PositionState, SolautoSettingsParameters } from "../../generated";
|
|
3
4
|
import { QuoteResponse } from "@jup-ag/api";
|
|
4
5
|
import { JupSwapDetails } from "../jupiterUtils";
|
|
5
6
|
export interface RebalanceValues {
|
|
6
7
|
increasingLeverage: boolean;
|
|
7
8
|
debtAdjustmentUsd: number;
|
|
9
|
+
amountToDcaIn: number;
|
|
8
10
|
amountUsdToDcaIn: number;
|
|
9
11
|
}
|
|
10
|
-
export declare function getRebalanceValues(
|
|
12
|
+
export declare function getRebalanceValues(state: PositionState, settings: SolautoSettingsParameters | undefined, dca: DCASettings | undefined, feeType: FeeType, currentUnixTime: number, supplyPrice: number, debtPrice: number, targetLiqUtilizationRateBps?: number, limitGapBps?: number): RebalanceValues;
|
|
11
13
|
export interface FlashLoanDetails {
|
|
12
14
|
baseUnitAmount: bigint;
|
|
13
15
|
mint: PublicKey;
|
|
@@ -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;
|
|
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,OAAO,EACP,aAAa,EAEb,yBAAyB,EAC1B,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAkJjD,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,yBAAyB,GAAG,SAAS,EAC/C,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,2BAA2B,CAAC,EAAE,MAAM,EACpC,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,CAsEjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,aAAa,GACtB,gBAAgB,GAAG,SAAS,CAkE9B;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,eAAe,EACvB,2BAA2B,CAAC,EAAE,MAAM,EACpC,UAAU,CAAC,EAAE,MAAM,GAClB,cAAc,CAkChB"}
|
|
@@ -3,81 +3,72 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getRebalanceValues = getRebalanceValues;
|
|
4
4
|
exports.getFlashLoanDetails = getFlashLoanDetails;
|
|
5
5
|
exports.getJupSwapRebalanceDetails = getJupSwapRebalanceDetails;
|
|
6
|
-
const generated_1 = require("../../generated");
|
|
7
6
|
const generalUtils_1 = require("./generalUtils");
|
|
8
7
|
const umi_web3js_adapters_1 = require("@metaplex-foundation/umi-web3js-adapters");
|
|
9
8
|
const generalUtils_2 = require("../generalUtils");
|
|
10
9
|
const numberUtils_1 = require("../numberUtils");
|
|
11
10
|
const generalAccounts_1 = require("../../constants/generalAccounts");
|
|
12
11
|
const solautoConstants_1 = require("../../constants/solautoConstants");
|
|
13
|
-
function getAdditionalAmountToDcaIn(
|
|
14
|
-
const dca = client.solautoPositionActiveDca();
|
|
12
|
+
function getAdditionalAmountToDcaIn(dca) {
|
|
15
13
|
if (dca.debtToAddBaseUnit === BigInt(0)) {
|
|
16
14
|
return 0;
|
|
17
15
|
}
|
|
18
|
-
const debtBalance = Number(
|
|
19
|
-
Number(client.livePositionUpdates.debtTaBalanceAdjustment ?? 0);
|
|
16
|
+
const debtBalance = Number(dca.debtToAddBaseUnit);
|
|
20
17
|
const updatedDebtBalance = (0, generalUtils_1.getUpdatedValueFromAutomation)(debtBalance, 0, dca.automation, (0, generalUtils_2.currentUnixSeconds)());
|
|
21
18
|
return debtBalance - updatedDebtBalance;
|
|
22
19
|
}
|
|
23
|
-
function getStandardTargetLiqUtilizationRateBps(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
repayFrom * 0.015) {
|
|
34
|
-
return adjustedSettings.repayToBps;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
throw new Error("Invalid rebalance condition");
|
|
38
|
-
}
|
|
20
|
+
function getStandardTargetLiqUtilizationRateBps(state, settings) {
|
|
21
|
+
const adjustedSettings = (0, generalUtils_1.getAdjustedSettingsFromAutomation)(settings, (0, generalUtils_2.currentUnixSeconds)());
|
|
22
|
+
const repayFrom = adjustedSettings.repayToBps - adjustedSettings.repayGap;
|
|
23
|
+
const boostFrom = adjustedSettings.boostToBps + adjustedSettings.boostGap;
|
|
24
|
+
if (state.liqUtilizationRateBps < boostFrom) {
|
|
25
|
+
return adjustedSettings.boostToBps;
|
|
26
|
+
}
|
|
27
|
+
else if (state.liqUtilizationRateBps > repayFrom ||
|
|
28
|
+
repayFrom - state.liqUtilizationRateBps < repayFrom * 0.015) {
|
|
29
|
+
return adjustedSettings.repayToBps;
|
|
39
30
|
}
|
|
40
31
|
else {
|
|
41
|
-
throw new Error("
|
|
32
|
+
throw new Error("Invalid rebalance condition");
|
|
42
33
|
}
|
|
43
34
|
}
|
|
44
|
-
function targetLiqUtilizationRateBpsFromDCA(
|
|
45
|
-
const adjustedSettings = (0, generalUtils_1.getAdjustedSettingsFromAutomation)(
|
|
35
|
+
function targetLiqUtilizationRateBpsFromDCA(state, settings, dca) {
|
|
36
|
+
const adjustedSettings = (0, generalUtils_1.getAdjustedSettingsFromAutomation)(settings, (0, generalUtils_2.currentUnixSeconds)());
|
|
46
37
|
let targetRateBps = 0;
|
|
47
|
-
if (
|
|
48
|
-
targetRateBps = Math.max(
|
|
38
|
+
if (dca.debtToAddBaseUnit > BigInt(0)) {
|
|
39
|
+
targetRateBps = Math.max(state.liqUtilizationRateBps, adjustedSettings.boostToBps);
|
|
49
40
|
}
|
|
50
41
|
else {
|
|
51
42
|
targetRateBps = adjustedSettings.boostToBps;
|
|
52
43
|
}
|
|
53
44
|
return targetRateBps;
|
|
54
45
|
}
|
|
55
|
-
function isDcaRebalance(
|
|
56
|
-
if (
|
|
46
|
+
function isDcaRebalance(state, settings, dca, currentUnixTime) {
|
|
47
|
+
if (dca === undefined || dca.automation.targetPeriods === 0) {
|
|
57
48
|
return false;
|
|
58
49
|
}
|
|
59
|
-
const adjustedSettings = (0, generalUtils_1.getAdjustedSettingsFromAutomation)(
|
|
60
|
-
if (
|
|
50
|
+
const adjustedSettings = (0, generalUtils_1.getAdjustedSettingsFromAutomation)(settings, (0, generalUtils_2.currentUnixSeconds)());
|
|
51
|
+
if (state.liqUtilizationRateBps >
|
|
61
52
|
adjustedSettings.repayToBps + adjustedSettings.repayGap) {
|
|
62
53
|
return false;
|
|
63
54
|
}
|
|
64
|
-
if (
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
if (!(0, generalUtils_1.eligibleForNextAutomationPeriod)(client.solautoPositionActiveDca().automation)) {
|
|
55
|
+
if (!(0, generalUtils_1.eligibleForNextAutomationPeriod)(dca.automation, currentUnixTime)) {
|
|
68
56
|
return false;
|
|
69
57
|
}
|
|
70
58
|
return true;
|
|
71
59
|
}
|
|
72
|
-
function getTargetRateAndDcaAmount(
|
|
60
|
+
function getTargetRateAndDcaAmount(state, settings, dca, currentUnixTime, targetLiqUtilizationRateBps) {
|
|
73
61
|
if (targetLiqUtilizationRateBps !== undefined) {
|
|
74
62
|
return {
|
|
75
63
|
targetRateBps: targetLiqUtilizationRateBps,
|
|
76
64
|
};
|
|
77
65
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
if (settings === undefined) {
|
|
67
|
+
throw new Error("If rebalancing a self-managed position, settings, and DCA should be provided");
|
|
68
|
+
}
|
|
69
|
+
if (isDcaRebalance(state, settings, dca, currentUnixTime)) {
|
|
70
|
+
const amountToDcaIn = getAdditionalAmountToDcaIn(dca);
|
|
71
|
+
const targetLiqUtilizationRateBps = targetLiqUtilizationRateBpsFromDCA(state, settings, dca);
|
|
81
72
|
return {
|
|
82
73
|
targetRateBps: targetLiqUtilizationRateBps,
|
|
83
74
|
amountToDcaIn,
|
|
@@ -85,33 +76,30 @@ function getTargetRateAndDcaAmount(client, targetLiqUtilizationRateBps) {
|
|
|
85
76
|
}
|
|
86
77
|
else {
|
|
87
78
|
return {
|
|
88
|
-
targetRateBps: getStandardTargetLiqUtilizationRateBps(
|
|
79
|
+
targetRateBps: getStandardTargetLiqUtilizationRateBps(state, settings),
|
|
89
80
|
};
|
|
90
81
|
}
|
|
91
82
|
}
|
|
92
|
-
function getRebalanceValues(
|
|
93
|
-
if (
|
|
94
|
-
|
|
83
|
+
function getRebalanceValues(state, settings, dca, feeType, currentUnixTime, supplyPrice, debtPrice, targetLiqUtilizationRateBps, limitGapBps) {
|
|
84
|
+
if (state === undefined ||
|
|
85
|
+
state.lastUpdated <
|
|
95
86
|
BigInt(Math.round((0, generalUtils_2.currentUnixSeconds)() - solautoConstants_1.MIN_POSITION_STATE_FRESHNESS_SECS))) {
|
|
96
87
|
throw new Error("Requires a fresh position state to get rebalance details");
|
|
97
88
|
}
|
|
98
|
-
const { targetRateBps, amountToDcaIn } = getTargetRateAndDcaAmount(
|
|
99
|
-
const amountUsdToDcaIn = (0, numberUtils_1.fromBaseUnit)(BigInt(Math.round(amountToDcaIn ?? 0)),
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
const { targetRateBps, amountToDcaIn } = getTargetRateAndDcaAmount(state, settings, dca, currentUnixTime, targetLiqUtilizationRateBps);
|
|
90
|
+
const amountUsdToDcaIn = (0, numberUtils_1.fromBaseUnit)(BigInt(Math.round(amountToDcaIn ?? 0)), state.debt.decimals) *
|
|
91
|
+
debtPrice;
|
|
92
|
+
const increasingLeverage = amountUsdToDcaIn > 0 || state.liqUtilizationRateBps < targetRateBps;
|
|
102
93
|
let adjustmentFeeBps = 0;
|
|
103
94
|
if (increasingLeverage) {
|
|
104
|
-
adjustmentFeeBps = (0, generalUtils_1.getSolautoFeesBps)(
|
|
105
|
-
}
|
|
106
|
-
const supplyUsd = (0, numberUtils_1.fromBaseUnit)(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const inputMarketPrice = increasingLeverage
|
|
113
|
-
? solautoConstants_1.PRICES[client.debtMint.toString()].price
|
|
114
|
-
: solautoConstants_1.PRICES[client.supplyMint.toString()].price;
|
|
95
|
+
adjustmentFeeBps = (0, generalUtils_1.getSolautoFeesBps)(false, feeType).total;
|
|
96
|
+
}
|
|
97
|
+
const supplyUsd = (0, numberUtils_1.fromBaseUnit)(state.supply.amountUsed.baseAmountUsdValue, generalAccounts_1.USD_DECIMALS) +
|
|
98
|
+
amountUsdToDcaIn;
|
|
99
|
+
const debtUsd = (0, numberUtils_1.fromBaseUnit)(state.debt.amountUsed.baseAmountUsdValue, generalAccounts_1.USD_DECIMALS);
|
|
100
|
+
let debtAdjustmentUsd = (0, numberUtils_1.getDebtAdjustmentUsd)(state.liqThresholdBps, supplyUsd, debtUsd, targetRateBps, adjustmentFeeBps);
|
|
101
|
+
const input = increasingLeverage ? state.debt : state.supply;
|
|
102
|
+
const inputMarketPrice = increasingLeverage ? debtPrice : supplyPrice;
|
|
115
103
|
const limitGap = limitGapBps
|
|
116
104
|
? (0, numberUtils_1.fromBps)(limitGapBps)
|
|
117
105
|
: (0, numberUtils_1.fromBps)(solautoConstants_1.DEFAULT_LIMIT_GAP_BPS);
|
|
@@ -126,6 +114,7 @@ function getRebalanceValues(client, targetLiqUtilizationRateBps, limitGapBps) {
|
|
|
126
114
|
return {
|
|
127
115
|
increasingLeverage,
|
|
128
116
|
debtAdjustmentUsd,
|
|
117
|
+
amountToDcaIn: amountToDcaIn ?? 0,
|
|
129
118
|
amountUsdToDcaIn,
|
|
130
119
|
};
|
|
131
120
|
}
|
|
@@ -186,7 +175,7 @@ function getJupSwapRebalanceDetails(client, values, targetLiqUtilizationRateBps,
|
|
|
186
175
|
inputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(input.mint),
|
|
187
176
|
outputMint: (0, umi_web3js_adapters_1.toWeb3JsPublicKey)(output.mint),
|
|
188
177
|
destinationWallet: client.solautoPosition,
|
|
189
|
-
slippageBpsIncFactor: 0.25 + (
|
|
178
|
+
slippageBpsIncFactor: 0.25 + (attemptNum ?? 0) * 0.2,
|
|
190
179
|
amount: rebalancingToZero
|
|
191
180
|
? client.solautoPositionState.debt.amountUsed.baseUnit +
|
|
192
181
|
BigInt(Math.round(Number(client.solautoPositionState.debt.amountUsed.baseUnit) *
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
Account as SplTokenAccount,
|
|
15
15
|
} from "@solana/spl-token";
|
|
16
16
|
import {
|
|
17
|
+
FeeType,
|
|
17
18
|
LendingPlatform,
|
|
18
19
|
ReferralState,
|
|
19
20
|
SOLAUTO_PROGRAM_ID,
|
|
@@ -56,6 +57,7 @@ import {
|
|
|
56
57
|
getLendingAccountWithdrawInstructionDataSerializer,
|
|
57
58
|
MARGINFI_PROGRAM_ID,
|
|
58
59
|
} from "../marginfi-sdk";
|
|
60
|
+
import { PRICES } from "../constants";
|
|
59
61
|
|
|
60
62
|
interface wSolTokenUsage {
|
|
61
63
|
wSolTokenAccount: PublicKey;
|
|
@@ -548,7 +550,6 @@ export async function getTransactionChores(
|
|
|
548
550
|
return [choresBefore, choresAfter];
|
|
549
551
|
}
|
|
550
552
|
|
|
551
|
-
|
|
552
553
|
export async function buildSolautoRebalanceTransaction(
|
|
553
554
|
client: SolautoClient,
|
|
554
555
|
targetLiqUtilizationRateBps?: number,
|
|
@@ -570,14 +571,23 @@ export async function buildSolautoRebalanceTransaction(
|
|
|
570
571
|
client.solautoPositionData?.position.settingParams!,
|
|
571
572
|
client.livePositionUpdates.activeDca ??
|
|
572
573
|
client.solautoPositionData?.position.dca!,
|
|
573
|
-
|
|
574
|
+
currentUnixSeconds()
|
|
574
575
|
))
|
|
575
576
|
) {
|
|
576
577
|
client.log("Not eligible for a rebalance");
|
|
577
578
|
return undefined;
|
|
578
579
|
}
|
|
579
580
|
|
|
580
|
-
const values = getRebalanceValues(
|
|
581
|
+
const values = getRebalanceValues(
|
|
582
|
+
client.solautoPositionState!,
|
|
583
|
+
client.solautoPositionSettings(),
|
|
584
|
+
client.solautoPositionActiveDca(),
|
|
585
|
+
client.solautoPositionData?.feeType ?? FeeType.Small,
|
|
586
|
+
currentUnixSeconds(),
|
|
587
|
+
PRICES[client.supplyMint.toString()].price,
|
|
588
|
+
PRICES[client.debtMint.toString()].price,
|
|
589
|
+
targetLiqUtilizationRateBps
|
|
590
|
+
);
|
|
581
591
|
client.log("Rebalance values: ", values);
|
|
582
592
|
|
|
583
593
|
const swapDetails = getJupSwapRebalanceDetails(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
|
-
import { isOption, isSome, Umi } from "@metaplex-foundation/umi";
|
|
2
|
+
import { isOption, isSome, publicKey, Umi } from "@metaplex-foundation/umi";
|
|
3
3
|
import {
|
|
4
4
|
AutomationSettings,
|
|
5
5
|
DCASettings,
|
|
@@ -54,9 +54,9 @@ export function nextAutomationPeriodTimestamp(
|
|
|
54
54
|
|
|
55
55
|
export function eligibleForNextAutomationPeriod(
|
|
56
56
|
automation: AutomationSettings,
|
|
57
|
-
|
|
57
|
+
currentUnixTime: number
|
|
58
58
|
): boolean {
|
|
59
|
-
return
|
|
59
|
+
return currentUnixTime >= nextAutomationPeriodTimestamp(automation);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export function getUpdatedValueFromAutomation(
|
|
@@ -79,16 +79,16 @@ export function getUpdatedValueFromAutomation(
|
|
|
79
79
|
|
|
80
80
|
export function getAdjustedSettingsFromAutomation(
|
|
81
81
|
settings: SolautoSettingsParameters,
|
|
82
|
-
|
|
82
|
+
currentUnixTime: number
|
|
83
83
|
): SolautoSettingsParameters {
|
|
84
84
|
const boostToBps =
|
|
85
85
|
settings.automation.targetPeriods > 0 &&
|
|
86
|
-
eligibleForNextAutomationPeriod(settings.automation,
|
|
86
|
+
eligibleForNextAutomationPeriod(settings.automation, currentUnixTime)
|
|
87
87
|
? getUpdatedValueFromAutomation(
|
|
88
88
|
settings.boostToBps,
|
|
89
89
|
settings.targetBoostToBps,
|
|
90
90
|
settings.automation,
|
|
91
|
-
|
|
91
|
+
currentUnixTime
|
|
92
92
|
)
|
|
93
93
|
: settings.boostToBps;
|
|
94
94
|
|
|
@@ -161,10 +161,13 @@ export function eligibleForRebalance(
|
|
|
161
161
|
export function eligibleForRefresh(
|
|
162
162
|
positionState: PositionState,
|
|
163
163
|
positionSettings: SolautoSettingsParameters,
|
|
164
|
-
|
|
164
|
+
currentUnixTime: number
|
|
165
165
|
): boolean {
|
|
166
166
|
if (positionSettings.automation.targetPeriods > 0) {
|
|
167
|
-
return eligibleForNextAutomationPeriod(
|
|
167
|
+
return eligibleForNextAutomationPeriod(
|
|
168
|
+
positionSettings.automation,
|
|
169
|
+
currentUnixTime
|
|
170
|
+
);
|
|
168
171
|
} else {
|
|
169
172
|
return (
|
|
170
173
|
currentUnixSeconds() - Number(positionState.lastUpdated) >
|
|
@@ -322,15 +325,32 @@ export async function getAllPositionsByAuthority(
|
|
|
322
325
|
return allPositions;
|
|
323
326
|
}
|
|
324
327
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
protocolAccount
|
|
329
|
-
lendingPlatform
|
|
330
|
-
supplyPrice?: number
|
|
331
|
-
debtPrice?: number
|
|
332
|
-
|
|
328
|
+
interface GetLatestStateProps {
|
|
329
|
+
state: PositionState;
|
|
330
|
+
umi?: Umi;
|
|
331
|
+
protocolAccount?: PublicKey;
|
|
332
|
+
lendingPlatform?: LendingPlatform;
|
|
333
|
+
supplyPrice?: number;
|
|
334
|
+
debtPrice?: number;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function positionStateWithPrices({
|
|
338
|
+
state,
|
|
339
|
+
supplyPrice,
|
|
340
|
+
debtPrice,
|
|
341
|
+
umi,
|
|
342
|
+
protocolAccount,
|
|
343
|
+
lendingPlatform,
|
|
344
|
+
}: GetLatestStateProps): Promise<PositionState | undefined> {
|
|
333
345
|
if (currentUnixSeconds() - Number(state.lastUpdated) > 60 * 60 * 24 * 7) {
|
|
346
|
+
if (
|
|
347
|
+
umi === undefined ||
|
|
348
|
+
protocolAccount === undefined ||
|
|
349
|
+
lendingPlatform === undefined
|
|
350
|
+
) {
|
|
351
|
+
throw new Error("Missing required parameters");
|
|
352
|
+
}
|
|
353
|
+
|
|
334
354
|
if (lendingPlatform === LendingPlatform.Marginfi) {
|
|
335
355
|
return await getMarginfiAccountPositionState(
|
|
336
356
|
umi,
|
|
@@ -364,7 +384,10 @@ export async function positionStateWithPrices(
|
|
|
364
384
|
state.liqThresholdBps
|
|
365
385
|
),
|
|
366
386
|
netWorth: {
|
|
367
|
-
|
|
387
|
+
baseUnit: toBaseUnit(
|
|
388
|
+
(supplyUsd - debtUsd) / supplyPrice,
|
|
389
|
+
state.supply.decimals
|
|
390
|
+
),
|
|
368
391
|
baseAmountUsdValue: toBaseUnit(supplyUsd - debtUsd, USD_DECIMALS),
|
|
369
392
|
},
|
|
370
393
|
supply: {
|
|
@@ -384,6 +407,82 @@ export async function positionStateWithPrices(
|
|
|
384
407
|
};
|
|
385
408
|
}
|
|
386
409
|
|
|
410
|
+
interface AssetProps {
|
|
411
|
+
amountUsedBaseUnit: bigint;
|
|
412
|
+
decimals: number;
|
|
413
|
+
price: number;
|
|
414
|
+
mint: PublicKey;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function createFakePositionState(
|
|
418
|
+
supply: AssetProps,
|
|
419
|
+
debt: AssetProps,
|
|
420
|
+
maxLtvBps: number,
|
|
421
|
+
liqThresholdBps: number
|
|
422
|
+
): PositionState {
|
|
423
|
+
const supplyUsd =
|
|
424
|
+
fromBaseUnit(supply.amountUsedBaseUnit, supply.decimals) * supply.price;
|
|
425
|
+
const debtUsd =
|
|
426
|
+
fromBaseUnit(debt.amountUsedBaseUnit, debt.decimals) * debt.price;
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
liqUtilizationRateBps: getLiqUtilzationRateBps(
|
|
430
|
+
supplyUsd,
|
|
431
|
+
debtUsd,
|
|
432
|
+
liqThresholdBps
|
|
433
|
+
),
|
|
434
|
+
supply: {
|
|
435
|
+
amountUsed: {
|
|
436
|
+
baseUnit: supply.amountUsedBaseUnit,
|
|
437
|
+
baseAmountUsdValue: toBaseUnit(supplyUsd, USD_DECIMALS),
|
|
438
|
+
},
|
|
439
|
+
amountCanBeUsed: {
|
|
440
|
+
baseUnit: toBaseUnit(1000000, supply.decimals),
|
|
441
|
+
baseAmountUsdValue: BigInt(Math.round(1000000 * supply.price)),
|
|
442
|
+
},
|
|
443
|
+
baseAmountMarketPriceUsd: toBaseUnit(supply.price, USD_DECIMALS),
|
|
444
|
+
borrowFeeBps: 0,
|
|
445
|
+
decimals: supply.decimals,
|
|
446
|
+
flashLoanFeeBps: 0,
|
|
447
|
+
mint: publicKey(supply.mint),
|
|
448
|
+
padding1: [],
|
|
449
|
+
padding2: [],
|
|
450
|
+
padding: new Uint8Array([]),
|
|
451
|
+
},
|
|
452
|
+
debt: {
|
|
453
|
+
amountUsed: {
|
|
454
|
+
baseUnit: debt.amountUsedBaseUnit,
|
|
455
|
+
baseAmountUsdValue: toBaseUnit(debtUsd, USD_DECIMALS),
|
|
456
|
+
},
|
|
457
|
+
amountCanBeUsed: {
|
|
458
|
+
baseUnit: toBaseUnit(1000000, debt.decimals),
|
|
459
|
+
baseAmountUsdValue: BigInt(Math.round(1000000 * debt.price)),
|
|
460
|
+
},
|
|
461
|
+
baseAmountMarketPriceUsd: toBaseUnit(debt.price, USD_DECIMALS),
|
|
462
|
+
borrowFeeBps: 0,
|
|
463
|
+
decimals: debt.decimals,
|
|
464
|
+
flashLoanFeeBps: 0,
|
|
465
|
+
mint: publicKey(debt.mint),
|
|
466
|
+
padding1: [],
|
|
467
|
+
padding2: [],
|
|
468
|
+
padding: new Uint8Array([]),
|
|
469
|
+
},
|
|
470
|
+
netWorth: {
|
|
471
|
+
baseUnit: toBaseUnit(
|
|
472
|
+
(supplyUsd - debtUsd) / supply.price,
|
|
473
|
+
supply.decimals
|
|
474
|
+
),
|
|
475
|
+
baseAmountUsdValue: toBaseUnit(supplyUsd - debtUsd, USD_DECIMALS),
|
|
476
|
+
},
|
|
477
|
+
maxLtvBps,
|
|
478
|
+
liqThresholdBps,
|
|
479
|
+
lastUpdated: BigInt(currentUnixSeconds()),
|
|
480
|
+
padding1: [],
|
|
481
|
+
padding2: [],
|
|
482
|
+
padding: [],
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
387
486
|
type PositionAdjustment =
|
|
388
487
|
| { type: "supply"; value: bigint }
|
|
389
488
|
| { type: "debt"; value: bigint }
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import { SolautoClient } from "../../clients/solautoClient";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
DCASettings,
|
|
5
|
+
FeeType,
|
|
6
|
+
PositionState,
|
|
7
|
+
PositionTokenUsage,
|
|
8
|
+
SolautoSettingsParameters,
|
|
9
|
+
} from "../../generated";
|
|
4
10
|
import {
|
|
5
11
|
eligibleForNextAutomationPeriod,
|
|
6
12
|
getAdjustedSettingsFromAutomation,
|
|
@@ -26,15 +32,12 @@ import {
|
|
|
26
32
|
PRICES,
|
|
27
33
|
} from "../../constants/solautoConstants";
|
|
28
34
|
|
|
29
|
-
function getAdditionalAmountToDcaIn(
|
|
30
|
-
const dca = client.solautoPositionActiveDca()!;
|
|
35
|
+
function getAdditionalAmountToDcaIn(dca: DCASettings): number {
|
|
31
36
|
if (dca.debtToAddBaseUnit === BigInt(0)) {
|
|
32
37
|
return 0;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
const debtBalance =
|
|
36
|
-
Number(client.solautoPositionData?.position.dca.debtToAddBaseUnit ?? 0) +
|
|
37
|
-
Number(client.livePositionUpdates.debtTaBalanceAdjustment ?? 0);
|
|
40
|
+
const debtBalance = Number(dca.debtToAddBaseUnit);
|
|
38
41
|
const updatedDebtBalance = getUpdatedValueFromAutomation(
|
|
39
42
|
debtBalance,
|
|
40
43
|
0,
|
|
@@ -45,44 +48,44 @@ function getAdditionalAmountToDcaIn(client: SolautoClient): number {
|
|
|
45
48
|
return debtBalance - updatedDebtBalance;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
function getStandardTargetLiqUtilizationRateBps(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
function getStandardTargetLiqUtilizationRateBps(
|
|
52
|
+
state: PositionState,
|
|
53
|
+
settings: SolautoSettingsParameters
|
|
54
|
+
): number {
|
|
55
|
+
const adjustedSettings = getAdjustedSettingsFromAutomation(
|
|
56
|
+
settings,
|
|
57
|
+
currentUnixSeconds()
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const repayFrom = adjustedSettings.repayToBps - adjustedSettings.repayGap;
|
|
61
|
+
const boostFrom = adjustedSettings.boostToBps + adjustedSettings.boostGap;
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
repayFrom - client.solautoPositionState!.liqUtilizationRateBps <
|
|
63
|
-
repayFrom * 0.015
|
|
64
|
-
) {
|
|
65
|
-
return adjustedSettings.repayToBps;
|
|
66
|
-
} else {
|
|
67
|
-
throw new Error("Invalid rebalance condition");
|
|
68
|
-
}
|
|
63
|
+
if (state.liqUtilizationRateBps < boostFrom) {
|
|
64
|
+
return adjustedSettings.boostToBps;
|
|
65
|
+
} else if (
|
|
66
|
+
state.liqUtilizationRateBps > repayFrom ||
|
|
67
|
+
repayFrom - state.liqUtilizationRateBps < repayFrom * 0.015
|
|
68
|
+
) {
|
|
69
|
+
return adjustedSettings.repayToBps;
|
|
69
70
|
} else {
|
|
70
|
-
throw new Error(
|
|
71
|
-
"This is a self-managed position, a targetLiqUtilizationRateBps must be provided initiate a rebalance"
|
|
72
|
-
);
|
|
71
|
+
throw new Error("Invalid rebalance condition");
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
function targetLiqUtilizationRateBpsFromDCA(
|
|
75
|
+
function targetLiqUtilizationRateBpsFromDCA(
|
|
76
|
+
state: PositionState,
|
|
77
|
+
settings: SolautoSettingsParameters,
|
|
78
|
+
dca: DCASettings
|
|
79
|
+
) {
|
|
77
80
|
const adjustedSettings = getAdjustedSettingsFromAutomation(
|
|
78
|
-
|
|
81
|
+
settings,
|
|
79
82
|
currentUnixSeconds()
|
|
80
83
|
);
|
|
81
84
|
|
|
82
85
|
let targetRateBps = 0;
|
|
83
|
-
if (
|
|
86
|
+
if (dca.debtToAddBaseUnit > BigInt(0)) {
|
|
84
87
|
targetRateBps = Math.max(
|
|
85
|
-
|
|
88
|
+
state.liqUtilizationRateBps,
|
|
86
89
|
adjustedSettings.boostToBps
|
|
87
90
|
);
|
|
88
91
|
} else {
|
|
@@ -91,32 +94,29 @@ function targetLiqUtilizationRateBpsFromDCA(client: SolautoClient) {
|
|
|
91
94
|
return targetRateBps;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
function isDcaRebalance(
|
|
95
|
-
|
|
97
|
+
function isDcaRebalance(
|
|
98
|
+
state: PositionState,
|
|
99
|
+
settings: SolautoSettingsParameters,
|
|
100
|
+
dca: DCASettings | undefined,
|
|
101
|
+
currentUnixTime: number
|
|
102
|
+
): boolean {
|
|
103
|
+
if (dca === undefined || dca.automation.targetPeriods === 0) {
|
|
96
104
|
return false;
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
const adjustedSettings = getAdjustedSettingsFromAutomation(
|
|
100
|
-
|
|
108
|
+
settings,
|
|
101
109
|
currentUnixSeconds()
|
|
102
110
|
);
|
|
103
111
|
|
|
104
112
|
if (
|
|
105
|
-
|
|
113
|
+
state.liqUtilizationRateBps >
|
|
106
114
|
adjustedSettings.repayToBps + adjustedSettings.repayGap
|
|
107
115
|
) {
|
|
108
116
|
return false;
|
|
109
117
|
}
|
|
110
118
|
|
|
111
|
-
if (
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
!eligibleForNextAutomationPeriod(
|
|
117
|
-
client.solautoPositionActiveDca()!.automation
|
|
118
|
-
)
|
|
119
|
-
) {
|
|
119
|
+
if (!eligibleForNextAutomationPeriod(dca.automation, currentUnixTime)) {
|
|
120
120
|
return false;
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -124,7 +124,10 @@ function isDcaRebalance(client: SolautoClient): boolean {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
function getTargetRateAndDcaAmount(
|
|
127
|
-
|
|
127
|
+
state: PositionState,
|
|
128
|
+
settings: SolautoSettingsParameters | undefined,
|
|
129
|
+
dca: DCASettings | undefined,
|
|
130
|
+
currentUnixTime: number,
|
|
128
131
|
targetLiqUtilizationRateBps?: number
|
|
129
132
|
): { targetRateBps: number; amountToDcaIn?: number } {
|
|
130
133
|
if (targetLiqUtilizationRateBps !== undefined) {
|
|
@@ -133,10 +136,19 @@ function getTargetRateAndDcaAmount(
|
|
|
133
136
|
};
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
if (settings === undefined) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
"If rebalancing a self-managed position, settings, and DCA should be provided"
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (isDcaRebalance(state, settings, dca, currentUnixTime)) {
|
|
146
|
+
const amountToDcaIn = getAdditionalAmountToDcaIn(dca!);
|
|
147
|
+
const targetLiqUtilizationRateBps = targetLiqUtilizationRateBpsFromDCA(
|
|
148
|
+
state,
|
|
149
|
+
settings,
|
|
150
|
+
dca!
|
|
151
|
+
);
|
|
140
152
|
|
|
141
153
|
return {
|
|
142
154
|
targetRateBps: targetLiqUtilizationRateBps,
|
|
@@ -144,7 +156,7 @@ function getTargetRateAndDcaAmount(
|
|
|
144
156
|
};
|
|
145
157
|
} else {
|
|
146
158
|
return {
|
|
147
|
-
targetRateBps: getStandardTargetLiqUtilizationRateBps(
|
|
159
|
+
targetRateBps: getStandardTargetLiqUtilizationRateBps(state, settings),
|
|
148
160
|
};
|
|
149
161
|
}
|
|
150
162
|
}
|
|
@@ -152,17 +164,24 @@ function getTargetRateAndDcaAmount(
|
|
|
152
164
|
export interface RebalanceValues {
|
|
153
165
|
increasingLeverage: boolean;
|
|
154
166
|
debtAdjustmentUsd: number;
|
|
167
|
+
amountToDcaIn: number;
|
|
155
168
|
amountUsdToDcaIn: number;
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
export function getRebalanceValues(
|
|
159
|
-
|
|
172
|
+
state: PositionState,
|
|
173
|
+
settings: SolautoSettingsParameters | undefined,
|
|
174
|
+
dca: DCASettings | undefined,
|
|
175
|
+
feeType: FeeType,
|
|
176
|
+
currentUnixTime: number,
|
|
177
|
+
supplyPrice: number,
|
|
178
|
+
debtPrice: number,
|
|
160
179
|
targetLiqUtilizationRateBps?: number,
|
|
161
180
|
limitGapBps?: number
|
|
162
181
|
): RebalanceValues {
|
|
163
182
|
if (
|
|
164
|
-
|
|
165
|
-
|
|
183
|
+
state === undefined ||
|
|
184
|
+
state.lastUpdated <
|
|
166
185
|
BigInt(
|
|
167
186
|
Math.round(currentUnixSeconds() - MIN_POSITION_STATE_FRESHNESS_SECS)
|
|
168
187
|
)
|
|
@@ -171,50 +190,41 @@ export function getRebalanceValues(
|
|
|
171
190
|
}
|
|
172
191
|
|
|
173
192
|
const { targetRateBps, amountToDcaIn } = getTargetRateAndDcaAmount(
|
|
174
|
-
|
|
193
|
+
state,
|
|
194
|
+
settings,
|
|
195
|
+
dca,
|
|
196
|
+
currentUnixTime,
|
|
175
197
|
targetLiqUtilizationRateBps
|
|
176
198
|
);
|
|
177
199
|
|
|
178
200
|
const amountUsdToDcaIn =
|
|
179
|
-
fromBaseUnit(
|
|
180
|
-
|
|
181
|
-
client.solautoPositionState!.debt.decimals
|
|
182
|
-
) * PRICES[client.debtMint.toString()].price;
|
|
201
|
+
fromBaseUnit(BigInt(Math.round(amountToDcaIn ?? 0)), state.debt.decimals) *
|
|
202
|
+
debtPrice;
|
|
183
203
|
|
|
184
204
|
const increasingLeverage =
|
|
185
|
-
amountUsdToDcaIn > 0 ||
|
|
186
|
-
client.solautoPositionState!.liqUtilizationRateBps < targetRateBps;
|
|
205
|
+
amountUsdToDcaIn > 0 || state.liqUtilizationRateBps < targetRateBps;
|
|
187
206
|
let adjustmentFeeBps = 0;
|
|
188
207
|
if (increasingLeverage) {
|
|
189
|
-
adjustmentFeeBps = getSolautoFeesBps(
|
|
190
|
-
client.referredByState !== undefined,
|
|
191
|
-
client.solautoPositionData?.feeType ?? FeeType.Small
|
|
192
|
-
).total;
|
|
208
|
+
adjustmentFeeBps = getSolautoFeesBps(false, feeType).total;
|
|
193
209
|
}
|
|
194
210
|
|
|
195
211
|
const supplyUsd =
|
|
196
|
-
fromBaseUnit(
|
|
197
|
-
|
|
198
|
-
USD_DECIMALS
|
|
199
|
-
) + amountUsdToDcaIn;
|
|
212
|
+
fromBaseUnit(state.supply.amountUsed.baseAmountUsdValue, USD_DECIMALS) +
|
|
213
|
+
amountUsdToDcaIn;
|
|
200
214
|
const debtUsd = fromBaseUnit(
|
|
201
|
-
|
|
215
|
+
state.debt.amountUsed.baseAmountUsdValue,
|
|
202
216
|
USD_DECIMALS
|
|
203
217
|
);
|
|
204
218
|
let debtAdjustmentUsd = getDebtAdjustmentUsd(
|
|
205
|
-
|
|
219
|
+
state.liqThresholdBps,
|
|
206
220
|
supplyUsd,
|
|
207
221
|
debtUsd,
|
|
208
222
|
targetRateBps,
|
|
209
223
|
adjustmentFeeBps
|
|
210
224
|
);
|
|
211
225
|
|
|
212
|
-
const input = increasingLeverage
|
|
213
|
-
|
|
214
|
-
: client.solautoPositionState!.supply;
|
|
215
|
-
const inputMarketPrice = increasingLeverage
|
|
216
|
-
? PRICES[client.debtMint.toString()].price
|
|
217
|
-
: PRICES[client.supplyMint.toString()].price;
|
|
226
|
+
const input = increasingLeverage ? state.debt : state.supply;
|
|
227
|
+
const inputMarketPrice = increasingLeverage ? debtPrice : supplyPrice;
|
|
218
228
|
|
|
219
229
|
const limitGap = limitGapBps
|
|
220
230
|
? fromBps(limitGapBps)
|
|
@@ -235,6 +245,7 @@ export function getRebalanceValues(
|
|
|
235
245
|
return {
|
|
236
246
|
increasingLeverage,
|
|
237
247
|
debtAdjustmentUsd,
|
|
248
|
+
amountToDcaIn: amountToDcaIn ?? 0,
|
|
238
249
|
amountUsdToDcaIn,
|
|
239
250
|
};
|
|
240
251
|
}
|
|
@@ -269,7 +280,7 @@ export function getFlashLoanDetails(
|
|
|
269
280
|
values.debtAdjustmentUsd > 0
|
|
270
281
|
? debtUsd + debtAdjustmentWithSlippage
|
|
271
282
|
: debtUsd;
|
|
272
|
-
|
|
283
|
+
|
|
273
284
|
const tempLiqUtilizationRateBps = getLiqUtilzationRateBps(
|
|
274
285
|
supplyUsd,
|
|
275
286
|
debtUsd,
|
|
@@ -342,7 +353,7 @@ export function getJupSwapRebalanceDetails(
|
|
|
342
353
|
inputMint: toWeb3JsPublicKey(input.mint),
|
|
343
354
|
outputMint: toWeb3JsPublicKey(output.mint),
|
|
344
355
|
destinationWallet: client.solautoPosition,
|
|
345
|
-
slippageBpsIncFactor: 0.25 + (
|
|
356
|
+
slippageBpsIncFactor: 0.25 + (attemptNum ?? 0) * 0.2,
|
|
346
357
|
amount: rebalancingToZero
|
|
347
358
|
? client.solautoPositionState!.debt.amountUsed.baseUnit +
|
|
348
359
|
BigInt(
|
package/tests/shared.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Signer, createSignerFromKeypair } from "@metaplex-foundation/umi";
|
|
2
|
-
import { Connection, clusterApiUrl } from "@solana/web3.js";
|
|
2
|
+
import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
|
|
3
3
|
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
|
4
4
|
import { getSecretKey } from "../local/shared";
|
|
5
|
+
import { fromWeb3JsKeypair } from "@metaplex-foundation/umi-web3js-adapters";
|
|
5
6
|
|
|
6
|
-
export function setupTest(keypairFilename?: string): Signer {
|
|
7
|
+
export function setupTest(keypairFilename?: string, random?: boolean): Signer {
|
|
7
8
|
const umi = createUmi(
|
|
8
9
|
new Connection(clusterApiUrl("mainnet-beta"), "confirmed")
|
|
9
10
|
);
|
|
10
11
|
const secretKey = getSecretKey(keypairFilename);
|
|
11
|
-
const signerKeypair =
|
|
12
|
+
const signerKeypair = random
|
|
13
|
+
? fromWeb3JsKeypair(Keypair.generate())
|
|
14
|
+
: umi.eddsa.createKeypairFromSecretKey(secretKey);
|
|
12
15
|
const signer = createSignerFromKeypair(umi, signerKeypair);
|
|
13
16
|
|
|
14
17
|
return signer;
|
|
@@ -4,7 +4,6 @@ import { NATIVE_MINT } from "@solana/spl-token";
|
|
|
4
4
|
import { assert } from "chai";
|
|
5
5
|
import { SolautoMarginfiClient } from "../../src/clients/solautoMarginfiClient";
|
|
6
6
|
import { setupTest } from "../shared";
|
|
7
|
-
import { MARGINFI_ACCOUNTS } from "../../src/constants/marginfiAccounts";
|
|
8
7
|
import { getRebalanceValues } from "../../src/utils/solauto/rebalanceUtils";
|
|
9
8
|
import { publicKey } from "@metaplex-foundation/umi";
|
|
10
9
|
import { SolautoClient } from "../../src/clients/solautoClient";
|
|
@@ -23,18 +22,21 @@ import {
|
|
|
23
22
|
} from "../../src/utils/numberUtils";
|
|
24
23
|
import { USD_DECIMALS } from "../../src/constants/generalAccounts";
|
|
25
24
|
import {
|
|
25
|
+
createFakePositionState,
|
|
26
26
|
eligibleForNextAutomationPeriod,
|
|
27
27
|
getAdjustedSettingsFromAutomation,
|
|
28
28
|
getSolautoFeesBps,
|
|
29
29
|
getUpdatedValueFromAutomation,
|
|
30
|
+
positionStateWithPrices,
|
|
30
31
|
} from "../../src/utils/solauto/generalUtils";
|
|
31
32
|
import {
|
|
32
33
|
currentUnixSeconds,
|
|
33
34
|
getTokenPrices,
|
|
34
35
|
} from "../../src/utils/generalUtils";
|
|
35
36
|
import { USDC_MINT } from "../../src/constants/tokenConstants";
|
|
37
|
+
import { PRICES } from "../../src/constants";
|
|
36
38
|
|
|
37
|
-
const signer = setupTest();
|
|
39
|
+
const signer = setupTest(undefined, true);
|
|
38
40
|
|
|
39
41
|
function assertAccurateRebalance(
|
|
40
42
|
client: SolautoClient,
|
|
@@ -43,7 +45,16 @@ function assertAccurateRebalance(
|
|
|
43
45
|
expectedUsdToDcaIn?: number
|
|
44
46
|
) {
|
|
45
47
|
const { increasingLeverage, debtAdjustmentUsd, amountUsdToDcaIn } =
|
|
46
|
-
getRebalanceValues(
|
|
48
|
+
getRebalanceValues(
|
|
49
|
+
client.solautoPositionState!,
|
|
50
|
+
client.solautoPositionSettings(),
|
|
51
|
+
client.solautoPositionActiveDca(),
|
|
52
|
+
client.solautoPositionData?.feeType ?? FeeType.Small,
|
|
53
|
+
currentUnixSeconds(),
|
|
54
|
+
PRICES[client.supplyMint.toString()].price,
|
|
55
|
+
PRICES[client.debtMint.toString()].price,
|
|
56
|
+
targetLiqUtilizationRateBps
|
|
57
|
+
);
|
|
47
58
|
|
|
48
59
|
let adjustmentFeeBps = 0;
|
|
49
60
|
if (increasingLeverage) {
|
|
@@ -55,7 +66,9 @@ function assertAccurateRebalance(
|
|
|
55
66
|
|
|
56
67
|
assert(
|
|
57
68
|
Math.round(amountUsdToDcaIn) === Math.round(expectedUsdToDcaIn ?? 0),
|
|
58
|
-
`Expected DCA-in amount does not match ${Math.round(
|
|
69
|
+
`Expected DCA-in amount does not match ${Math.round(
|
|
70
|
+
amountUsdToDcaIn
|
|
71
|
+
)}, ${Math.round(expectedUsdToDcaIn ?? 0)}`
|
|
59
72
|
);
|
|
60
73
|
|
|
61
74
|
const newSupply =
|
|
@@ -77,8 +90,9 @@ function assertAccurateRebalance(
|
|
|
77
90
|
client.solautoPositionState!.liqThresholdBps
|
|
78
91
|
);
|
|
79
92
|
assert(
|
|
80
|
-
Math.round(newLiqUtilizationRateBps) ===
|
|
81
|
-
|
|
93
|
+
Math.round(newLiqUtilizationRateBps) ===
|
|
94
|
+
Math.round(expectedLiqUtilizationRateBps),
|
|
95
|
+
`Expected liq utilization rate does not match ${newLiqUtilizationRateBps}, ${expectedLiqUtilizationRateBps}`
|
|
82
96
|
);
|
|
83
97
|
}
|
|
84
98
|
|
|
@@ -97,10 +111,37 @@ async function getFakePosition(
|
|
|
97
111
|
positionId: 1,
|
|
98
112
|
signer,
|
|
99
113
|
supplyMint: new PublicKey(NATIVE_MINT),
|
|
100
|
-
debtMint: new PublicKey(
|
|
114
|
+
debtMint: new PublicKey(USDC_MINT),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const supplyUsd = 1000;
|
|
118
|
+
const maxLtvBps = 6400;
|
|
119
|
+
const liqThresholdBps = 8181;
|
|
120
|
+
client.solautoPositionState = await positionStateWithPrices({
|
|
121
|
+
state: createFakePositionState(
|
|
122
|
+
{
|
|
123
|
+
amountUsedBaseUnit: toBaseUnit(supplyUsd / supplyPrice, 9),
|
|
124
|
+
decimals: 9,
|
|
125
|
+
price: PRICES[NATIVE_MINT.toString()].price,
|
|
126
|
+
mint: NATIVE_MINT,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
amountUsedBaseUnit: toBaseUnit(
|
|
130
|
+
(supplyUsd *
|
|
131
|
+
fromBps(liqThresholdBps) *
|
|
132
|
+
fromBps(fakeLiqUtilizationRateBps)) /
|
|
133
|
+
debtPrice,
|
|
134
|
+
6
|
|
135
|
+
),
|
|
136
|
+
decimals: 6,
|
|
137
|
+
price: 1,
|
|
138
|
+
mint: new PublicKey(USDC_MINT),
|
|
139
|
+
},
|
|
140
|
+
maxLtvBps,
|
|
141
|
+
liqThresholdBps
|
|
142
|
+
),
|
|
101
143
|
});
|
|
102
144
|
|
|
103
|
-
const state = await client.getFreshPositionState();
|
|
104
145
|
client.solautoPositionData = {
|
|
105
146
|
positionId: [1],
|
|
106
147
|
bump: [0],
|
|
@@ -129,7 +170,7 @@ async function getFakePosition(
|
|
|
129
170
|
padding1: [],
|
|
130
171
|
padding: [],
|
|
131
172
|
},
|
|
132
|
-
state:
|
|
173
|
+
state: client.solautoPositionState!,
|
|
133
174
|
rebalance: {
|
|
134
175
|
rebalanceType: SolautoRebalanceType.Regular,
|
|
135
176
|
targetLiqUtilizationRateBps: 0,
|
|
@@ -139,7 +180,7 @@ async function getFakePosition(
|
|
|
139
180
|
padding2: [],
|
|
140
181
|
padding: new Uint8Array([]),
|
|
141
182
|
},
|
|
142
|
-
feeType: FeeType.
|
|
183
|
+
feeType: FeeType.Default,
|
|
143
184
|
padding1: [],
|
|
144
185
|
padding2: [],
|
|
145
186
|
padding: [],
|
|
@@ -155,25 +196,14 @@ async function getFakePosition(
|
|
|
155
196
|
},
|
|
156
197
|
};
|
|
157
198
|
|
|
158
|
-
const supplyUsd = 1000;
|
|
159
|
-
client.livePositionUpdates.new({
|
|
160
|
-
type: "supply",
|
|
161
|
-
value: toBaseUnit(supplyUsd / supplyPrice, state!.supply.decimals),
|
|
162
|
-
});
|
|
163
|
-
client.livePositionUpdates.new({
|
|
164
|
-
type: "debt",
|
|
165
|
-
value: toBaseUnit(
|
|
166
|
-
(supplyUsd *
|
|
167
|
-
fromBps(state!.liqThresholdBps) *
|
|
168
|
-
fromBps(fakeLiqUtilizationRateBps)) /
|
|
169
|
-
debtPrice,
|
|
170
|
-
state!.debt.decimals
|
|
171
|
-
),
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
client.solautoPositionState = await client.getFreshPositionState();
|
|
175
199
|
client.solautoPositionState!.lastUpdated = BigInt(currentUnixSeconds());
|
|
176
200
|
|
|
201
|
+
assert(
|
|
202
|
+
fakeLiqUtilizationRateBps ===
|
|
203
|
+
client.solautoPositionState!.liqUtilizationRateBps,
|
|
204
|
+
"Fake position not set up correctly"
|
|
205
|
+
);
|
|
206
|
+
|
|
177
207
|
return client;
|
|
178
208
|
}
|
|
179
209
|
|
|
@@ -227,7 +257,8 @@ async function dcaRebalanceFromFakePosition(
|
|
|
227
257
|
: adjustedSettings.boostToBps;
|
|
228
258
|
|
|
229
259
|
const expectedDcaInAmount =
|
|
230
|
-
dca.debtToAddBaseUnit > 0 &&
|
|
260
|
+
dca.debtToAddBaseUnit > 0 &&
|
|
261
|
+
eligibleForNextAutomationPeriod(dca.automation, currentUnixSeconds())
|
|
231
262
|
? dca.debtToAddBaseUnit -
|
|
232
263
|
BigInt(
|
|
233
264
|
Math.round(
|
|
@@ -265,23 +296,23 @@ describe("Rebalance tests", async () => {
|
|
|
265
296
|
});
|
|
266
297
|
|
|
267
298
|
it("Standard rebalance with target rate", async () => {
|
|
268
|
-
const client =
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
299
|
+
const client = await getFakePosition(supplyPrice, debtPrice, 3450, {
|
|
300
|
+
boostToBps: 500,
|
|
301
|
+
boostGap: 100,
|
|
302
|
+
repayToBps: 7000,
|
|
303
|
+
repayGap: 250,
|
|
304
|
+
automation: {
|
|
305
|
+
targetPeriods: 0,
|
|
306
|
+
periodsPassed: 0,
|
|
307
|
+
unixStartDate: BigInt(0),
|
|
308
|
+
intervalSeconds: BigInt(0),
|
|
309
|
+
padding1: [],
|
|
310
|
+
padding: new Uint8Array([]),
|
|
311
|
+
},
|
|
312
|
+
targetBoostToBps: 0,
|
|
313
|
+
padding1: [],
|
|
314
|
+
padding: new Uint8Array([]),
|
|
282
315
|
});
|
|
283
|
-
client.solautoPositionState = await client.getFreshPositionState();
|
|
284
|
-
client.solautoPositionState!.lastUpdated = BigInt(currentUnixSeconds());
|
|
285
316
|
|
|
286
317
|
assertAccurateRebalance(client, 5000, 5000);
|
|
287
318
|
assertAccurateRebalance(client, 1000, 1000);
|
|
@@ -393,14 +424,14 @@ describe("Rebalance tests", async () => {
|
|
|
393
424
|
it("Rebalance DCA in", async () => {
|
|
394
425
|
const settings: SolautoSettingsParameters = {
|
|
395
426
|
automation: {
|
|
396
|
-
targetPeriods:
|
|
427
|
+
targetPeriods: 3,
|
|
397
428
|
periodsPassed: 0,
|
|
398
429
|
intervalSeconds: BigInt(5),
|
|
399
430
|
unixStartDate: BigInt(currentUnixSeconds()),
|
|
400
431
|
padding1: [],
|
|
401
432
|
padding: new Uint8Array([]),
|
|
402
433
|
},
|
|
403
|
-
targetBoostToBps:
|
|
434
|
+
targetBoostToBps: 5000,
|
|
404
435
|
boostGap: 1000,
|
|
405
436
|
boostToBps: 4000,
|
|
406
437
|
repayGap: 1000,
|