@suilend/sdk 1.1.92 → 1.1.93
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/client.js +5 -1
- package/lib/initialize.d.ts +1 -1
- package/lib/initialize.js +16 -8
- package/lib/pyth.d.ts +12 -0
- package/lib/pyth.js +53 -0
- package/lib/strategyOwnerCap.d.ts +4 -1
- package/lib/strategyOwnerCap.js +109 -44
- package/package.json +1 -1
- package/strategies.d.ts +6 -1
- package/strategies.js +240 -16
package/client.js
CHANGED
|
@@ -24,6 +24,7 @@ const functions_2 = require("./_generated/suilend/lending-market-registry/functi
|
|
|
24
24
|
const structs_3 = require("./_generated/suilend/obligation/structs");
|
|
25
25
|
const functions_3 = require("./_generated/suilend/rate-limiter/functions");
|
|
26
26
|
const functions_4 = require("./_generated/suilend/reserve-config/functions");
|
|
27
|
+
const pyth_1 = require("./lib/pyth");
|
|
27
28
|
const types_1 = require("./lib/types");
|
|
28
29
|
const SUI_COINTYPE = "0x2::sui::SUI";
|
|
29
30
|
const NORMALIZED_SUI_COINTYPE = (0, utils_1.normalizeStructTag)(SUI_COINTYPE);
|
|
@@ -74,7 +75,10 @@ class SuilendClient {
|
|
|
74
75
|
this.lendingMarket = lendingMarket;
|
|
75
76
|
this.client = client;
|
|
76
77
|
this.pythClient = new pyth_sui_js_1.SuiPythClient(client, PYTH_STATE_ID, WORMHOLE_STATE_ID);
|
|
77
|
-
|
|
78
|
+
const pythEndpoint = pyth_1.PRIMARY_PYTH_ENDPOINT; // TODO: Use getWorkingPythEndpoint
|
|
79
|
+
this.pythConnection = new pyth_sui_js_1.SuiPriceServiceConnection(pythEndpoint, {
|
|
80
|
+
timeout: 30 * 1000,
|
|
81
|
+
});
|
|
78
82
|
}
|
|
79
83
|
static initialize(lendingMarketId, lendingMarketType, client, logPackageId) {
|
|
80
84
|
return __awaiter(this, void 0, void 0, function* () {
|
package/lib/initialize.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare const RESERVES_CUSTOM_ORDER: Record<string, string[]>;
|
|
|
8
8
|
export declare const NORMALIZED_MAYA_COINTYPE: string;
|
|
9
9
|
export declare const NORMALIZED_mPOINTS_COINTYPE: string;
|
|
10
10
|
export declare const NORMALIZED_TREATS_COINTYPE: string;
|
|
11
|
-
export declare const initializeSuilend: (suiClient: SuiClient, suilendClient: SuilendClient, lendingMarketMetadata?: LendingMarketMetadata) => Promise<{
|
|
11
|
+
export declare const initializeSuilend: (suiClient: SuiClient, suilendClient: SuilendClient, lendingMarketMetadata?: LendingMarketMetadata, fallbackPythEndpoint?: string) => Promise<{
|
|
12
12
|
lendingMarket: {
|
|
13
13
|
version: bigint;
|
|
14
14
|
reserves: {
|
package/lib/initialize.js
CHANGED
|
@@ -54,6 +54,7 @@ const client_1 = require("../client");
|
|
|
54
54
|
const parsers_1 = require("../parsers");
|
|
55
55
|
const simulate = __importStar(require("../utils/simulate"));
|
|
56
56
|
const constants_1 = require("./constants");
|
|
57
|
+
const pyth_1 = require("./pyth");
|
|
57
58
|
const strategyOwnerCap_1 = require("./strategyOwnerCap");
|
|
58
59
|
exports.RESERVES_CUSTOM_ORDER = {
|
|
59
60
|
[client_1.LENDING_MARKET_ID]: [
|
|
@@ -101,14 +102,18 @@ exports.RESERVES_CUSTOM_ORDER = {
|
|
|
101
102
|
sui_fe_1.NORMALIZED_HIPPO_COINTYPE,
|
|
102
103
|
sui_fe_1.NORMALIZED_FUD_COINTYPE,
|
|
103
104
|
],
|
|
104
|
-
"0x0d3a7f758d19d11e8526f66cca43403a99da16862c570c43efe0f8c4a500f7f2": [
|
|
105
|
-
sui_fe_1.NORMALIZED_sdeUSD_COINTYPE,
|
|
106
|
-
sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
107
|
-
],
|
|
108
105
|
"0x8a8d8e138a28de1c637d0b0955e621b017da7010de388db5a18493eca99c5e82": [
|
|
109
106
|
sui_fe_1.NORMALIZED_XAUm_COINTYPE,
|
|
110
107
|
sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
111
108
|
],
|
|
109
|
+
"0xc1549fd5db74c3aad37a260c9fd251d93d6f2f3ccfacc277398a57718c275a17": [
|
|
110
|
+
sui_fe_1.NORMALIZED_SEND_COINTYPE,
|
|
111
|
+
sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
112
|
+
],
|
|
113
|
+
"0x0d3a7f758d19d11e8526f66cca43403a99da16862c570c43efe0f8c4a500f7f2": [
|
|
114
|
+
sui_fe_1.NORMALIZED_sdeUSD_COINTYPE,
|
|
115
|
+
sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
116
|
+
],
|
|
112
117
|
};
|
|
113
118
|
const MAYA_COINTYPE = "0x3bf0aeb7b9698b18ec7937290a5701088fcd5d43ad11a2564b074d022a6d71ec::maya::MAYA";
|
|
114
119
|
const mPOINTS_COINTYPE = "0x7bae0b3b7b6c3da899fe3f4af95b7110633499c02b8c6945110d799d99deaa68::mpoints::MPOINTS";
|
|
@@ -116,7 +121,7 @@ const TREATS_COINTYPE = "0x0dadb7fa2771c2952f96161fc1f0c105d1f22d53926b9ff2498a8
|
|
|
116
121
|
exports.NORMALIZED_MAYA_COINTYPE = (0, utils_1.normalizeStructTag)(MAYA_COINTYPE);
|
|
117
122
|
exports.NORMALIZED_mPOINTS_COINTYPE = (0, utils_1.normalizeStructTag)(mPOINTS_COINTYPE);
|
|
118
123
|
exports.NORMALIZED_TREATS_COINTYPE = (0, utils_1.normalizeStructTag)(TREATS_COINTYPE);
|
|
119
|
-
const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata) => __awaiter(void 0, void 0, void 0, function* () {
|
|
124
|
+
const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata, fallbackPythEndpoint) => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
125
|
const nowMs = Date.now();
|
|
121
126
|
const nowS = Math.floor(nowMs / 1000);
|
|
122
127
|
const interestCompoundedRawReserves = suilendClient.lendingMarket.reserves.map((r) => simulate.compoundReserveInterest(r, nowS));
|
|
@@ -131,10 +136,13 @@ const initializeSuilend = (suiClient, suilendClient, lendingMarketMetadata) => _
|
|
|
131
136
|
reservesWithoutTemporaryPythPriceFeeds.push(reserve);
|
|
132
137
|
}
|
|
133
138
|
}
|
|
139
|
+
// Get a working Pyth endpoint (try primary, fallback to fallbackPythEndpoint if provided)
|
|
140
|
+
const pythEndpoint = yield (0, pyth_1.getWorkingPythEndpoint)(fallbackPythEndpoint);
|
|
141
|
+
const pythConnection = new pyth_sui_js_1.SuiPriceServiceConnection(pythEndpoint, {
|
|
142
|
+
timeout: 30 * 1000,
|
|
143
|
+
});
|
|
134
144
|
const [refreshedReservesWithoutTemporaryPythPriceFeeds] = yield Promise.all([
|
|
135
|
-
simulate.refreshReservePrice(reservesWithoutTemporaryPythPriceFeeds,
|
|
136
|
-
timeout: 30 * 1000,
|
|
137
|
-
})),
|
|
145
|
+
simulate.refreshReservePrice(reservesWithoutTemporaryPythPriceFeeds, pythConnection),
|
|
138
146
|
Promise.all(reservesWithTemporaryPythPriceFeeds.map((reserve) => (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
147
|
let cachedUsdPrice;
|
|
140
148
|
try {
|
package/lib/pyth.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const PRIMARY_PYTH_ENDPOINT = "https://hermes.pyth.network";
|
|
2
|
+
/**
|
|
3
|
+
* Tests if the primary Pyth connection endpoint is working by checking the /live endpoint
|
|
4
|
+
* @returns true if the connection is working, false otherwise
|
|
5
|
+
*/
|
|
6
|
+
export declare const testPrimaryPythConnection: () => Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Gets a working Pyth connection endpoint, trying primary first, then fallback if provided
|
|
9
|
+
* @param fallbackPythEndpoint Optional fallback endpoint
|
|
10
|
+
* @returns The endpoint URL that is working, or the primary endpoint if fallback fails
|
|
11
|
+
*/
|
|
12
|
+
export declare const getWorkingPythEndpoint: (fallbackPythEndpoint?: string) => Promise<string>;
|
package/lib/pyth.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getWorkingPythEndpoint = exports.testPrimaryPythConnection = exports.PRIMARY_PYTH_ENDPOINT = void 0;
|
|
13
|
+
exports.PRIMARY_PYTH_ENDPOINT = "https://hermes.pyth.network";
|
|
14
|
+
/**
|
|
15
|
+
* Tests if the primary Pyth connection endpoint is working by checking the /live endpoint
|
|
16
|
+
* @returns true if the connection is working, false otherwise
|
|
17
|
+
*/
|
|
18
|
+
const testPrimaryPythConnection = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
try {
|
|
20
|
+
const res = yield fetch(`${exports.PRIMARY_PYTH_ENDPOINT}/live`, {
|
|
21
|
+
signal: AbortSignal.timeout(5 * 1000), // 5 second timeout
|
|
22
|
+
});
|
|
23
|
+
return res.ok;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.warn(`[testPrimaryPythConnection] Pyth connection test failed for ${exports.PRIMARY_PYTH_ENDPOINT}:`, err);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
exports.testPrimaryPythConnection = testPrimaryPythConnection;
|
|
31
|
+
/**
|
|
32
|
+
* Gets a working Pyth connection endpoint, trying primary first, then fallback if provided
|
|
33
|
+
* @param fallbackPythEndpoint Optional fallback endpoint
|
|
34
|
+
* @returns The endpoint URL that is working, or the primary endpoint if fallback fails
|
|
35
|
+
*/
|
|
36
|
+
const getWorkingPythEndpoint = (fallbackPythEndpoint) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
// Test primary endpoint first
|
|
38
|
+
const primaryWorking = yield (0, exports.testPrimaryPythConnection)();
|
|
39
|
+
if (primaryWorking) {
|
|
40
|
+
console.log(`[getWorkingPythEndpoint] Using primary Pyth endpoint: ${exports.PRIMARY_PYTH_ENDPOINT}`);
|
|
41
|
+
return exports.PRIMARY_PYTH_ENDPOINT;
|
|
42
|
+
}
|
|
43
|
+
// If primary fails and fallback is provided, use fallback
|
|
44
|
+
if (!!fallbackPythEndpoint) {
|
|
45
|
+
console.warn(`[getWorkingPythEndpoint] Primary Pyth endpoint failed, using fallback: ${fallbackPythEndpoint}`);
|
|
46
|
+
return fallbackPythEndpoint;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.error(`[getWorkingPythEndpoint] Primary Pyth endpoint failed, no fallback provided, using primary anyway`);
|
|
50
|
+
return exports.PRIMARY_PYTH_ENDPOINT;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
exports.getWorkingPythEndpoint = getWorkingPythEndpoint;
|
|
@@ -11,7 +11,10 @@ export declare enum StrategyType {
|
|
|
11
11
|
AUSD_sSUI_SUI_LOOPING = "4",
|
|
12
12
|
xBTC_sSUI_SUI_LOOPING = "100",// Used to be for Slush Strategies #0
|
|
13
13
|
xBTC_wBTC_LOOPING = "101",// Used to be for Slush Strategies #1
|
|
14
|
-
suiUSDT_sSUI_SUI_LOOPING = "5"
|
|
14
|
+
suiUSDT_sSUI_SUI_LOOPING = "5",
|
|
15
|
+
AUSD_USDC_LOOPING = "6",
|
|
16
|
+
AUSD_suiUSDT_LOOPING = "7",
|
|
17
|
+
USDC_suiUSDT_LOOPING = "8"
|
|
15
18
|
}
|
|
16
19
|
export declare const STRATEGY_TYPE_INFO_MAP: Record<StrategyType, {
|
|
17
20
|
queryParam: string;
|
package/lib/strategyOwnerCap.js
CHANGED
|
@@ -30,6 +30,9 @@ var StrategyType;
|
|
|
30
30
|
StrategyType["xBTC_sSUI_SUI_LOOPING"] = "100";
|
|
31
31
|
StrategyType["xBTC_wBTC_LOOPING"] = "101";
|
|
32
32
|
StrategyType["suiUSDT_sSUI_SUI_LOOPING"] = "5";
|
|
33
|
+
StrategyType["AUSD_USDC_LOOPING"] = "6";
|
|
34
|
+
StrategyType["AUSD_suiUSDT_LOOPING"] = "7";
|
|
35
|
+
StrategyType["USDC_suiUSDT_LOOPING"] = "8";
|
|
33
36
|
})(StrategyType || (exports.StrategyType = StrategyType = {}));
|
|
34
37
|
exports.STRATEGY_TYPE_INFO_MAP = {
|
|
35
38
|
[StrategyType.sSUI_SUI_LOOPING]: {
|
|
@@ -130,6 +133,48 @@ exports.STRATEGY_TYPE_INFO_MAP = {
|
|
|
130
133
|
currencyCoinTypes: [sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
131
134
|
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
132
135
|
},
|
|
136
|
+
[StrategyType.AUSD_USDC_LOOPING]: {
|
|
137
|
+
queryParam: "AUSD-USDC-looping",
|
|
138
|
+
header: {
|
|
139
|
+
coinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_USDC_COINTYPE],
|
|
140
|
+
title: "AUSD/USDC",
|
|
141
|
+
tooltip: "Sets up an AUSD/USDC Looping strategy by depositing AUSD and borrowing USDC to the desired leverage",
|
|
142
|
+
type: "Looping",
|
|
143
|
+
},
|
|
144
|
+
depositBaseCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
145
|
+
depositLstCoinType: undefined,
|
|
146
|
+
borrowCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
147
|
+
currencyCoinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_USDC_COINTYPE],
|
|
148
|
+
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
149
|
+
},
|
|
150
|
+
[StrategyType.AUSD_suiUSDT_LOOPING]: {
|
|
151
|
+
queryParam: "AUSD-suiUSDT-looping",
|
|
152
|
+
header: {
|
|
153
|
+
coinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
154
|
+
title: "AUSD/suiUSDT",
|
|
155
|
+
tooltip: "Sets up an AUSD/suiUSDT Looping strategy by depositing AUSD and borrowing suiUSDT to the desired leverage",
|
|
156
|
+
type: "Looping",
|
|
157
|
+
},
|
|
158
|
+
depositBaseCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
159
|
+
depositLstCoinType: undefined,
|
|
160
|
+
borrowCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
161
|
+
currencyCoinTypes: [sui_fe_1.NORMALIZED_AUSD_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
162
|
+
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
163
|
+
},
|
|
164
|
+
[StrategyType.USDC_suiUSDT_LOOPING]: {
|
|
165
|
+
queryParam: "USDC-suiUSDT-looping",
|
|
166
|
+
header: {
|
|
167
|
+
coinTypes: [sui_fe_1.NORMALIZED_USDC_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
168
|
+
title: "USDC/suiUSDT",
|
|
169
|
+
tooltip: "Sets up a USDC/suiUSDT Looping strategy by depositing USDC and borrowing suiUSDT to the desired leverage",
|
|
170
|
+
type: "Looping",
|
|
171
|
+
},
|
|
172
|
+
depositBaseCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
173
|
+
depositLstCoinType: undefined,
|
|
174
|
+
borrowCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
175
|
+
currencyCoinTypes: [sui_fe_1.NORMALIZED_USDC_COINTYPE, sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
176
|
+
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
177
|
+
},
|
|
133
178
|
};
|
|
134
179
|
const strategyDeposit = (coin, coinType, strategyOwnerCap, reserveArrayIndex, transaction) => transaction.moveCall({
|
|
135
180
|
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::deposit_liquidity_and_deposit_into_obligation`,
|
|
@@ -273,23 +318,29 @@ const strategyClaimRewardsAndSwapForCoinType = (address, cetusSdk, cetusPartnerI
|
|
|
273
318
|
if (routers === undefined)
|
|
274
319
|
continue; // Skip coin if no swap quote found
|
|
275
320
|
console.log("[strategyClaimRewardsAndSwapForCoinType] swapping coinType", coinType);
|
|
276
|
-
let coinOut;
|
|
277
321
|
try {
|
|
278
|
-
coinOut
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
322
|
+
let coinOut;
|
|
323
|
+
try {
|
|
324
|
+
coinOut = yield cetusSdk.fixableRouterSwapV3({
|
|
325
|
+
router: routers,
|
|
326
|
+
inputCoin: coinIn,
|
|
327
|
+
slippage: 3 / 100,
|
|
328
|
+
txb: transaction,
|
|
329
|
+
partner: cetusPartnerId,
|
|
330
|
+
});
|
|
331
|
+
if (resultCoin)
|
|
332
|
+
transaction.mergeCoins(resultCoin, [coinOut]);
|
|
333
|
+
else
|
|
334
|
+
resultCoin = coinOut;
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
throw new Error(`No swap quote found for ${coinType}`);
|
|
338
|
+
}
|
|
285
339
|
}
|
|
286
340
|
catch (err) {
|
|
287
|
-
|
|
341
|
+
console.error(err);
|
|
342
|
+
continue; // Skip coin if swap fails
|
|
288
343
|
}
|
|
289
|
-
if (resultCoin)
|
|
290
|
-
transaction.mergeCoins(resultCoin, [coinOut]);
|
|
291
|
-
else
|
|
292
|
-
resultCoin = coinOut;
|
|
293
344
|
}
|
|
294
345
|
// 4) Deposit
|
|
295
346
|
if (!resultCoin)
|
|
@@ -329,46 +380,60 @@ depositReserve, strategyOwnerCap, transaction) => __awaiter(void 0, void 0, void
|
|
|
329
380
|
let resultCoin = undefined;
|
|
330
381
|
// 2.1) Get routers
|
|
331
382
|
const amountsAndSortedQuotesMap = Object.fromEntries(yield Promise.all(Object.entries(withdrawnCoinsMap).map(([coinType, { deposit, coin }]) => (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
383
|
+
try {
|
|
384
|
+
// Get amount
|
|
385
|
+
const amount = new bignumber_js_1.default(deposit.depositedAmount.times(swapPercent.div(100)))
|
|
386
|
+
.times(10 ** deposit.reserve.token.decimals)
|
|
387
|
+
.integerValue(bignumber_js_1.default.ROUND_DOWN); // Use underestimate (deposits keep accruing if deposit APR >0)
|
|
388
|
+
// Get routes
|
|
389
|
+
const routers = yield cetusSdk.findRouters({
|
|
390
|
+
from: deposit.coinType,
|
|
391
|
+
target: depositReserve.coinType,
|
|
392
|
+
amount: new bn_js_1.default(amount.toString()), // Underestimate (deposits keep accruing if deposit APR >0)
|
|
393
|
+
byAmountIn: true,
|
|
394
|
+
});
|
|
395
|
+
if (!routers)
|
|
396
|
+
throw new Error(`No swap quote found for ${deposit.coinType}`);
|
|
397
|
+
console.log("[strategySwapSomeDepositsForCoinType] routers", {
|
|
398
|
+
coinType: deposit.coinType,
|
|
399
|
+
routers,
|
|
400
|
+
});
|
|
401
|
+
return [deposit.coinType, { coin, routers }];
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
console.error(err);
|
|
405
|
+
return [coinType, { coin, routers: undefined }];
|
|
406
|
+
}
|
|
350
407
|
}))())));
|
|
351
408
|
console.log("[strategySwapSomeDepositsForCoinType] amountsAndSortedQuotesMap", { amountsAndSortedQuotesMap });
|
|
352
409
|
// 2.2) Swap
|
|
353
410
|
for (const [coinType, { coin: coinIn, routers }] of Object.entries(amountsAndSortedQuotesMap)) {
|
|
411
|
+
if (routers === undefined)
|
|
412
|
+
continue; // Skip coin if no swap quote found
|
|
354
413
|
console.log("[strategySwapSomeDepositsForCoinType] swapping coinType", coinType);
|
|
355
|
-
let coinOut;
|
|
356
414
|
try {
|
|
357
|
-
coinOut
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
415
|
+
let coinOut;
|
|
416
|
+
try {
|
|
417
|
+
coinOut = yield cetusSdk.fixableRouterSwapV3({
|
|
418
|
+
router: routers,
|
|
419
|
+
inputCoin: coinIn,
|
|
420
|
+
slippage: 3 / 100,
|
|
421
|
+
txb: transaction,
|
|
422
|
+
partner: cetusPartnerId,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
throw new Error(`No swap quote found for ${coinType}`);
|
|
427
|
+
}
|
|
428
|
+
if (resultCoin)
|
|
429
|
+
transaction.mergeCoins(resultCoin, [coinOut]);
|
|
430
|
+
else
|
|
431
|
+
resultCoin = coinOut;
|
|
364
432
|
}
|
|
365
433
|
catch (err) {
|
|
366
|
-
|
|
434
|
+
console.error(err);
|
|
435
|
+
continue; // Skip coin if swap fails
|
|
367
436
|
}
|
|
368
|
-
if (resultCoin)
|
|
369
|
-
transaction.mergeCoins(resultCoin, [coinOut]);
|
|
370
|
-
else
|
|
371
|
-
resultCoin = coinOut;
|
|
372
437
|
}
|
|
373
438
|
// 3) Deposit
|
|
374
439
|
if (!resultCoin)
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"1.1.
|
|
1
|
+
{"name":"@suilend/sdk","version":"1.1.93","private":false,"description":"A TypeScript SDK for interacting with the Suilend program","author":"Suilend","license":"MIT","main":"./index.js","exports":{".":"./index.js","./client":"./client.js","./mmt":"./mmt.js","./strategies":"./strategies.js","./api/events":"./api/events.js","./api":"./api/index.js","./lib/constants":"./lib/constants.js","./lib":"./lib/index.js","./lib/initialize":"./lib/initialize.js","./lib/liquidityMining":"./lib/liquidityMining.js","./lib/pyth":"./lib/pyth.js","./lib/strategyOwnerCap":"./lib/strategyOwnerCap.js","./lib/transactions":"./lib/transactions.js","./lib/types":"./lib/types.js","./parsers/apiReserveAssetDataEvent":"./parsers/apiReserveAssetDataEvent.js","./parsers":"./parsers/index.js","./parsers/lendingMarket":"./parsers/lendingMarket.js","./parsers/obligation":"./parsers/obligation.js","./parsers/rateLimiter":"./parsers/rateLimiter.js","./parsers/reserve":"./parsers/reserve.js","./swap":"./swap/index.js","./swap/quote":"./swap/quote.js","./swap/transaction":"./swap/transaction.js","./utils/events":"./utils/events.js","./utils":"./utils/index.js","./utils/obligation":"./utils/obligation.js","./utils/simulate":"./utils/simulate.js","./_generated/_framework/reified":"./_generated/_framework/reified.js","./_generated/_framework/util":"./_generated/_framework/util.js","./_generated/_framework/vector":"./_generated/_framework/vector.js","./_generated/suilend":"./_generated/suilend/index.js","./_generated/suilend/cell/structs":"./_generated/suilend/cell/structs.js","./_generated/suilend/decimal/structs":"./_generated/suilend/decimal/structs.js","./_generated/suilend/lending-market/functions":"./_generated/suilend/lending-market/functions.js","./_generated/suilend/lending-market/structs":"./_generated/suilend/lending-market/structs.js","./_generated/suilend/lending-market-registry/functions":"./_generated/suilend/lending-market-registry/functions.js","./_generated/suilend/liquidity-mining/structs":"./_generated/suilend/liquidity-mining/structs.js","./_generated/suilend/obligation/structs":"./_generated/suilend/obligation/structs.js","./_generated/suilend/rate-limiter/functions":"./_generated/suilend/rate-limiter/functions.js","./_generated/suilend/rate-limiter/structs":"./_generated/suilend/rate-limiter/structs.js","./_generated/suilend/reserve/structs":"./_generated/suilend/reserve/structs.js","./_generated/suilend/reserve-config/functions":"./_generated/suilend/reserve-config/functions.js","./_generated/suilend/reserve-config/structs":"./_generated/suilend/reserve-config/structs.js","./_generated/_dependencies/source/0x1":"./_generated/_dependencies/source/0x1/index.js","./_generated/_dependencies/source/0x2":"./_generated/_dependencies/source/0x2/index.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/index.js","./_generated/_dependencies/source/0x1/ascii/structs":"./_generated/_dependencies/source/0x1/ascii/structs.js","./_generated/_dependencies/source/0x1/option/structs":"./_generated/_dependencies/source/0x1/option/structs.js","./_generated/_dependencies/source/0x1/type-name/structs":"./_generated/_dependencies/source/0x1/type-name/structs.js","./_generated/_dependencies/source/0x2/bag/structs":"./_generated/_dependencies/source/0x2/bag/structs.js","./_generated/_dependencies/source/0x2/balance/structs":"./_generated/_dependencies/source/0x2/balance/structs.js","./_generated/_dependencies/source/0x2/object/structs":"./_generated/_dependencies/source/0x2/object/structs.js","./_generated/_dependencies/source/0x2/object-table/structs":"./_generated/_dependencies/source/0x2/object-table/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.js"},"types":"./index.js","scripts":{"build":"rm -rf ./dist && bun tsc","eslint":"eslint --fix \"./src/**/*.ts\"","prettier":"prettier --write \"./src/**/*\"","lint":"bun eslint && bun prettier && bun tsc --noEmit","release":"bun run build && bun ts-node ./release.ts && cd ./dist && npm publish --access public"},"repository":{"type":"git","url":"git+https://github.com/suilend/suilend-fe-public.git"},"bugs":{"url":"https://github.com/suilend/suilend-fe-public/issues"},"dependencies":{"@7kprotocol/sdk-ts":"^3.5.0","@cetusprotocol/aggregator-sdk":"^1.4.2","@flowx-finance/sdk":"^1.14.0","@pythnetwork/pyth-sui-js":"^2.2.0","@suilend/springsui-sdk":"^1.0.27","aftermath-ts-sdk":"^1.3.24","bignumber.js":"^9.1.2","bn.js":"^5.2.2","crypto-js":"^4.2.0","lodash":"^4.17.21","p-limit":"3.1.0","uuid":"^11.0.3"},"devDependencies":{"@types/bn.js":"^5.2.0","@types/lodash":"^4.17.20","ts-node":"^10.9.2"},"peerDependencies":{"@mysten/bcs":"1.8.1","@mysten/sui":"1.42.0","@suilend/sui-fe":"^0.3.43"},"overrides":{"chalk":"5.3.0","strip-ansi":"7.1.0","color-convert":"2.0.1","color-name":"1.1.4","is-core-module":"2.13.1","error-ex":"1.3.2","has-ansi":"5.0.1"}}
|
package/strategies.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type StrategyWithdraw = {
|
|
|
22
22
|
export declare enum StrategyFlashLoanProvider {
|
|
23
23
|
MMT = "mmt"
|
|
24
24
|
}
|
|
25
|
-
export declare const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP: Record<
|
|
25
|
+
export declare const STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP: Record<StrategyType, {
|
|
26
26
|
provider: StrategyFlashLoanProvider;
|
|
27
27
|
poolId: string;
|
|
28
28
|
coinTypeA: string;
|
|
@@ -336,6 +336,11 @@ export declare const strategyMaxWithdrawTx: (reserveMap: Record<string, ParsedRe
|
|
|
336
336
|
borrowedAmount: BigNumber;
|
|
337
337
|
transaction: Transaction;
|
|
338
338
|
}>;
|
|
339
|
+
export declare const strategyAdjustRepayTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiClient: SuiClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, flashLoanBorrowedAmount: BigNumber, transaction: Transaction, dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<DevInspectResults>) => Promise<{
|
|
340
|
+
deposits: StrategyDeposit[];
|
|
341
|
+
borrowedAmount: BigNumber;
|
|
342
|
+
transaction: Transaction;
|
|
343
|
+
}>;
|
|
339
344
|
export declare const strategyDepositAdjustWithdrawTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiClient: SuiClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, flashLoanBorrowedAmount: BigNumber, transaction: Transaction, dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<DevInspectResults>) => Promise<{
|
|
340
345
|
deposits: StrategyDeposit[];
|
|
341
346
|
borrowedAmount: BigNumber;
|
package/strategies.js
CHANGED
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.strategyAdjustTx = exports.strategyDepositAdjustWithdrawTx = exports.strategyMaxWithdrawTx = exports.strategyWithdrawTx = exports.strategyDepositAndLoopToExposureTx = exports.strategyDepositTx = exports.strategyUnloopToExposureTx = exports.strategyLoopToExposureTx = exports.getStrategyLiquidationPrice = exports.getStrategyHealthPercent = exports.getStrategyAprPercent = exports.getStrategyUnclaimedRewardsAmount = exports.fetchStrategyGlobalTvlAmountUsdMap = exports.strategySimulateDepositAndLoopToExposure = exports.strategySimulateDeposit = exports.strategySimulateLoopToExposure = exports.getStrategyStepMaxWithdrawnAmount = exports.getStrategyStepMaxBorrowedAmount = exports.getStrategyExposure = exports.getStrategyTvlAmount = exports.getStrategyBorrowedAmount = exports.getStrategyDepositedAmount = exports.getStrategySimulatedObligation = exports.getStrategyDefaultCurrencyReserve = exports.getStrategyBorrowReserve = exports.getStrategyDepositReserves = exports.STRATEGY_TYPE_EXPOSURE_MAP = exports.getStrategyLstRedeemFee = exports.getStrategyLstMintFee = exports.fetchStrategyLstMap = exports.getStrategySuiReserve = exports.hasStrategyPosition = exports.addOrInsertStrategyDeposit = exports.getReserveSafeDepositLimit = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = exports.StrategyFlashLoanProvider = exports.LST_DECIMALS = exports.STRATEGY_E = void 0;
|
|
15
|
+
exports.strategyAdjustTx = exports.strategyDepositAdjustWithdrawTx = exports.strategyAdjustRepayTx = exports.strategyMaxWithdrawTx = exports.strategyWithdrawTx = exports.strategyDepositAndLoopToExposureTx = exports.strategyDepositTx = exports.strategyUnloopToExposureTx = exports.strategyLoopToExposureTx = exports.getStrategyLiquidationPrice = exports.getStrategyHealthPercent = exports.getStrategyAprPercent = exports.getStrategyUnclaimedRewardsAmount = exports.fetchStrategyGlobalTvlAmountUsdMap = exports.strategySimulateDepositAndLoopToExposure = exports.strategySimulateDeposit = exports.strategySimulateLoopToExposure = exports.getStrategyStepMaxWithdrawnAmount = exports.getStrategyStepMaxBorrowedAmount = exports.getStrategyExposure = exports.getStrategyTvlAmount = exports.getStrategyBorrowedAmount = exports.getStrategyDepositedAmount = exports.getStrategySimulatedObligation = exports.getStrategyDefaultCurrencyReserve = exports.getStrategyBorrowReserve = exports.getStrategyDepositReserves = exports.STRATEGY_TYPE_EXPOSURE_MAP = exports.getStrategyLstRedeemFee = exports.getStrategyLstMintFee = exports.fetchStrategyLstMap = exports.getStrategySuiReserve = exports.hasStrategyPosition = exports.addOrInsertStrategyDeposit = exports.getReserveSafeDepositLimit = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = exports.StrategyFlashLoanProvider = exports.LST_DECIMALS = exports.STRATEGY_E = void 0;
|
|
16
16
|
const bcs_1 = require("@mysten/bcs");
|
|
17
17
|
const transactions_1 = require("@mysten/sui/transactions");
|
|
18
18
|
const utils_1 = require("@mysten/sui/utils");
|
|
@@ -89,6 +89,30 @@ exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP = {
|
|
|
89
89
|
borrowA: true,
|
|
90
90
|
feePercent: 0.001,
|
|
91
91
|
},
|
|
92
|
+
[strategyOwnerCap_1.StrategyType.AUSD_USDC_LOOPING]: {
|
|
93
|
+
provider: StrategyFlashLoanProvider.MMT,
|
|
94
|
+
poolId: "0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b", // AUSD-USDC 0.01% https://app.mmt.finance/liquidity/0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b
|
|
95
|
+
coinTypeA: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
96
|
+
coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
97
|
+
borrowA: true,
|
|
98
|
+
feePercent: 0.01,
|
|
99
|
+
},
|
|
100
|
+
[strategyOwnerCap_1.StrategyType.AUSD_suiUSDT_LOOPING]: {
|
|
101
|
+
provider: StrategyFlashLoanProvider.MMT,
|
|
102
|
+
poolId: "0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b", // AUSD-USDC 0.01% https://app.mmt.finance/liquidity/0x900f25b27d2b1686886277d763223988d802f3b6152d02872c382d4dce05e25b
|
|
103
|
+
coinTypeA: sui_fe_1.NORMALIZED_AUSD_COINTYPE,
|
|
104
|
+
coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
105
|
+
borrowA: true,
|
|
106
|
+
feePercent: 0.01,
|
|
107
|
+
},
|
|
108
|
+
[strategyOwnerCap_1.StrategyType.USDC_suiUSDT_LOOPING]: {
|
|
109
|
+
provider: StrategyFlashLoanProvider.MMT,
|
|
110
|
+
poolId: "0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9", // suiUSDT-USDC 0.001% https://app.mmt.finance/liquidity/0x737ec6a4d3ed0c7e6cc18d8ba04e7ffd4806b726c97efd89867597368c4d06a9
|
|
111
|
+
coinTypeA: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
112
|
+
coinTypeB: sui_fe_1.NORMALIZED_USDC_COINTYPE,
|
|
113
|
+
borrowA: false,
|
|
114
|
+
feePercent: 0.001,
|
|
115
|
+
},
|
|
92
116
|
};
|
|
93
117
|
const getReserveSafeDepositLimit = (reserve) => {
|
|
94
118
|
// Calculate safe deposit limit (subtract 10 mins of deposit APR from cap)
|
|
@@ -232,6 +256,21 @@ exports.STRATEGY_TYPE_EXPOSURE_MAP = {
|
|
|
232
256
|
max: new bignumber_js_1.default(3), // Actual max: 1 + (suiUSDT Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where suiUSDT Open LTV % = 77% and sSUI Open LTV % = 70%
|
|
233
257
|
default: new bignumber_js_1.default(3),
|
|
234
258
|
},
|
|
259
|
+
[strategyOwnerCap_1.StrategyType.AUSD_USDC_LOOPING]: {
|
|
260
|
+
min: new bignumber_js_1.default(1),
|
|
261
|
+
max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (AUSD Open LTV %)) = 4.347x, where AUSD Open LTV % = 77%
|
|
262
|
+
default: new bignumber_js_1.default(4),
|
|
263
|
+
},
|
|
264
|
+
[strategyOwnerCap_1.StrategyType.AUSD_suiUSDT_LOOPING]: {
|
|
265
|
+
min: new bignumber_js_1.default(1),
|
|
266
|
+
max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (AUSD Open LTV %)) = 4.347x, where AUSD Open LTV % = 77%
|
|
267
|
+
default: new bignumber_js_1.default(4),
|
|
268
|
+
},
|
|
269
|
+
[strategyOwnerCap_1.StrategyType.USDC_suiUSDT_LOOPING]: {
|
|
270
|
+
min: new bignumber_js_1.default(1),
|
|
271
|
+
max: new bignumber_js_1.default(4), // Actual max: 1 / (1 - (USDC Open LTV %)) = 4.347x, where USDC Open LTV % = 77%
|
|
272
|
+
default: new bignumber_js_1.default(4),
|
|
273
|
+
},
|
|
235
274
|
};
|
|
236
275
|
// Reserves
|
|
237
276
|
const getStrategyDepositReserves = (
|
|
@@ -765,7 +804,7 @@ lstMap, strategyType, obligation, exposure) => {
|
|
|
765
804
|
const weightedBorrowsUsd = (0, utils_2.getWeightedBorrowsUsd)(_obligation);
|
|
766
805
|
const borrowLimitUsd = _obligation.minPriceBorrowLimitUsd.times(depositReserves.base !== undefined
|
|
767
806
|
? 0.99 // 1% buffer
|
|
768
|
-
:
|
|
807
|
+
: 1);
|
|
769
808
|
const liquidationThresholdUsd = _obligation.unhealthyBorrowValueUsd;
|
|
770
809
|
if (weightedBorrowsUsd.lte(borrowLimitUsd))
|
|
771
810
|
return new bignumber_js_1.default(100);
|
|
@@ -1102,8 +1141,14 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1102
1141
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1103
1142
|
if (depositReserves.lst === undefined)
|
|
1104
1143
|
throw new Error("LST reserve not found");
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1144
|
+
const borrowedAmountUsd = borrowedAmount.times(borrowReserve.price);
|
|
1145
|
+
const fullRepaymentAmount = (borrowedAmountUsd.lt(0.1)
|
|
1146
|
+
? new bignumber_js_1.default(0.1).div(borrowReserve.price) // $0.1 in borrow coinType
|
|
1147
|
+
: borrowedAmountUsd.lt(1)
|
|
1148
|
+
? borrowedAmount.times(1.1) // 10% buffer
|
|
1149
|
+
: borrowedAmountUsd.lt(10)
|
|
1150
|
+
? borrowedAmount.times(1.01) // 1% buffer
|
|
1151
|
+
: borrowedAmount.times(1.001)) // 0.1% buffer
|
|
1107
1152
|
.decimalPlaces(borrowReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN);
|
|
1108
1153
|
console.log(`[unloopStrategyToExposure.fullyRepayBorrowsUsingLst] |`, JSON.stringify({
|
|
1109
1154
|
borrowedAmount: borrowedAmount.toFixed(20),
|
|
@@ -1217,9 +1262,9 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1217
1262
|
.toFixed(20),
|
|
1218
1263
|
});
|
|
1219
1264
|
// 2.2) Swap
|
|
1220
|
-
let
|
|
1265
|
+
let swapCoin;
|
|
1221
1266
|
try {
|
|
1222
|
-
|
|
1267
|
+
swapCoin = yield cetusSdk.fixableRouterSwapV3({
|
|
1223
1268
|
router: routers,
|
|
1224
1269
|
inputCoin: withdrawnRemainingLstCoin,
|
|
1225
1270
|
slippage: 100 / 100,
|
|
@@ -1231,14 +1276,22 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1231
1276
|
throw new Error("No swap quote found");
|
|
1232
1277
|
}
|
|
1233
1278
|
// 3) Deposit base
|
|
1234
|
-
(0, strategyOwnerCap_1.strategyDeposit)(
|
|
1279
|
+
(0, strategyOwnerCap_1.strategyDeposit)(swapCoin, depositReserves.base.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserves.base.coinType), transaction);
|
|
1235
1280
|
}
|
|
1236
1281
|
});
|
|
1237
1282
|
const fullyRepayBorrowsUsingBase = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1238
1283
|
var _a, _b;
|
|
1239
1284
|
if (depositReserves.base === undefined)
|
|
1240
1285
|
throw new Error("Base reserve not found");
|
|
1241
|
-
const
|
|
1286
|
+
const borrowedAmountUsd = borrowedAmount.times(borrowReserve.price);
|
|
1287
|
+
const fullRepaymentAmount = (borrowedAmountUsd.lt(0.1)
|
|
1288
|
+
? new bignumber_js_1.default(0.1).div(borrowReserve.price) // $0.1 in borrow coinType
|
|
1289
|
+
: borrowedAmountUsd.lt(1)
|
|
1290
|
+
? borrowedAmount.times(1.1) // 10% buffer
|
|
1291
|
+
: borrowedAmountUsd.lt(10)
|
|
1292
|
+
? borrowedAmount.times(1.01) // 1% buffer
|
|
1293
|
+
: borrowedAmount.times(1.001)) // 0.1% buffer
|
|
1294
|
+
.decimalPlaces(borrowReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN);
|
|
1242
1295
|
console.log(`[unloopStrategyToExposure.fullyRepayBorrowsUsingBase] |`, JSON.stringify({
|
|
1243
1296
|
borrowedAmount: borrowedAmount.toFixed(20),
|
|
1244
1297
|
fullRepaymentAmount: fullRepaymentAmount.toFixed(20),
|
|
@@ -1267,7 +1320,8 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1267
1320
|
// 2) Withdraw base
|
|
1268
1321
|
const baseWithdrawnAmount = new bignumber_js_1.default(fullRepaymentAmount.times(borrowReserve.price))
|
|
1269
1322
|
.div(depositReserves.base.price)
|
|
1270
|
-
.times(1.03)
|
|
1323
|
+
.times(1.03) // 3% buffer
|
|
1324
|
+
.decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_UP);
|
|
1271
1325
|
console.log(`[unloopStrategyToExposure.fullyRepayBorrowsUsingBase] withdraw_base |`, JSON.stringify({
|
|
1272
1326
|
baseWithdrawnAmount: baseWithdrawnAmount.toFixed(20),
|
|
1273
1327
|
}, null, 2));
|
|
@@ -1316,9 +1370,9 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1316
1370
|
.toFixed(20),
|
|
1317
1371
|
});
|
|
1318
1372
|
// 3.2) Swap
|
|
1319
|
-
let
|
|
1373
|
+
let swapCoin;
|
|
1320
1374
|
try {
|
|
1321
|
-
|
|
1375
|
+
swapCoin = yield cetusSdk.fixableRouterSwapV3({
|
|
1322
1376
|
router: routers,
|
|
1323
1377
|
inputCoin: withdrawnBaseCoin,
|
|
1324
1378
|
slippage: 1 / 100,
|
|
@@ -1337,15 +1391,15 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1337
1391
|
}, null, 2));
|
|
1338
1392
|
try {
|
|
1339
1393
|
const txCopy = transactions_1.Transaction.from(transaction);
|
|
1340
|
-
suilendClient.repay(obligationId, borrowReserve.coinType,
|
|
1341
|
-
txCopy.transferObjects([
|
|
1394
|
+
suilendClient.repay(obligationId, borrowReserve.coinType, swapCoin, txCopy);
|
|
1395
|
+
txCopy.transferObjects([swapCoin], _address); // Transfer remaining to user
|
|
1342
1396
|
yield dryRunTransaction(txCopy); // Throws error if fails
|
|
1343
1397
|
transaction = txCopy;
|
|
1344
1398
|
}
|
|
1345
1399
|
catch (err) {
|
|
1346
1400
|
// Don't block user if fails
|
|
1347
1401
|
console.error(err);
|
|
1348
|
-
transaction.transferObjects([
|
|
1402
|
+
transaction.transferObjects([swapCoin], _address); // Transfer to user
|
|
1349
1403
|
}
|
|
1350
1404
|
// 4.2) Update state
|
|
1351
1405
|
borrowedAmount = bignumber_js_1.default.max(borrowedAmount.minus(repaidAmount), new bignumber_js_1.default(0));
|
|
@@ -1356,7 +1410,7 @@ transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
1356
1410
|
})),
|
|
1357
1411
|
borrowedAmount: borrowedAmount.toFixed(20),
|
|
1358
1412
|
}, null, 2));
|
|
1359
|
-
// 5) Swap remaining
|
|
1413
|
+
// 5) Swap remaining to base and redeposit (not possible because coin is a mutable reference (?))
|
|
1360
1414
|
});
|
|
1361
1415
|
for (let i = 0; i < 30; i++) {
|
|
1362
1416
|
const exposure = (0, exports.getStrategyExposure)(reserveMap, lstMap, strategyType, (0, exports.getStrategySimulatedObligation)(reserveMap, lstMap, strategyType, deposits, borrowedAmount));
|
|
@@ -2006,6 +2060,176 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
|
|
|
2006
2060
|
return { deposits, borrowedAmount, transaction };
|
|
2007
2061
|
});
|
|
2008
2062
|
exports.strategyMaxWithdrawTx = strategyMaxWithdrawTx;
|
|
2063
|
+
const strategyAdjustRepayTx = (
|
|
2064
|
+
// AppContext
|
|
2065
|
+
reserveMap,
|
|
2066
|
+
// Strategy
|
|
2067
|
+
lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, flashLoanBorrowedAmount, transaction, dryRunTransaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2068
|
+
var _a, _b, _c, _d;
|
|
2069
|
+
const strategyInfo = strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP[strategyType];
|
|
2070
|
+
const lst = strategyInfo.depositLstCoinType !== undefined
|
|
2071
|
+
? lstMap[strategyInfo.depositLstCoinType]
|
|
2072
|
+
: undefined;
|
|
2073
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
2074
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
2075
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
2076
|
+
const adjustRepayExposure = exports.STRATEGY_TYPE_EXPOSURE_MAP[strategyType].min;
|
|
2077
|
+
console.log(`[strategyAdjustRepay] args |`, JSON.stringify({
|
|
2078
|
+
_address,
|
|
2079
|
+
strategyOwnerCapId,
|
|
2080
|
+
obligationId,
|
|
2081
|
+
_deposits: _deposits.map((d) => ({
|
|
2082
|
+
coinType: d.coinType,
|
|
2083
|
+
depositedAmount: d.depositedAmount.toFixed(20),
|
|
2084
|
+
})),
|
|
2085
|
+
_borrowedAmount: _borrowedAmount.toFixed(20),
|
|
2086
|
+
flashLoanBorrowedAmount: flashLoanBorrowedAmount.toFixed(20),
|
|
2087
|
+
}, null, 2));
|
|
2088
|
+
// const depositReserve = (depositReserves.base ?? depositReserves.lst)!; // Must have LST if no base
|
|
2089
|
+
if (!depositReserves.base)
|
|
2090
|
+
throw new Error("Base reserve not found");
|
|
2091
|
+
//
|
|
2092
|
+
let deposits = (0, lodash_1.cloneDeep)(_deposits);
|
|
2093
|
+
let borrowedAmount = _borrowedAmount;
|
|
2094
|
+
// 1) Flash loan base
|
|
2095
|
+
const flashLoanObj = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
|
|
2096
|
+
let borrowedBalanceA, borrowedBalanceB, receipt;
|
|
2097
|
+
if (flashLoanObj.provider === StrategyFlashLoanProvider.MMT) {
|
|
2098
|
+
[borrowedBalanceA, borrowedBalanceB, receipt] = transaction.moveCall({
|
|
2099
|
+
target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::flash_loan`,
|
|
2100
|
+
typeArguments: [flashLoanObj.coinTypeA, flashLoanObj.coinTypeB],
|
|
2101
|
+
arguments: [
|
|
2102
|
+
transaction.object(flashLoanObj.poolId),
|
|
2103
|
+
transaction.pure.u64(flashLoanObj.borrowA
|
|
2104
|
+
? flashLoanBorrowedAmount
|
|
2105
|
+
.times(10 ** depositReserves.base.token.decimals)
|
|
2106
|
+
.integerValue(bignumber_js_1.default.ROUND_DOWN)
|
|
2107
|
+
.toString()
|
|
2108
|
+
: 0),
|
|
2109
|
+
transaction.pure.u64(flashLoanObj.borrowA
|
|
2110
|
+
? 0
|
|
2111
|
+
: flashLoanBorrowedAmount
|
|
2112
|
+
.times(10 ** depositReserves.base.token.decimals)
|
|
2113
|
+
.integerValue(bignumber_js_1.default.ROUND_DOWN)
|
|
2114
|
+
.toString()),
|
|
2115
|
+
transaction.object(mmt_1.MMT_VERSION_OBJECT_ID),
|
|
2116
|
+
],
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
else {
|
|
2120
|
+
throw new Error("Invalid flash loan provider");
|
|
2121
|
+
}
|
|
2122
|
+
const flashLoanBorrowedCoin = transaction.moveCall({
|
|
2123
|
+
target: "0x2::coin::from_balance",
|
|
2124
|
+
typeArguments: [
|
|
2125
|
+
flashLoanObj.borrowA ? flashLoanObj.coinTypeA : flashLoanObj.coinTypeB,
|
|
2126
|
+
],
|
|
2127
|
+
arguments: [flashLoanObj.borrowA ? borrowedBalanceA : borrowedBalanceB],
|
|
2128
|
+
});
|
|
2129
|
+
// 2) Swap flash loaned base for borrow
|
|
2130
|
+
// 2.1) Get routers
|
|
2131
|
+
const routers = yield cetusSdk.findRouters({
|
|
2132
|
+
from: depositReserves.base.coinType,
|
|
2133
|
+
target: borrowReserve.coinType,
|
|
2134
|
+
amount: new bn_js_1.BN(flashLoanBorrowedAmount
|
|
2135
|
+
.times(10 ** depositReserves.base.token.decimals)
|
|
2136
|
+
.integerValue(bignumber_js_1.default.ROUND_DOWN)
|
|
2137
|
+
.toString()),
|
|
2138
|
+
byAmountIn: true,
|
|
2139
|
+
});
|
|
2140
|
+
if (!routers)
|
|
2141
|
+
throw new Error("No swap quote found");
|
|
2142
|
+
console.log(`[strategyAdjustRepay] swap_flash_loan_base_for_borrows.get_routers`, {
|
|
2143
|
+
routers,
|
|
2144
|
+
amountIn: new bignumber_js_1.default(routers.amountIn.toString())
|
|
2145
|
+
.div(10 ** depositReserves.base.token.decimals)
|
|
2146
|
+
.decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_DOWN)
|
|
2147
|
+
.toFixed(20),
|
|
2148
|
+
amountOut: new bignumber_js_1.default(routers.amountOut.toString())
|
|
2149
|
+
.div(10 ** borrowReserve.token.decimals)
|
|
2150
|
+
.decimalPlaces(borrowReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN)
|
|
2151
|
+
.toFixed(20),
|
|
2152
|
+
});
|
|
2153
|
+
// 2.2) Swap
|
|
2154
|
+
let swapCoin;
|
|
2155
|
+
try {
|
|
2156
|
+
swapCoin = yield cetusSdk.fixableRouterSwapV3({
|
|
2157
|
+
router: routers,
|
|
2158
|
+
inputCoin: flashLoanBorrowedCoin,
|
|
2159
|
+
slippage: 1 / 100,
|
|
2160
|
+
txb: transaction,
|
|
2161
|
+
partner: cetusPartnerId,
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
catch (err) {
|
|
2165
|
+
throw new Error("No swap quote found");
|
|
2166
|
+
}
|
|
2167
|
+
// 3) Fully repay borrows
|
|
2168
|
+
// 3.1) Repay
|
|
2169
|
+
suilendClient.repay(obligationId, borrowReserve.coinType, swapCoin, transaction);
|
|
2170
|
+
transaction.transferObjects([swapCoin], _address); // Transfer remaining to user
|
|
2171
|
+
// 3.2) Update state
|
|
2172
|
+
borrowedAmount = new bignumber_js_1.default(0);
|
|
2173
|
+
console.log(`[strategyAdjustRepay] repay_borrows.update_state |`, JSON.stringify({
|
|
2174
|
+
deposits: deposits.map((d) => ({
|
|
2175
|
+
coinType: d.coinType,
|
|
2176
|
+
depositedAmount: d.depositedAmount.toFixed(20),
|
|
2177
|
+
})),
|
|
2178
|
+
borrowedAmount: borrowedAmount.toFixed(20),
|
|
2179
|
+
}, null, 2));
|
|
2180
|
+
// 4) Swap remaining to base and redeposit (not possible because coin is a mutable reference (?))
|
|
2181
|
+
// 5) Repay flash loan + fee
|
|
2182
|
+
const receiptDebts = transaction.moveCall({
|
|
2183
|
+
target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::flash_receipt_debts`,
|
|
2184
|
+
typeArguments: [],
|
|
2185
|
+
arguments: [receipt],
|
|
2186
|
+
});
|
|
2187
|
+
const dryRunResults = yield dryRunTransaction(transaction);
|
|
2188
|
+
const flashLoanRepayAmount = new bignumber_js_1.default(bcs_1.bcs
|
|
2189
|
+
.u64()
|
|
2190
|
+
.parse(new Uint8Array((_d = (_c = (_b = (_a = dryRunResults.results) === null || _a === void 0 ? void 0 : _a.find((r, index) => index === receiptDebts.Result)) === null || _b === void 0 ? void 0 : _b.returnValues) === null || _c === void 0 ? void 0 : _c[flashLoanObj.borrowA ? 0 : 1][0]) !== null && _d !== void 0 ? _d : [0])))
|
|
2191
|
+
.div(10 ** depositReserves.base.token.decimals)
|
|
2192
|
+
.decimalPlaces(depositReserves.base.token.decimals, bignumber_js_1.default.ROUND_UP);
|
|
2193
|
+
// 5.1) Withdraw base + fee
|
|
2194
|
+
const withdrawnAmount = flashLoanRepayAmount;
|
|
2195
|
+
const { deposits: newDeposits2, borrowedAmount: newBorrowedAmount2, transaction: newTransaction2, withdrawnCoin, } = yield (0, exports.strategyWithdrawTx)(reserveMap, lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, {
|
|
2196
|
+
coinType: depositReserves.base.coinType,
|
|
2197
|
+
withdrawnAmount,
|
|
2198
|
+
}, transaction, dryRunTransaction, true);
|
|
2199
|
+
if (!withdrawnCoin)
|
|
2200
|
+
throw new Error("Withdrawn coin not found");
|
|
2201
|
+
// 5.2) Update state
|
|
2202
|
+
deposits = newDeposits2;
|
|
2203
|
+
borrowedAmount = newBorrowedAmount2;
|
|
2204
|
+
transaction = newTransaction2;
|
|
2205
|
+
// 5.3) Repay flash loan
|
|
2206
|
+
const flashLoanRepayCoin = withdrawnCoin;
|
|
2207
|
+
const flashLoanRepayBalance = transaction.moveCall({
|
|
2208
|
+
target: "0x2::coin::into_balance",
|
|
2209
|
+
typeArguments: [
|
|
2210
|
+
flashLoanObj.borrowA ? flashLoanObj.coinTypeA : flashLoanObj.coinTypeB,
|
|
2211
|
+
],
|
|
2212
|
+
arguments: [flashLoanRepayCoin],
|
|
2213
|
+
});
|
|
2214
|
+
if (flashLoanObj.provider === StrategyFlashLoanProvider.MMT) {
|
|
2215
|
+
transaction.moveCall({
|
|
2216
|
+
target: `${mmt_1.MMT_CONTRACT_PACKAGE_ID}::trade::repay_flash_loan`,
|
|
2217
|
+
typeArguments: [flashLoanObj.coinTypeA, flashLoanObj.coinTypeB],
|
|
2218
|
+
arguments: [
|
|
2219
|
+
transaction.object(flashLoanObj.poolId),
|
|
2220
|
+
receipt,
|
|
2221
|
+
flashLoanObj.borrowA ? flashLoanRepayBalance : borrowedBalanceA,
|
|
2222
|
+
flashLoanObj.borrowA ? borrowedBalanceB : flashLoanRepayBalance,
|
|
2223
|
+
transaction.object(mmt_1.MMT_VERSION_OBJECT_ID),
|
|
2224
|
+
],
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
else {
|
|
2228
|
+
throw new Error("Invalid flash loan provider");
|
|
2229
|
+
}
|
|
2230
|
+
return { deposits, borrowedAmount, transaction };
|
|
2231
|
+
});
|
|
2232
|
+
exports.strategyAdjustRepayTx = strategyAdjustRepayTx;
|
|
2009
2233
|
const strategyDepositAdjustWithdrawTx = (
|
|
2010
2234
|
// AppContext
|
|
2011
2235
|
reserveMap,
|
|
@@ -2035,7 +2259,7 @@ lstMap, strategyType, suiClient, suilendClient, cetusSdk, cetusPartnerId, _addre
|
|
|
2035
2259
|
//
|
|
2036
2260
|
let deposits = (0, lodash_1.cloneDeep)(_deposits);
|
|
2037
2261
|
let borrowedAmount = _borrowedAmount;
|
|
2038
|
-
// 1) Flash loan
|
|
2262
|
+
// 1) Flash loan base/LST
|
|
2039
2263
|
const flashLoanObj = exports.STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
|
|
2040
2264
|
if (depositReserve.coinType === ((_b = depositReserves.lst) === null || _b === void 0 ? void 0 : _b.coinType)) {
|
|
2041
2265
|
// TODO: Account for LST mint fees
|