@carrot-protocol/clend-rpc 0.1.27-group-refactor1-dev-0a2c078 → 0.1.27-swapper1-dev-0d501ff
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/addresses.d.ts +7 -14
- package/dist/addresses.js +11 -30
- package/dist/addresses.js.map +1 -1
- package/dist/events.d.ts +1 -8
- package/dist/events.js +0 -11
- package/dist/events.js.map +1 -1
- package/dist/idl/clend.d.ts +1 -40
- package/dist/idl/clend.js +1 -40
- package/dist/idl/clend.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +4 -8
- package/dist/instructions.js +6 -101
- package/dist/instructions.js.map +1 -1
- package/dist/rpc.d.ts +13 -19
- package/dist/rpc.js +306 -336
- package/dist/rpc.js.map +1 -1
- package/dist/state.d.ts +4 -34
- package/dist/state.js +3 -61
- package/dist/state.js.map +1 -1
- package/dist/swapper/interface.d.ts +1 -4
- package/dist/swapper/jupiterSwapper.d.ts +2 -1
- package/dist/swapper/jupiterSwapper.js +2 -3
- package/dist/swapper/jupiterSwapper.js.map +1 -1
- package/dist/swapper/mockJupiterSwapper.d.ts +1 -1
- package/dist/swapper/mockJupiterSwapper.js +1 -2
- package/dist/swapper/mockJupiterSwapper.js.map +1 -1
- package/dist/utils.d.ts +1 -49
- package/dist/utils.js +0 -129
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
package/dist/rpc.js
CHANGED
|
@@ -33,25 +33,10 @@ class ClendClient {
|
|
|
33
33
|
address() {
|
|
34
34
|
return this.provider.wallet.publicKey;
|
|
35
35
|
}
|
|
36
|
-
// determine type of oracle then fetch price from mint
|
|
37
|
-
// TODO: do it better than this hack
|
|
38
|
-
async getOraclePrice(mint) {
|
|
39
|
-
try {
|
|
40
|
-
return await this.getPythOraclePrice(mint);
|
|
41
|
-
}
|
|
42
|
-
catch (e) {
|
|
43
|
-
try {
|
|
44
|
-
return await this.getSBOraclePrice(mint);
|
|
45
|
-
}
|
|
46
|
-
catch (sbError) {
|
|
47
|
-
throw sbError;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
36
|
/**
|
|
52
37
|
* Get pyth oracle price for a token
|
|
53
38
|
*/
|
|
54
|
-
async
|
|
39
|
+
async getOraclePrice(mint) {
|
|
55
40
|
const oracle = this.getOracle(mint);
|
|
56
41
|
// get oracle account info
|
|
57
42
|
const oracleAccountInfo = await this.connection.getAccountInfo(oracle, {
|
|
@@ -70,34 +55,10 @@ class ClendClient {
|
|
|
70
55
|
// get ema price
|
|
71
56
|
const emaPrice = new anchor_1.BN(oracleData.priceMessage.emaPrice);
|
|
72
57
|
// return price
|
|
73
|
-
return (
|
|
58
|
+
return (emaPrice.toNumber() *
|
|
59
|
+
Math.pow(10, Number(oracleData.priceMessage.exponent)));
|
|
74
60
|
}
|
|
75
|
-
|
|
76
|
-
const oracle = this.getOracle(mint);
|
|
77
|
-
// Fetch the raw account info.
|
|
78
|
-
const feedAccountInfo = await this.connection.getAccountInfo(oracle, "processed");
|
|
79
|
-
if (feedAccountInfo === null) {
|
|
80
|
-
throw new Error(`Feed account ${oracle.toString()} not found.`);
|
|
81
|
-
}
|
|
82
|
-
// Use our manual parser instead of the Anchor coder.
|
|
83
|
-
const pullFeedAccountData = (0, utils_1.parsePullFeedAccountData)(feedAccountInfo.data);
|
|
84
|
-
if (!pullFeedAccountData ||
|
|
85
|
-
!pullFeedAccountData.submissions ||
|
|
86
|
-
pullFeedAccountData.submissions.length === 0) {
|
|
87
|
-
throw new Error(`No valid submissions found for feed ${oracle.toString()}.`);
|
|
88
|
-
}
|
|
89
|
-
// The latest submission will be the first element after sorting.
|
|
90
|
-
const latestSubmission = pullFeedAccountData.submissions[0];
|
|
91
|
-
// The 'value' is a BN (BigNumber), so we convert it to a standard JavaScript number.
|
|
92
|
-
// Be aware of potential precision loss if the number is larger than Number.MAX_SAFE_INTEGER.
|
|
93
|
-
const price = Number(latestSubmission.value);
|
|
94
|
-
// The exponent for Switchboard v2/v3 feeds is typically -18, but you should
|
|
95
|
-
// confirm this for the specific feed you are using.
|
|
96
|
-
const exponent = -18;
|
|
97
|
-
const priceDecimal = (0, utils_1.calculatePriceUi)(price, exponent);
|
|
98
|
-
return priceDecimal;
|
|
99
|
-
}
|
|
100
|
-
// find oracle for a mint from in memory cache
|
|
61
|
+
// find oracle for a mint
|
|
101
62
|
getOracle(mint) {
|
|
102
63
|
const oracleStr = this.mintOracleMapping.get(mint.toString());
|
|
103
64
|
if (!oracleStr) {
|
|
@@ -197,73 +158,14 @@ class ClendClient {
|
|
|
197
158
|
return this.send([initIx]);
|
|
198
159
|
}
|
|
199
160
|
// Bank Operations
|
|
200
|
-
async addBank(clendGroup, bankMint,
|
|
161
|
+
async addBank(clendGroup, bankMint, pythOracle, pythOracleFeedId, bankConfig, interestRateConfig) {
|
|
201
162
|
const tokenProgram = (0, utils_1.getTokenProgramForMint)(bankMint);
|
|
202
163
|
const feeStateAccountData = await this.getFeeState();
|
|
203
164
|
const globalFeeWallet = feeStateAccountData.globalFeeWallet;
|
|
204
|
-
const { bank, ixns } = await this.instructions.addBank(clendGroup, this.address(), globalFeeWallet, bankMint, tokenProgram,
|
|
165
|
+
const { bank, ixns } = await this.instructions.addBank(clendGroup, this.address(), globalFeeWallet, bankMint, tokenProgram, pythOracle, pythOracleFeedId, bankConfig, interestRateConfig);
|
|
205
166
|
const txSig = await this.send(ixns);
|
|
206
167
|
return { bank, txSig };
|
|
207
168
|
}
|
|
208
|
-
async setupBankEmissions(bank, emissionsMint, emissionsMode, emissionsRate, totalEmissions) {
|
|
209
|
-
// some sanity checks
|
|
210
|
-
if (totalEmissions.lte(new anchor_1.BN(0))) {
|
|
211
|
-
throw new Error("totalEmissions must be greater than 0");
|
|
212
|
-
}
|
|
213
|
-
if (emissionsRate.lte(new anchor_1.BN(0))) {
|
|
214
|
-
throw new Error("emissionsRate must be greater than 0");
|
|
215
|
-
}
|
|
216
|
-
if (emissionsRate.gt(totalEmissions)) {
|
|
217
|
-
throw new Error("emissionsRate must be less than totalEmissions");
|
|
218
|
-
}
|
|
219
|
-
const bankData = await this.getBank(bank);
|
|
220
|
-
if (!bankData.emissionsMint.equals(anchor_1.web3.PublicKey.default)) {
|
|
221
|
-
throw new Error("bank already has emissions mint set");
|
|
222
|
-
}
|
|
223
|
-
// fetch token program from chain
|
|
224
|
-
const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
|
|
225
|
-
const ixns = await this.instructions.setupBankEmissions(bankData.group, this.address(), bank, emissionsMint, emissionsMintTokenProgram, emissionsMode, emissionsRate, totalEmissions);
|
|
226
|
-
const txSig = await this.send(ixns);
|
|
227
|
-
return txSig;
|
|
228
|
-
}
|
|
229
|
-
async updateBankEmissions(bank, emissionsMode, emissionsRate, additionalEmissions) {
|
|
230
|
-
// some sanity checks
|
|
231
|
-
if (additionalEmissions !== null && additionalEmissions.lte(new anchor_1.BN(0))) {
|
|
232
|
-
throw new Error("additionalEmissions must be greater than 0");
|
|
233
|
-
}
|
|
234
|
-
if (emissionsRate !== null && emissionsRate.lte(new anchor_1.BN(0))) {
|
|
235
|
-
throw new Error("emissionsRate must be greater than 0");
|
|
236
|
-
}
|
|
237
|
-
if (emissionsRate !== null &&
|
|
238
|
-
additionalEmissions !== null &&
|
|
239
|
-
emissionsRate.gt(additionalEmissions)) {
|
|
240
|
-
throw new Error("emissionsRate must be less than additionalEmissions");
|
|
241
|
-
}
|
|
242
|
-
const bankData = await this.getBank(bank);
|
|
243
|
-
// with updateBankEmissions you cannot change the emissions mint
|
|
244
|
-
const emissionsMint = bankData.emissionsMint;
|
|
245
|
-
if (emissionsMint.equals(anchor_1.web3.PublicKey.default)) {
|
|
246
|
-
throw new Error("bank does not have emissions mint set, must call setupBankEmissions first");
|
|
247
|
-
}
|
|
248
|
-
const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
|
|
249
|
-
const ix = await this.instructions.updateBankEmissions(bankData.group, this.address(), bank, emissionsMint, emissionsMintTokenProgram, emissionsMode, emissionsRate, additionalEmissions);
|
|
250
|
-
const txSig = await this.send([ix]);
|
|
251
|
-
return txSig;
|
|
252
|
-
}
|
|
253
|
-
async withdrawEmissions(clendAccount, bank) {
|
|
254
|
-
const bankData = await this.getBank(bank);
|
|
255
|
-
const emissionsMint = bankData.emissionsMint;
|
|
256
|
-
const mintData = await this.connection.getAccountInfo(emissionsMint, {
|
|
257
|
-
commitment: "processed",
|
|
258
|
-
});
|
|
259
|
-
if (mintData === null) {
|
|
260
|
-
throw new Error(`emissions mint not found: ${emissionsMint.toString()}`);
|
|
261
|
-
}
|
|
262
|
-
const emissionsMintTokenProgram = mintData.owner;
|
|
263
|
-
const ixns = await this.instructions.withdrawEmissions(bankData.group, clendAccount, this.address(), bank, emissionsMint, emissionsMintTokenProgram);
|
|
264
|
-
const txSig = await this.send(ixns);
|
|
265
|
-
return txSig;
|
|
266
|
-
}
|
|
267
169
|
// Account fetching Operations
|
|
268
170
|
async getClendGroup(clendGroup) {
|
|
269
171
|
const accountInfo = await this.connection.getAccountInfo(clendGroup, {
|
|
@@ -338,9 +240,9 @@ class ClendClient {
|
|
|
338
240
|
collectedGroupFeesOutstanding: Number((0, utils_1.wrappedI80F48toBigNumber)(data.collectedGroupFeesOutstanding)),
|
|
339
241
|
lastUpdate: new anchor_1.BN(data.lastUpdate),
|
|
340
242
|
config: bankConfig,
|
|
341
|
-
flags:
|
|
243
|
+
flags: new anchor_1.BN(data.flags),
|
|
342
244
|
emissionsRate: new anchor_1.BN(data.emissionsRate),
|
|
343
|
-
emissionsRemaining:
|
|
245
|
+
emissionsRemaining: (0, utils_1.wrappedI80F48toBigNumber)(data.emissionsRemaining),
|
|
344
246
|
emissionsMint: new anchor_1.web3.PublicKey(data.emissionsMint),
|
|
345
247
|
collectedProgramFeesOutstanding: Number((0, utils_1.wrappedI80F48toBigNumber)(data.collectedProgramFeesOutstanding)),
|
|
346
248
|
assetAmount,
|
|
@@ -393,29 +295,21 @@ class ClendClient {
|
|
|
393
295
|
const bankData = await this.getBank(bank);
|
|
394
296
|
const bankMint = bankData.mint;
|
|
395
297
|
const price = await this.getOraclePrice(bankMint);
|
|
396
|
-
const assetShares = Number((0, utils_1.wrappedI80F48toBigNumber)(balance.assetShares));
|
|
397
|
-
const liabilityShares = Number((0, utils_1.wrappedI80F48toBigNumber)(balance.liabilityShares));
|
|
398
|
-
const lastUpdate = new anchor_1.BN(balance.lastUpdate);
|
|
399
|
-
const emissionsOutstanding = new anchor_1.BN((0, utils_1.wrappedI80F48toBigNumber)(balance.emissionsOutstanding));
|
|
400
|
-
// calculate oustanding emissions
|
|
401
|
-
const emissionsOutstandingAndUnclaimed = (0, utils_1.calculateUnclaimedEmissions)(new anchor_1.BN(assetShares), new anchor_1.BN(liabilityShares), lastUpdate, emissionsOutstanding, bankData.flags, bankData.assetShareValue, bankData.liabilityShareValue, bankData.emissionsRate, bankData.emissionsRemaining, bankData.mintDecimals);
|
|
402
298
|
const lendingAccountBalance = (0, state_1.newClendAccountBalance)({
|
|
403
299
|
active,
|
|
404
300
|
bankPk: bank,
|
|
405
301
|
bankMint,
|
|
406
302
|
bankAssetTag: Number(balance.bankAssetTag),
|
|
407
|
-
assetShares,
|
|
303
|
+
assetShares: Number((0, utils_1.wrappedI80F48toBigNumber)(balance.assetShares)),
|
|
408
304
|
assetShareValue: Number(bankData.assetShareValue),
|
|
409
305
|
assetMintDecimals: Number(bankData.mintDecimals),
|
|
410
|
-
liabilityShares,
|
|
306
|
+
liabilityShares: Number((0, utils_1.wrappedI80F48toBigNumber)(balance.liabilityShares)),
|
|
411
307
|
liabilityShareValue: Number(bankData.liabilityShareValue),
|
|
412
308
|
liabilityMintDecimals: Number(bankData.mintDecimals),
|
|
413
309
|
lastUpdate: new anchor_1.BN(balance.lastUpdate),
|
|
414
310
|
assetWeightMaint: Number(bankData.config.assetWeightMaint),
|
|
415
311
|
liabilityWeightMaint: Number(bankData.config.liabilityWeightMaint),
|
|
416
312
|
price,
|
|
417
|
-
emissionsOutstanding,
|
|
418
|
-
emissionsOutstandingAndUnclaimed,
|
|
419
313
|
});
|
|
420
314
|
balances.push(lendingAccountBalance);
|
|
421
315
|
healthFactorWeightedAssetArgs.push(lendingAccountBalance.assetWeightedMaintValue);
|
|
@@ -501,6 +395,13 @@ class ClendClient {
|
|
|
501
395
|
// get required remaining accounts based on account balance
|
|
502
396
|
const clendAccountData = await this.getClendAccount(clendAccount);
|
|
503
397
|
let clendAccountActiveBanks = (0, utils_1.getClendAccountActiveBanks)(clendAccountData);
|
|
398
|
+
//// If withdrawAll is true, remove the target bank from activeBanks
|
|
399
|
+
//// as we wont have a remaining balance after the withdraw operation
|
|
400
|
+
//if (withdrawAll === true) {
|
|
401
|
+
// clendAccountActiveBanks = clendAccountActiveBanks.filter(
|
|
402
|
+
// (b) => !b.equals(bank),
|
|
403
|
+
// );
|
|
404
|
+
//}
|
|
504
405
|
// fetch all active banks
|
|
505
406
|
const activeBankData = [];
|
|
506
407
|
for (const bank of clendAccountActiveBanks) {
|
|
@@ -535,7 +436,7 @@ class ClendClient {
|
|
|
535
436
|
const ix = await this.instructions.borrow(clendGroup, clendAccount, this.address(), bank, destinationTokenAccount, tokenProgram, amount, remainingAccounts);
|
|
536
437
|
return this.send([ix]);
|
|
537
438
|
}
|
|
538
|
-
async repay(clendGroup, clendAccount, mint, amount, repayAll
|
|
439
|
+
async repay(clendGroup, clendAccount, mint, amount, repayAll = null) {
|
|
539
440
|
const bank = (0, addresses_1.getBankPda)(clendGroup, mint);
|
|
540
441
|
// Get bank data to access the liquidityVault and mint
|
|
541
442
|
const bankData = await this.getBank(bank);
|
|
@@ -551,7 +452,7 @@ class ClendClient {
|
|
|
551
452
|
activeBankData.push(bankData);
|
|
552
453
|
}
|
|
553
454
|
const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
|
|
554
|
-
const ix = await this.instructions.repay(clendGroup, clendAccount, this.address(), bank, userTokenAccount, tokenProgram, amount, repayAll,
|
|
455
|
+
const ix = await this.instructions.repay(clendGroup, clendAccount, this.address(), bank, userTokenAccount, tokenProgram, amount, repayAll, remainingAccounts);
|
|
555
456
|
return this.send([ix]);
|
|
556
457
|
}
|
|
557
458
|
async editGlobalFeeState(clendGroup, newGlobalFeeWallet, newBankInitFlatSolFee, newProgramFeeFixed, newProgramFeeRate) {
|
|
@@ -655,10 +556,9 @@ class ClendClient {
|
|
|
655
556
|
* returns: instructions, luts, deposit amount (libaility token)
|
|
656
557
|
*/
|
|
657
558
|
async getLiquidateClendAccountIxns(liquidatorClendAccount, liquidateeClendAccount, assetBankData, liabBankData, targetOnChainMaintenanceHealthValue, slippageBps, swapperOverride) {
|
|
658
|
-
let activeSwapper = this.swapper;
|
|
659
559
|
// override swapper if provided
|
|
660
560
|
if (swapperOverride) {
|
|
661
|
-
|
|
561
|
+
this.swapper = swapperOverride;
|
|
662
562
|
}
|
|
663
563
|
utils_1.logger.info("Starting liquidation calculation", {
|
|
664
564
|
liquidatee: liquidateeClendAccount.authority.toString(),
|
|
@@ -779,8 +679,7 @@ class ClendClient {
|
|
|
779
679
|
// balance for the asset
|
|
780
680
|
const withdrawAssetIx = await this.instructions.withdraw(assetBankData.group, liquidatorClendAccount.key, liquidatorClendAccount.authority, assetBankData.key, liquidatorAssetAta, assetTokenProgram, finalAssetAmount, false, remainingAccounts);
|
|
781
681
|
// get a swap quote
|
|
782
|
-
const swapQuote = await
|
|
783
|
-
payer: liquidatorClendAccount.authority,
|
|
682
|
+
const swapQuote = await this.swapper.getQuote({
|
|
784
683
|
inputMint: assetBankData.mint,
|
|
785
684
|
inputMintDecimals: assetBankData.mintDecimals,
|
|
786
685
|
outputMint: liabBankData.mint,
|
|
@@ -796,7 +695,7 @@ class ClendClient {
|
|
|
796
695
|
outAmountMin: outAmountMin.toString(10),
|
|
797
696
|
});
|
|
798
697
|
// 5. Get Swap Instructions from Jupiter
|
|
799
|
-
const swapIxns = await
|
|
698
|
+
const swapIxns = await this.swapper.getSwapIxns(this.address(), swapQuote);
|
|
800
699
|
const ixns = [
|
|
801
700
|
depositIx, // deposit liability mint into liquidator clend account
|
|
802
701
|
liquidationIx, // liquidate liquidatee clend account
|
|
@@ -835,14 +734,9 @@ class ClendClient {
|
|
|
835
734
|
const ix = await this.instructions.configureBankOracleMaxAge(clendGroup, this.address(), bank, maxAge);
|
|
836
735
|
return this.send([ix]);
|
|
837
736
|
}
|
|
838
|
-
async
|
|
737
|
+
async configureBankOracle(bank, pythOracle, pythOracleFeed) {
|
|
839
738
|
const bankData = await this.getBank(bank);
|
|
840
|
-
const ix = await this.instructions.
|
|
841
|
-
return this.send([ix]);
|
|
842
|
-
}
|
|
843
|
-
async configureBankSBOracle(bank, pullFeedAccount) {
|
|
844
|
-
const bankData = await this.getBank(bank);
|
|
845
|
-
const ix = await this.instructions.configureBankSwitchboardOracle(bankData.group, this.address(), bank, pullFeedAccount);
|
|
739
|
+
const ix = await this.instructions.configureBankOracle(bankData.group, this.address(), bank, pythOracle, pythOracleFeed);
|
|
846
740
|
return this.send([ix]);
|
|
847
741
|
}
|
|
848
742
|
async setBankOperationalState(clendGroup, bank, operationalState) {
|
|
@@ -855,7 +749,7 @@ class ClendClient {
|
|
|
855
749
|
let additionalSigners = [];
|
|
856
750
|
switch (selectedMint.toString()) {
|
|
857
751
|
case collateralMint.toString():
|
|
858
|
-
const collateralParams = await this.getDepositLeverageFromCollateralParams(clendGroup, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps);
|
|
752
|
+
const collateralParams = await this.getDepositLeverageFromCollateralParams(clendGroup, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps, swapperOverride);
|
|
859
753
|
const { ixns: collateralIxns, luts: collateralLuts, additionalSigners: collateralAdditionalSigners, } = await this.getDepositLeverageFromCollateralIxns(clendGroup, this.address(), clendAccount, collateralMint, debtMint, collateralParams.collateralBankData.mintDecimals, collateralParams.debtBankData.mintDecimals, collateralParams.borrowAmount, depositAmount, slippageBps, 0, swapperOverride);
|
|
860
754
|
ixns = collateralIxns;
|
|
861
755
|
luts = collateralLuts;
|
|
@@ -878,9 +772,8 @@ class ClendClient {
|
|
|
878
772
|
debtMintDecimals, collateralMintDecimals, initialUserDebtContributionForSwap, finalLoopBorrowAmount, slippageBps, additionalIxnCount, // For JIT liquidity, etc.
|
|
879
773
|
swapperOverride) {
|
|
880
774
|
// override swapper if provided
|
|
881
|
-
let activeSwapper = this.swapper;
|
|
882
775
|
if (swapperOverride) {
|
|
883
|
-
|
|
776
|
+
this.swapper = swapperOverride;
|
|
884
777
|
}
|
|
885
778
|
const collateralTokenProgram = (0, utils_1.getTokenProgramForMint)(collateralMint);
|
|
886
779
|
const debtTokenProgram = (0, utils_1.getTokenProgramForMint)(debtMint);
|
|
@@ -921,8 +814,7 @@ class ClendClient {
|
|
|
921
814
|
const totalDebtTokenForSwap = initialUserDebtContributionForSwap.add(finalLoopBorrowAmount);
|
|
922
815
|
// 3. Get Jupiter Quote for the TOTAL debt token amount
|
|
923
816
|
const swapMode = "ExactIn";
|
|
924
|
-
const swapQuote = await
|
|
925
|
-
payer: user,
|
|
817
|
+
const swapQuote = await this.swapper.getQuote({
|
|
926
818
|
inputMint: debtMint,
|
|
927
819
|
inputMintDecimals: debtMintDecimals,
|
|
928
820
|
outputMint: collateralMint,
|
|
@@ -944,7 +836,7 @@ class ClendClient {
|
|
|
944
836
|
const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, user, true, debtTokenProgram);
|
|
945
837
|
const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, user, true, collateralTokenProgram);
|
|
946
838
|
// 5. Get Swap Instructions from Jupiter
|
|
947
|
-
const swapIxns = await
|
|
839
|
+
const swapIxns = await this.swapper.getSwapIxns(user, swapQuote);
|
|
948
840
|
// 6. Create Clend Protocol Instructions
|
|
949
841
|
const borrowIx = await this.instructions.borrow(clendGroup, clendAccount, // clendAccount is guaranteed to be non-null here
|
|
950
842
|
user, debtBank, userDebtAta, // Borrow into user's ATA
|
|
@@ -993,9 +885,8 @@ class ClendClient {
|
|
|
993
885
|
async getDepositLeverageFromCollateralIxns(clendGroup, user, clendAccount, collateralMint, debtMint, debtMintDecimals, collateralMintDecimals, borrowAmount, depositAmount, slippageBps, additionalIxnCount, // used to correctly offset the flash loan index
|
|
994
886
|
swapperOverride) {
|
|
995
887
|
// override swapper if provided
|
|
996
|
-
let activeSwapper = this.swapper;
|
|
997
888
|
if (swapperOverride) {
|
|
998
|
-
|
|
889
|
+
this.swapper = swapperOverride;
|
|
999
890
|
}
|
|
1000
891
|
// Get token programs
|
|
1001
892
|
const collateralTokenProgram = (0, utils_1.getTokenProgramForMint)(collateralMint);
|
|
@@ -1004,8 +895,7 @@ class ClendClient {
|
|
|
1004
895
|
const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
|
|
1005
896
|
// Get Jupiter quote for swapping debt token to collateral token
|
|
1006
897
|
const swapMode = "ExactIn";
|
|
1007
|
-
const swapQuote = await
|
|
1008
|
-
payer: user,
|
|
898
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1009
899
|
inputMint: debtMint,
|
|
1010
900
|
inputMintDecimals: debtMintDecimals,
|
|
1011
901
|
outputMint: collateralMint,
|
|
@@ -1056,7 +946,7 @@ class ClendClient {
|
|
|
1056
946
|
}
|
|
1057
947
|
const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
|
|
1058
948
|
// Get swap instructions
|
|
1059
|
-
const swapIxns = await
|
|
949
|
+
const swapIxns = await this.swapper.getSwapIxns(user, swapQuote);
|
|
1060
950
|
// Calculate additional collateral from swap
|
|
1061
951
|
const additionalCollateralAmount = swapQuote.outAmount;
|
|
1062
952
|
const totalCollateralAmount = depositAmount.add(additionalCollateralAmount);
|
|
@@ -1101,7 +991,11 @@ class ClendClient {
|
|
|
1101
991
|
additionalSigners,
|
|
1102
992
|
};
|
|
1103
993
|
}
|
|
1104
|
-
async getDepositLeverageFromCollateralParams(clendGroup, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps) {
|
|
994
|
+
async getDepositLeverageFromCollateralParams(clendGroup, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps, swapperOverride) {
|
|
995
|
+
// override swapper if provided
|
|
996
|
+
if (swapperOverride) {
|
|
997
|
+
this.swapper = swapperOverride;
|
|
998
|
+
}
|
|
1105
999
|
// Get decimals
|
|
1106
1000
|
const collateralDecimals = (0, utils_1.getTokenDecimalsForMint)(collateralMint);
|
|
1107
1001
|
const debtDecimals = (0, utils_1.getTokenDecimalsForMint)(debtMint);
|
|
@@ -1174,9 +1068,8 @@ class ClendClient {
|
|
|
1174
1068
|
initialUserDebtContributionForSwap, // User's initial DEBT token for the swap
|
|
1175
1069
|
targetLeverage, slippageBps, swapperOverride) {
|
|
1176
1070
|
// override swapper if provided
|
|
1177
|
-
let activeSwapper = this.swapper;
|
|
1178
1071
|
if (swapperOverride) {
|
|
1179
|
-
|
|
1072
|
+
this.swapper = swapperOverride;
|
|
1180
1073
|
}
|
|
1181
1074
|
// 1. Get decimals and bank data
|
|
1182
1075
|
const collateralDecimals = (0, utils_1.getTokenDecimalsForMint)(collateralMint);
|
|
@@ -1208,8 +1101,7 @@ class ClendClient {
|
|
|
1208
1101
|
// This is the user's initial contribution + what's borrowed from the protocol
|
|
1209
1102
|
const totalDebtTokenForSwap = initialUserDebtContributionForSwap.add(finalLoopBorrowAmount);
|
|
1210
1103
|
// 7. Calculate Expected COLLATERAL Output from swapping the total DEBT token amount
|
|
1211
|
-
const swapQuote = await
|
|
1212
|
-
payer: anchor_1.web3.PublicKey.default, // doesnt matter right now
|
|
1104
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1213
1105
|
inputMint: debtMint,
|
|
1214
1106
|
inputMintDecimals: debtDecimals,
|
|
1215
1107
|
outputMint: collateralMint,
|
|
@@ -1253,14 +1145,14 @@ class ClendClient {
|
|
|
1253
1145
|
let luts = [];
|
|
1254
1146
|
switch (selectedMint.toString()) {
|
|
1255
1147
|
case collateralMint.toString():
|
|
1256
|
-
const collateralParams = await this.getNetWithdrawLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll);
|
|
1257
|
-
const { ixns: collateralIxns, luts: collateralLuts } = await this.getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralParams.collateralBankData.mintDecimals, collateralParams.debtBankData.mintDecimals, withdrawAll, collateralParams.
|
|
1148
|
+
const collateralParams = await this.getNetWithdrawLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll, slippageBps, swapperOverride);
|
|
1149
|
+
const { ixns: collateralIxns, luts: collateralLuts } = await this.getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralParams.collateralBankData.mintDecimals, collateralParams.debtBankData.mintDecimals, withdrawAll, collateralParams.debtToRepay, collateralParams.collateralToWithdraw, slippageBps, 0, swapperOverride);
|
|
1258
1150
|
ixns = collateralIxns;
|
|
1259
1151
|
luts = collateralLuts;
|
|
1260
1152
|
break;
|
|
1261
1153
|
case debtMint.toString():
|
|
1262
|
-
const debtParams = await this.getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll, swapperOverride);
|
|
1263
|
-
const { ixns: debtIxns, luts: debtLuts } = await this.getWithdrawLeverageDebtIxns(clendGroup, clendAccount, collateralMint, debtMint, debtParams.collateralBankData.mintDecimals, debtParams.debtBankData.mintDecimals, withdrawAll, debtParams.debtToRepay, debtParams.collateralToWithdraw, slippageBps, 0, swapperOverride);
|
|
1154
|
+
const debtParams = await this.getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll, slippageBps, swapperOverride);
|
|
1155
|
+
const { ixns: debtIxns, luts: debtLuts } = await this.getWithdrawLeverageDebtIxns(clendGroup, clendAccount, collateralMint, debtMint, debtParams.collateralBankData.mintDecimals, debtParams.debtBankData.mintDecimals, withdrawAll, debtParams.debtToRepay, debtParams.collateralToWithdraw, withdrawAmount, slippageBps, 0, swapperOverride);
|
|
1264
1156
|
ixns = debtIxns;
|
|
1265
1157
|
luts = debtLuts;
|
|
1266
1158
|
break;
|
|
@@ -1270,98 +1162,75 @@ class ClendClient {
|
|
|
1270
1162
|
// Send transaction
|
|
1271
1163
|
return this.send(ixns, [], luts);
|
|
1272
1164
|
}
|
|
1273
|
-
async
|
|
1165
|
+
async getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride) {
|
|
1274
1166
|
// override swapper if provided
|
|
1275
|
-
let activeSwapper = this.swapper;
|
|
1276
1167
|
if (swapperOverride) {
|
|
1277
|
-
|
|
1168
|
+
this.swapper = swapperOverride;
|
|
1278
1169
|
}
|
|
1279
1170
|
const debtBank = (0, addresses_1.getBankPda)(clendGroup, debtMint);
|
|
1280
1171
|
const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
|
|
1172
|
+
// Get remaining accounts for flash loan
|
|
1281
1173
|
const clendAccountData = await this.getClendAccount(clendAccount);
|
|
1282
1174
|
if (!clendAccountData) {
|
|
1283
1175
|
throw new Error(`Clend account not found: ${clendAccount.toString()}`);
|
|
1284
1176
|
}
|
|
1285
1177
|
let activeBanks = (0, utils_1.getClendAccountActiveBanks)(clendAccountData);
|
|
1286
|
-
const activeBankData =
|
|
1178
|
+
const activeBankData = [];
|
|
1179
|
+
for (const bank of activeBanks) {
|
|
1180
|
+
const bankData = await this.getBank(bank);
|
|
1181
|
+
activeBankData.push(bankData);
|
|
1182
|
+
}
|
|
1287
1183
|
const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
|
|
1288
|
-
// Get
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1184
|
+
// Get Jupiter quote for swapping collateral to debt token (ExactOut mode)
|
|
1185
|
+
const swapMode = "ExactOut";
|
|
1186
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1291
1187
|
inputMint: collateralMint,
|
|
1292
1188
|
inputMintDecimals: collateralDecimals,
|
|
1293
1189
|
outputMint: debtMint,
|
|
1294
1190
|
outputMintDecimals: debtDecimals,
|
|
1295
|
-
inputAmount:
|
|
1191
|
+
inputAmount: debtToRepay,
|
|
1296
1192
|
slippageBps,
|
|
1297
|
-
swapMode
|
|
1193
|
+
swapMode,
|
|
1298
1194
|
});
|
|
1299
|
-
//
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
utils_1.logger.debug("getWithdrawLeverageDebtIxns: swap and repay details", {
|
|
1304
|
-
collateralToWithdraw: collateralToWithdraw.toString(),
|
|
1305
|
-
minDebtReceivedFromSwap: minDebtReceivedFromSwap.toString(),
|
|
1306
|
-
targetDebtToRepay: debtToRepay.toString(),
|
|
1307
|
-
finalDebtToRepay: finalDebtToRepay.toString(),
|
|
1195
|
+
// set collateralToSwap to the inAmount from the swap quote
|
|
1196
|
+
const collateralToSwap = swapQuote.inAmount;
|
|
1197
|
+
utils_1.logger.debug("withdrawLeverage collateralToSwap", {
|
|
1198
|
+
collateralToSwap,
|
|
1308
1199
|
});
|
|
1309
|
-
// Get
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1200
|
+
// Get swap instructions
|
|
1201
|
+
const swapInputs = {
|
|
1202
|
+
inputAmountLamports: new decimal_js_1.default(collateralToSwap.toString()),
|
|
1203
|
+
inputMint: collateralMint,
|
|
1204
|
+
outputMint: debtMint,
|
|
1205
|
+
};
|
|
1206
|
+
utils_1.logger.debug("withdrawLeverage swapInputs", {
|
|
1207
|
+
swapInputs,
|
|
1208
|
+
});
|
|
1209
|
+
const swapIxns = await this.swapper.getSwapIxns(clendAccountData.authority, swapQuote);
|
|
1210
|
+
utils_1.logger.info(`swapIxns fetched`);
|
|
1313
1211
|
const collateralTokenProgram = (0, utils_1.getTokenProgramForMint)(collateralMint);
|
|
1314
1212
|
const debtTokenProgram = (0, utils_1.getTokenProgramForMint)(debtMint);
|
|
1315
1213
|
const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, clendAccountData.authority, true, collateralTokenProgram);
|
|
1316
1214
|
const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, clendAccountData.authority, true, debtTokenProgram);
|
|
1317
|
-
|
|
1215
|
+
utils_1.logger.info(`begin crafting ixns`);
|
|
1216
|
+
// Create withdraw instruction
|
|
1318
1217
|
const withdrawIx = await this.instructions.withdraw(clendGroup, clendAccount, clendAccountData.authority, collateralBank, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
if (!collateralBankData) {
|
|
1325
|
-
throw new Error(`Collateral bank not found: ${collateralMint.toString()}`);
|
|
1326
|
-
}
|
|
1327
|
-
const debtBankData = activeBankData.find((b) => b.mint.equals(debtMint));
|
|
1328
|
-
if (!debtBankData) {
|
|
1329
|
-
throw new Error(`Debt bank not found: ${debtMint.toString()}`);
|
|
1330
|
-
}
|
|
1331
|
-
// collateral bank emissions
|
|
1332
|
-
if (!collateralBankData.emissionsMint.equals(anchor_1.web3.PublicKey.default) &&
|
|
1333
|
-
(collateralBankData.flags === state_1.BankFlags.LendingEmissionsActive ||
|
|
1334
|
-
collateralBankData.flags ===
|
|
1335
|
-
state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
|
|
1336
|
-
const emissionsMint = collateralBankData.emissionsMint;
|
|
1337
|
-
const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
|
|
1338
|
-
const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, collateralBank, emissionsMint, emissionsMintTokenProgram);
|
|
1339
|
-
emissionsIxns.push(...withdrawEmissionsIx);
|
|
1340
|
-
}
|
|
1341
|
-
// debt bank emissions
|
|
1342
|
-
if (!debtBankData.emissionsMint.equals(anchor_1.web3.PublicKey.default) &&
|
|
1343
|
-
(debtBankData.flags === state_1.BankFlags.BorrowEmissionsActive ||
|
|
1344
|
-
debtBankData.flags === state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
|
|
1345
|
-
const emissionsMint = debtBankData.emissionsMint;
|
|
1346
|
-
const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
|
|
1347
|
-
const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, debtBank, emissionsMint, emissionsMintTokenProgram);
|
|
1348
|
-
emissionsIxns.push(...withdrawEmissionsIx);
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
// Create repay instruction: Repay the debt portion using the guaranteed swap output
|
|
1352
|
-
const repayIx = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, userDebtAta, debtTokenProgram, finalDebtToRepay, // Use the slippage-protected amount from the final quote
|
|
1353
|
-
withdrawAll, true, remainingAccounts);
|
|
1354
|
-
// Assemble instructions
|
|
1218
|
+
utils_1.logger.info(`withdrawIx set`);
|
|
1219
|
+
// Create repay instruction
|
|
1220
|
+
const repayIx = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, userDebtAta, debtTokenProgram, debtToRepay, withdrawAll, remainingAccounts);
|
|
1221
|
+
utils_1.logger.info(`repayIx set`);
|
|
1222
|
+
// Assemble all instructions without flash loan
|
|
1355
1223
|
const ixnsWithoutFlashLoan = [
|
|
1356
|
-
...emissionsIxns,
|
|
1357
1224
|
withdrawIx,
|
|
1358
1225
|
...swapIxns.ixns,
|
|
1359
1226
|
repayIx,
|
|
1360
1227
|
];
|
|
1361
|
-
|
|
1228
|
+
utils_1.logger.info(`ixnsWithoutFlashLoan set`);
|
|
1229
|
+
// Create flash loan instructions
|
|
1362
1230
|
const cuIxns = 2;
|
|
1363
1231
|
const endIndex = new anchor_1.BN(cuIxns + ixnsWithoutFlashLoan.length + 1 + additionalIxnCount);
|
|
1364
1232
|
const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, clendAccountData.authority, endIndex, remainingAccounts);
|
|
1233
|
+
// Assemble all instructions in the correct order
|
|
1365
1234
|
const instructions = [
|
|
1366
1235
|
beginFlashLoanIx,
|
|
1367
1236
|
...ixnsWithoutFlashLoan,
|
|
@@ -1369,13 +1238,92 @@ class ClendClient {
|
|
|
1369
1238
|
];
|
|
1370
1239
|
return { ixns: instructions, luts: swapIxns.luts };
|
|
1371
1240
|
}
|
|
1372
|
-
async
|
|
1373
|
-
|
|
1241
|
+
async getWithdrawLeverageDebtIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, debtToRepay, collateralToWithdraw, desiredNetDebtToReceive, slippageBps, additionalIxnCount, swapperOverride) {
|
|
1242
|
+
// override swapper if provided
|
|
1243
|
+
if (swapperOverride) {
|
|
1244
|
+
this.swapper = swapperOverride;
|
|
1245
|
+
}
|
|
1246
|
+
const debtBank = (0, addresses_1.getBankPda)(clendGroup, debtMint);
|
|
1247
|
+
const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
|
|
1248
|
+
const clendAccountData = await this.getClendAccount(clendAccount);
|
|
1249
|
+
if (!clendAccountData) {
|
|
1250
|
+
throw new Error(`Clend account not found: ${clendAccount.toString()}`);
|
|
1251
|
+
}
|
|
1252
|
+
let activeBanks = (0, utils_1.getClendAccountActiveBanks)(clendAccountData);
|
|
1253
|
+
//if (withdrawAll) {
|
|
1254
|
+
// activeBanks = activeBanks.filter(
|
|
1255
|
+
// (b) => !b.equals(collateralBank) && !b.equals(debtBank),
|
|
1256
|
+
// );
|
|
1257
|
+
//}
|
|
1258
|
+
const activeBankData = await Promise.all(activeBanks.map((bankPk) => this.getBank(bankPk)));
|
|
1259
|
+
const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
|
|
1260
|
+
// 1. Determine Total USDC Needed from the Swap
|
|
1261
|
+
// This is the amount needed to repay Clend's debt AND give the user their desired net withdrawal.
|
|
1262
|
+
const totalDebtToReceive = debtToRepay.add(desiredNetDebtToReceive);
|
|
1263
|
+
const swapMode = "ExactIn";
|
|
1264
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1265
|
+
inputMint: collateralMint,
|
|
1266
|
+
inputMintDecimals: collateralDecimals,
|
|
1267
|
+
outputMint: debtMint,
|
|
1268
|
+
outputMintDecimals: debtDecimals,
|
|
1269
|
+
inputAmount: collateralToWithdraw,
|
|
1270
|
+
slippageBps,
|
|
1271
|
+
swapMode,
|
|
1272
|
+
});
|
|
1273
|
+
const minUsdcReceivedFromSwap_BN = new anchor_1.BN(swapQuote.otherAmountThreshold);
|
|
1274
|
+
utils_1.logger.debug("getWithdrawLeverageDebtIxns: collateral and debt details", {
|
|
1275
|
+
debtToRepay: debtToRepay.toString(),
|
|
1276
|
+
desiredNetDebtToReceive: desiredNetDebtToReceive.toString(),
|
|
1277
|
+
totalDebtToReceive: totalDebtToReceive.toString(),
|
|
1278
|
+
minUsdcReceivedFromSwap_BN: minUsdcReceivedFromSwap_BN.toString(),
|
|
1279
|
+
});
|
|
1280
|
+
// 3. Get Swap Instructions from swapper
|
|
1281
|
+
const swapIxns = await this.swapper.getSwapIxns(clendAccountData.authority, swapQuote);
|
|
1282
|
+
utils_1.logger.info(`swapIxns fetched for ReceiveDebtToken`);
|
|
1283
|
+
// --- ATAs and Clend Instructions (largely similar structure) ---
|
|
1284
|
+
const collateralTokenProgram = (0, utils_1.getTokenProgramForMint)(collateralMint);
|
|
1285
|
+
const debtTokenProgram = (0, utils_1.getTokenProgramForMint)(debtMint);
|
|
1286
|
+
const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, clendAccountData.authority, true, collateralTokenProgram);
|
|
1287
|
+
const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, clendAccountData.authority, true, debtTokenProgram);
|
|
1288
|
+
// Create withdraw instruction: Withdraw ALL the JLP calculated by params function
|
|
1289
|
+
const withdrawIx = await this.instructions.withdraw(clendGroup, clendAccount, clendAccountData.authority, collateralBank, userCollateralAta, collateralTokenProgram, collateralToWithdraw, // Withdraw all the JLP needed for the full swap
|
|
1290
|
+
withdrawAll, // This flag is for Clend's internal logic
|
|
1291
|
+
remainingAccounts);
|
|
1292
|
+
// Create repay instruction: Repay the calculated debt portion to Clend
|
|
1293
|
+
const repayIx = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, userDebtAta, debtTokenProgram, debtToRepay, // Repay the specified debt amount
|
|
1294
|
+
withdrawAll, // This flag is for Clend's internal logic
|
|
1295
|
+
remainingAccounts);
|
|
1296
|
+
// Assemble instructions
|
|
1297
|
+
const ixnsWithoutFlashLoan = [
|
|
1298
|
+
withdrawIx,
|
|
1299
|
+
...swapIxns.ixns, // Swap all withdrawn collateral to debt
|
|
1300
|
+
repayIx, // Repay the debt portion
|
|
1301
|
+
]; // User is left with the remaining debt in their ATA
|
|
1302
|
+
// Flash Loan Wrapping (same as before)
|
|
1303
|
+
const cuIxns = 2;
|
|
1304
|
+
const endIndex = new anchor_1.BN(cuIxns + ixnsWithoutFlashLoan.length + 1 + additionalIxnCount);
|
|
1305
|
+
const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, clendAccountData.authority, endIndex, remainingAccounts);
|
|
1306
|
+
const instructions = [
|
|
1307
|
+
beginFlashLoanIx,
|
|
1308
|
+
...ixnsWithoutFlashLoan,
|
|
1309
|
+
endFlashLoanIx,
|
|
1310
|
+
];
|
|
1311
|
+
return { ixns: instructions, luts: swapIxns.luts };
|
|
1312
|
+
}
|
|
1313
|
+
// caller will receive desiredNetWithdraw, the position will be adjusted accordingly
|
|
1314
|
+
// receive the collateral mint
|
|
1315
|
+
async getNetWithdrawLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, desiredNetWithdraw, withdrawAll, slippageBps, swapperOverride) {
|
|
1316
|
+
// override swapper if provided
|
|
1317
|
+
if (swapperOverride) {
|
|
1318
|
+
this.swapper = swapperOverride;
|
|
1319
|
+
}
|
|
1320
|
+
utils_1.logger.info("getNetWithdrawParams", {
|
|
1374
1321
|
desiredNetWithdraw: desiredNetWithdraw.toString(),
|
|
1375
1322
|
withdrawAll,
|
|
1376
1323
|
});
|
|
1324
|
+
// if desiredNetWithdraw is zero, throw an error
|
|
1377
1325
|
if (desiredNetWithdraw.isZero() && !withdrawAll) {
|
|
1378
|
-
throw new Error("Desired net withdrawal is zero
|
|
1326
|
+
throw new Error("Desired net withdrawal is zero");
|
|
1379
1327
|
}
|
|
1380
1328
|
const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
|
|
1381
1329
|
const debtBank = (0, addresses_1.getBankPda)(clendGroup, debtMint);
|
|
@@ -1387,6 +1335,7 @@ class ClendClient {
|
|
|
1387
1335
|
if (!clendAccountData) {
|
|
1388
1336
|
throw new Error(`Clend account not found: ${clendAccount.toString()}`);
|
|
1389
1337
|
}
|
|
1338
|
+
// fetch balances and pricing
|
|
1390
1339
|
let debtBalance;
|
|
1391
1340
|
let debtPrice;
|
|
1392
1341
|
let collateralBalance;
|
|
@@ -1405,32 +1354,75 @@ class ClendClient {
|
|
|
1405
1354
|
throw new Error("Could not find debt or collateral position in account");
|
|
1406
1355
|
}
|
|
1407
1356
|
const collateralAmount = collateralBalance.assetBalance;
|
|
1408
|
-
const
|
|
1357
|
+
const collateralAmountUI = collateralBalance.assetBalanceUi;
|
|
1358
|
+
const collateralValue = collateralBalance.assetValue;
|
|
1409
1359
|
const collateralDecimals = collateralBankData.mintDecimals;
|
|
1360
|
+
const debtAmount = debtBalance.liabilityBalance;
|
|
1361
|
+
const debtAmountUI = debtBalance.liabilityBalanceUi;
|
|
1362
|
+
const debtValue = debtBalance.liabilityValue;
|
|
1410
1363
|
const debtDecimals = debtBankData.mintDecimals;
|
|
1364
|
+
const desiredNetWithdrawUi = (0, clend_common_1.amountToUi)(desiredNetWithdraw, debtDecimals);
|
|
1365
|
+
utils_1.logger.debug("Current amounts", {
|
|
1366
|
+
desiredNetWithdrawUi,
|
|
1367
|
+
collateralAmount: collateralAmount.toString(),
|
|
1368
|
+
collateralAmountUI,
|
|
1369
|
+
collateralValue,
|
|
1370
|
+
debtAmount: debtAmount.toString(),
|
|
1371
|
+
debtAmountUI,
|
|
1372
|
+
debtValue,
|
|
1373
|
+
});
|
|
1374
|
+
// --- Determine collateral to withdraw and debt to repay ---
|
|
1411
1375
|
let collateralToWithdraw;
|
|
1412
1376
|
let debtToRepay;
|
|
1413
1377
|
if (withdrawAll) {
|
|
1414
1378
|
utils_1.logger.info("WithdrawAll selected");
|
|
1415
1379
|
collateralToWithdraw = collateralAmount;
|
|
1416
|
-
debtToRepay = (0, clend_common_1.calculateLiabilityInterest)(debtBalance.liabilityShares, debtBankData.liabilityShareValue, debtBankData.borrowApy, debtBankData.lastUpdate.toNumber(),
|
|
1380
|
+
debtToRepay = (0, clend_common_1.calculateLiabilityInterest)(debtBalance.liabilityShares, debtBankData.liabilityShareValue, debtBankData.borrowApy, debtBankData.lastUpdate.toNumber(), new Date().getTime() / 1000);
|
|
1381
|
+
utils_1.logger.info(`calculated debt to repay`, {
|
|
1382
|
+
debtToRepayWithInterest: debtToRepay.toString(),
|
|
1383
|
+
debtToRepayRaw: debtAmount.toString(),
|
|
1384
|
+
});
|
|
1417
1385
|
}
|
|
1418
1386
|
else {
|
|
1419
|
-
utils_1.logger.info("Calculating partial deleverage
|
|
1387
|
+
utils_1.logger.info("Calculating partial deleverage for net withdrawal");
|
|
1388
|
+
// 1. Calculate estimated current debt accurately
|
|
1420
1389
|
const estimatedCurrentDebt = (0, clend_common_1.calculateLiabilityInterest)(debtBalance.liabilityShares, debtBankData.liabilityShareValue, debtBankData.borrowApy, debtBankData.lastUpdate.toNumber(), Math.floor(Date.now() / 1000));
|
|
1421
1390
|
const estimatedCurrentDebtUi = (0, clend_common_1.amountToUi)(estimatedCurrentDebt, debtDecimals);
|
|
1422
1391
|
const collateralAmountUI = (0, clend_common_1.amountToUi)(collateralAmount, collateralDecimals);
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1425
|
-
|
|
1392
|
+
const { debtToRepayUi, totalCollateralToWithdrawUi, newLeverage, currentLeverage, } = (0, clend_common_1.computeWithdrawLeverageAmounts)(collateralAmountUI, estimatedCurrentDebtUi, desiredNetWithdrawUi, collateralPrice, debtPrice);
|
|
1393
|
+
utils_1.logger.info("computeWithdrawLeverageAmounts", {
|
|
1394
|
+
debtToRepayUi,
|
|
1395
|
+
totalCollateralToWithdrawUi,
|
|
1396
|
+
newLeverage,
|
|
1397
|
+
currentLeverage,
|
|
1398
|
+
});
|
|
1426
1399
|
const baseDebtToRepay = (0, clend_common_1.uiToAmount)(debtToRepayUi, debtDecimals);
|
|
1400
|
+
// --- Step 5: Add Buffers to the Debt Repayment Target ---
|
|
1401
|
+
// This adds a small buffer for interest that might accrue during the transaction's execution time.
|
|
1427
1402
|
const timeBufferSec = 15;
|
|
1428
1403
|
debtToRepay = (0, clend_common_1.addInterestAccrualBuffer)(baseDebtToRepay, debtBankData.borrowApy, timeBufferSec);
|
|
1404
|
+
// --- Step 6: Get a Jupiter Quote for the Swap ---
|
|
1405
|
+
// Query Jupiter for an EXACT_OUT swap to find out exactly how much collateral
|
|
1406
|
+
// is needed to get the final amount of debt we need to repay.
|
|
1407
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1408
|
+
inputMint: collateralMint,
|
|
1409
|
+
inputMintDecimals: collateralDecimals,
|
|
1410
|
+
outputMint: debtMint,
|
|
1411
|
+
outputMintDecimals: debtDecimals,
|
|
1412
|
+
inputAmount: debtToRepay,
|
|
1413
|
+
slippageBps,
|
|
1414
|
+
swapMode: "ExactOut",
|
|
1415
|
+
});
|
|
1416
|
+
const collateralNeededForSwap = new anchor_1.BN(swapQuote.inAmount);
|
|
1417
|
+
// --- Step 7: Calculate the Final Total Collateral to Withdraw ---
|
|
1418
|
+
// This is the sum of what the user gets (desiredNetWithdraw) and what the swap needs.
|
|
1419
|
+
collateralToWithdraw = desiredNetWithdraw.add(collateralNeededForSwap);
|
|
1420
|
+
// Final sanity check to ensure we don't try to withdraw more than exists.
|
|
1429
1421
|
if (collateralToWithdraw.gt(collateralAmount)) {
|
|
1430
|
-
throw new Error("Total required collateral for withdrawal exceeds the available balance.");
|
|
1422
|
+
throw new Error("Total required collateral for withdrawal and swap exceeds the available balance. The position may be too leveraged for this withdrawal amount.");
|
|
1431
1423
|
}
|
|
1432
1424
|
}
|
|
1433
|
-
utils_1.logger.debug("Final calculated amounts
|
|
1425
|
+
utils_1.logger.debug("Final calculated amounts", {
|
|
1434
1426
|
collateralToWithdraw: collateralToWithdraw.toString(),
|
|
1435
1427
|
debtToRepay: debtToRepay.toString(),
|
|
1436
1428
|
});
|
|
@@ -1441,84 +1433,12 @@ class ClendClient {
|
|
|
1441
1433
|
debtBankData,
|
|
1442
1434
|
};
|
|
1443
1435
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
if (swapperOverride) {
|
|
1448
|
-
activeSwapper = swapperOverride;
|
|
1449
|
-
}
|
|
1450
|
-
const debtBank = (0, addresses_1.getBankPda)(clendGroup, debtMint);
|
|
1451
|
-
const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
|
|
1452
|
-
const clendAccountData = await this.getClendAccount(clendAccount);
|
|
1453
|
-
if (!clendAccountData) {
|
|
1454
|
-
throw new Error(`Clend account not found: ${clendAccount.toString()}`);
|
|
1455
|
-
}
|
|
1456
|
-
let activeBanks = (0, utils_1.getClendAccountActiveBanks)(clendAccountData);
|
|
1457
|
-
const activeBankData = [];
|
|
1458
|
-
for (const bank of activeBanks) {
|
|
1459
|
-
const bankData = await this.getBank(bank);
|
|
1460
|
-
activeBankData.push(bankData);
|
|
1461
|
-
}
|
|
1462
|
-
const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
|
|
1463
|
-
// 1. Determine the amount of collateral that needs to be swapped.
|
|
1464
|
-
const collateralToSwap = collateralToWithdraw.sub(desiredNetCollateralToReceive);
|
|
1465
|
-
// Safety check
|
|
1466
|
-
if (collateralToSwap.isNeg() || collateralToSwap.isZero()) {
|
|
1467
|
-
throw new Error(`Invalid calculation: collateral to swap is not positive. Total withdraw: ${collateralToWithdraw}, user receives: ${desiredNetCollateralToReceive}. Collateral to swap: ${collateralToSwap}`);
|
|
1468
|
-
}
|
|
1469
|
-
// 2. Get a fresh 'ExactIn' quote for swapping that collateral amount.
|
|
1470
|
-
const swapQuote = await activeSwapper.getQuote({
|
|
1471
|
-
payer: clendAccountData.authority,
|
|
1472
|
-
inputMint: collateralMint,
|
|
1473
|
-
inputMintDecimals: collateralDecimals,
|
|
1474
|
-
outputMint: debtMint,
|
|
1475
|
-
outputMintDecimals: debtDecimals,
|
|
1476
|
-
inputAmount: collateralToSwap, // This is our exact input
|
|
1477
|
-
slippageBps,
|
|
1478
|
-
swapMode: "ExactIn",
|
|
1479
|
-
});
|
|
1480
|
-
// 3. The final amount to repay is the minimum we are guaranteed to get from the swap.
|
|
1481
|
-
const finalDebtToRepay = new anchor_1.BN(swapQuote.otherAmountThreshold);
|
|
1482
|
-
const swapIxns = await activeSwapper.getSwapIxns(swapQuote);
|
|
1483
|
-
utils_1.logger.info(`swapIxns fetched`);
|
|
1484
|
-
const collateralTokenProgram = (0, utils_1.getTokenProgramForMint)(collateralMint);
|
|
1485
|
-
const debtTokenProgram = (0, utils_1.getTokenProgramForMint)(debtMint);
|
|
1486
|
-
const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, clendAccountData.authority, true, collateralTokenProgram);
|
|
1487
|
-
const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, clendAccountData.authority, true, debtTokenProgram);
|
|
1488
|
-
utils_1.logger.info(`begin crafting ixns`);
|
|
1489
|
-
const withdrawIx = await this.instructions.withdraw(clendGroup, clendAccount, clendAccountData.authority, collateralBank, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
|
|
1490
|
-
utils_1.logger.info(`withdrawIx set`);
|
|
1491
|
-
const emissionsIxns = [];
|
|
1492
|
-
if (withdrawAll) {
|
|
1493
|
-
// ... (emission logic remains the same)
|
|
1494
|
-
}
|
|
1495
|
-
// Create repay instruction with the amount from the 'ExactIn' swap
|
|
1496
|
-
const repayIx = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, userDebtAta, debtTokenProgram, finalDebtToRepay, // Use the slippage-protected amount from the final quote
|
|
1497
|
-
withdrawAll, true, // Use the new repay_up_to_amount flag
|
|
1498
|
-
remainingAccounts);
|
|
1499
|
-
utils_1.logger.info(`repayIx set`);
|
|
1500
|
-
const ixnsWithoutFlashLoan = [
|
|
1501
|
-
...emissionsIxns,
|
|
1502
|
-
withdrawIx,
|
|
1503
|
-
...swapIxns.ixns,
|
|
1504
|
-
repayIx,
|
|
1505
|
-
];
|
|
1506
|
-
utils_1.logger.info(`ixnsWithoutFlashLoan set`);
|
|
1507
|
-
const cuIxns = 2;
|
|
1508
|
-
const endIndex = new anchor_1.BN(cuIxns + ixnsWithoutFlashLoan.length + 1 + additionalIxnCount);
|
|
1509
|
-
const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, clendAccountData.authority, endIndex, remainingAccounts);
|
|
1510
|
-
const instructions = [
|
|
1511
|
-
beginFlashLoanIx,
|
|
1512
|
-
...ixnsWithoutFlashLoan,
|
|
1513
|
-
endFlashLoanIx,
|
|
1514
|
-
];
|
|
1515
|
-
return { ixns: instructions, luts: swapIxns.luts };
|
|
1516
|
-
}
|
|
1517
|
-
async getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, desiredNetWithdraw, withdrawAll, swapperOverride) {
|
|
1436
|
+
// caller will receive desiredNetWithdraw, the position will be adjusted accordingly
|
|
1437
|
+
// receive the debt mint
|
|
1438
|
+
async getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, desiredNetWithdraw, withdrawAll, slippageBps, swapperOverride) {
|
|
1518
1439
|
// override swapper if provided
|
|
1519
|
-
let activeSwapper = this.swapper;
|
|
1520
1440
|
if (swapperOverride) {
|
|
1521
|
-
|
|
1441
|
+
this.swapper = swapperOverride;
|
|
1522
1442
|
}
|
|
1523
1443
|
utils_1.logger.info("getNetWithdrawDebtParams", {
|
|
1524
1444
|
desiredNetWithdraw: desiredNetWithdraw.toString(),
|
|
@@ -1565,31 +1485,52 @@ class ClendClient {
|
|
|
1565
1485
|
let debtToRepay;
|
|
1566
1486
|
if (withdrawAll) {
|
|
1567
1487
|
utils_1.logger.info("WithdrawAll selected for receiving debt token");
|
|
1568
|
-
collateralToWithdraw = collateralAmount; // All
|
|
1488
|
+
collateralToWithdraw = collateralAmount; // All JLP will be swapped
|
|
1569
1489
|
debtToRepay = (0, clend_common_1.calculateLiabilityInterest)(currentDebtBalance.liabilityShares, debtBankData.liabilityShareValue, debtBankData.borrowApy, debtBankData.lastUpdate.toNumber(), Math.floor(Date.now() / 1000));
|
|
1570
|
-
utils_1.logger.info(`calculated debt to repay
|
|
1490
|
+
utils_1.logger.info(`calculated debt to repay`, {
|
|
1571
1491
|
debtToRepayWithInterest: debtToRepay.toString(),
|
|
1492
|
+
debtToRepayRaw: debtAmount.toString(),
|
|
1572
1493
|
});
|
|
1573
1494
|
}
|
|
1574
1495
|
else {
|
|
1575
|
-
utils_1.logger.info("Calculating partial deleverage for receiving debt token
|
|
1496
|
+
utils_1.logger.info("Calculating partial deleverage for receiving debt token");
|
|
1576
1497
|
// 1. Calculate estimated current debt accurately
|
|
1577
1498
|
const estimatedCurrentDebt = (0, clend_common_1.calculateLiabilityInterest)(currentDebtBalance.liabilityShares, debtBankData.liabilityShareValue, debtBankData.borrowApy, debtBankData.lastUpdate.toNumber(), Math.floor(Date.now() / 1000));
|
|
1578
1499
|
const estimatedCurrentDebtUi = (0, clend_common_1.amountToUi)(estimatedCurrentDebt, debtDecimals);
|
|
1579
1500
|
const collateralAmountUI = (0, clend_common_1.amountToUi)(collateralAmount, collateralDecimals);
|
|
1580
1501
|
const desiredNetWithdrawalOfDebtUi = (0, clend_common_1.amountToUi)(desiredNetWithdraw, debtDecimals);
|
|
1581
|
-
//
|
|
1502
|
+
// Convert the value of the desired debt withdrawal into an equivalent amount of collateral
|
|
1503
|
+
// This is the "collateral-equivalent" value of the equity being removed.
|
|
1582
1504
|
const netWithdrawAmountInCollateralUi = (0, clend_common_1.calculateWeightedValue)(desiredNetWithdrawalOfDebtUi, debtPrice, 1) /
|
|
1583
1505
|
collateralPrice;
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1506
|
+
const { debtToRepayUi, totalCollateralToWithdrawUi, newLeverage, currentLeverage, } = (0, clend_common_1.computeWithdrawLeverageAmounts)(collateralAmountUI, estimatedCurrentDebtUi, netWithdrawAmountInCollateralUi, collateralPrice, debtPrice);
|
|
1507
|
+
utils_1.logger.info("computeWithdrawLeverageAmounts", {
|
|
1508
|
+
debtToRepayUi,
|
|
1509
|
+
totalCollateralToWithdrawUi,
|
|
1510
|
+
newLeverage,
|
|
1511
|
+
currentLeverage,
|
|
1512
|
+
});
|
|
1589
1513
|
const baseDebtToRepay = (0, clend_common_1.uiToAmount)(debtToRepayUi, debtDecimals);
|
|
1514
|
+
// --- Step 5: Add Buffers to the Debt Repayment Target ---
|
|
1515
|
+
// This adds a small buffer for interest that might accrue during the transaction's execution time.
|
|
1590
1516
|
const timeBufferSec = 15;
|
|
1591
1517
|
debtToRepay = (0, clend_common_1.addInterestAccrualBuffer)(baseDebtToRepay, debtBankData.borrowApy, timeBufferSec);
|
|
1592
|
-
//
|
|
1518
|
+
// --- Step 2: Determine total USDC needed from the swap ---
|
|
1519
|
+
// The total value we need to get from selling JLP is the debt we must repay
|
|
1520
|
+
const totalDebtNeededFromSwap = debtToRepay.add(desiredNetWithdraw);
|
|
1521
|
+
// Now, find how much collateral is needed to produce this swap via swap
|
|
1522
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1523
|
+
inputMint: collateralMint,
|
|
1524
|
+
inputMintDecimals: collateralDecimals,
|
|
1525
|
+
outputMint: debtMint,
|
|
1526
|
+
outputMintDecimals: debtDecimals,
|
|
1527
|
+
inputAmount: totalDebtNeededFromSwap,
|
|
1528
|
+
slippageBps,
|
|
1529
|
+
swapMode: "ExactOut",
|
|
1530
|
+
});
|
|
1531
|
+
// The answer from swapper is the total collateral we must withdraw.
|
|
1532
|
+
collateralToWithdraw = swapQuote.inAmount;
|
|
1533
|
+
// --- Step 4: Final Sanity Check ---
|
|
1593
1534
|
if (collateralToWithdraw.gt(collateralAmount)) {
|
|
1594
1535
|
throw new Error("Total required collateral for withdrawal and swap exceeds the available balance.");
|
|
1595
1536
|
}
|
|
@@ -1751,7 +1692,7 @@ class ClendClient {
|
|
|
1751
1692
|
finalDebtToRepayTargetBN: finalDebtToRepayTargetBN.toString(),
|
|
1752
1693
|
finalAdjustedDebtDeltaUi: finalDebtDeltaUi,
|
|
1753
1694
|
});
|
|
1754
|
-
// 3. Recalculate Collateral Delta needed for the swap
|
|
1695
|
+
// 3. Recalculate Collateral Delta needed for the swap (ExactOut)
|
|
1755
1696
|
const slippageFactor = new decimal_js_1.default(slippageBps).div(10000);
|
|
1756
1697
|
if (slippageFactor.gte(1)) {
|
|
1757
1698
|
throw new Error("Slippage cannot be 100% or more.");
|
|
@@ -1817,9 +1758,8 @@ class ClendClient {
|
|
|
1817
1758
|
finalCollateralDeltaUi, // Use the final adjusted value from getAdjustLeverageParams
|
|
1818
1759
|
slippageBps, additionalIxnCount, swapperOverride) {
|
|
1819
1760
|
// override swapper if provided
|
|
1820
|
-
let activeSwapper = this.swapper;
|
|
1821
1761
|
if (swapperOverride) {
|
|
1822
|
-
|
|
1762
|
+
this.swapper = swapperOverride;
|
|
1823
1763
|
}
|
|
1824
1764
|
const clendAccountData = await this.getClendAccount(clendAccount);
|
|
1825
1765
|
if (!clendAccountData) {
|
|
@@ -1849,60 +1789,90 @@ class ClendClient {
|
|
|
1849
1789
|
let swapLookupTables = [];
|
|
1850
1790
|
if (isIncrease) {
|
|
1851
1791
|
utils_1.logger.info("Building instructions for increasing leverage");
|
|
1852
|
-
//
|
|
1792
|
+
// Use the finalDebtDeltaUi passed in (already adjusted)
|
|
1853
1793
|
const additionalDebtAmount = (0, clend_common_1.uiToAmount)(finalDebtDeltaUi, debtBankData.mintDecimals);
|
|
1854
|
-
|
|
1855
|
-
|
|
1794
|
+
utils_1.logger.debug("additionalDebtAmount to borrow (final adjusted)", {
|
|
1795
|
+
additionalDebtAmount: additionalDebtAmount.toString(),
|
|
1796
|
+
});
|
|
1797
|
+
// Get Jupiter quote for swapping debt token to collateral token (ExactIn)
|
|
1798
|
+
const swapMode = "ExactIn";
|
|
1799
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1856
1800
|
inputMint: debtBankData.mint,
|
|
1857
1801
|
inputMintDecimals: debtBankData.mintDecimals,
|
|
1858
1802
|
outputMint: collateralBankData.mint,
|
|
1859
1803
|
outputMintDecimals: collateralBankData.mintDecimals,
|
|
1860
1804
|
inputAmount: additionalDebtAmount,
|
|
1861
1805
|
slippageBps,
|
|
1862
|
-
swapMode
|
|
1806
|
+
swapMode,
|
|
1807
|
+
});
|
|
1808
|
+
utils_1.logger.debug("swapQuote calculated (Increase)", {
|
|
1809
|
+
inAmount: swapQuote.inAmount.toString(),
|
|
1810
|
+
outAmount: swapQuote.outAmount.toString(),
|
|
1811
|
+
otherAmountThreshold: swapQuote.otherAmountThreshold.toString(),
|
|
1863
1812
|
});
|
|
1864
|
-
|
|
1865
|
-
const
|
|
1813
|
+
// Get swap instructions
|
|
1814
|
+
const swapIxns = await this.swapper.getSwapIxns(user, swapQuote);
|
|
1815
|
+
// Borrow the final adjusted debt amount
|
|
1816
|
+
const borrowIx = await this.instructions.borrow(clendGroup, clendAccount, user, debtBankData.key, userDebtAta, debtTokenProgram, additionalDebtAmount, // Use final adjusted amount
|
|
1817
|
+
remainingAccounts);
|
|
1818
|
+
// Calculate additional collateral expected from swap (based on quote)
|
|
1866
1819
|
const additionalCollateralAmount = swapQuote.outAmount;
|
|
1867
|
-
|
|
1820
|
+
utils_1.logger.debug("additionalCollateralAmount expected from swap", {
|
|
1821
|
+
additionalCollateralAmount: additionalCollateralAmount.toString(),
|
|
1822
|
+
});
|
|
1823
|
+
// Deposit additional collateral received from swap
|
|
1824
|
+
const depositIx = await this.instructions.deposit(clendGroup, clendAccount, user, collateralBankData.key, userCollateralAta, collateralTokenProgram, additionalCollateralAmount, // Deposit what the swap provides
|
|
1825
|
+
true, remainingAccounts);
|
|
1868
1826
|
instructions.push(borrowIx, ...swapIxns.ixns, depositIx);
|
|
1869
1827
|
swapLookupTables = swapIxns.luts;
|
|
1870
1828
|
}
|
|
1871
1829
|
else {
|
|
1872
|
-
//
|
|
1830
|
+
// Decreasing Leverage
|
|
1873
1831
|
utils_1.logger.info("Building instructions for decreasing leverage");
|
|
1874
|
-
//
|
|
1875
|
-
const
|
|
1876
|
-
//
|
|
1877
|
-
const
|
|
1878
|
-
|
|
1832
|
+
// Use the finalDebtDeltaUi passed in (already includes future buffer)
|
|
1833
|
+
const finalDebtToRepayBN = (0, clend_common_1.uiToAmount)(finalDebtDeltaUi, debtBankData.mintDecimals);
|
|
1834
|
+
// Use the finalCollateralDeltaUi passed in (already includes slippage adjustment for swap)
|
|
1835
|
+
const finalCollateralToWithdrawBN = (0, clend_common_1.uiToAmount)(finalCollateralDeltaUi, collateralBankData.mintDecimals);
|
|
1836
|
+
utils_1.logger.debug("Final amounts for decrease operation (Native)", {
|
|
1837
|
+
finalDebtToRepayBN: finalDebtToRepayBN.toString(),
|
|
1838
|
+
finalCollateralToWithdrawBN: finalCollateralToWithdrawBN.toString(),
|
|
1839
|
+
});
|
|
1840
|
+
// Get Jupiter quote for swapping collateral token to debt token (ExactOut)
|
|
1841
|
+
// Target the final buffered debt repayment amount
|
|
1842
|
+
const swapMode = "ExactOut";
|
|
1843
|
+
const swapQuote = await this.swapper.getQuote({
|
|
1879
1844
|
inputMint: collateralBankData.mint,
|
|
1880
1845
|
inputMintDecimals: collateralBankData.mintDecimals,
|
|
1881
1846
|
outputMint: debtBankData.mint,
|
|
1882
1847
|
outputMintDecimals: debtBankData.mintDecimals,
|
|
1883
|
-
inputAmount:
|
|
1848
|
+
inputAmount: finalDebtToRepayBN,
|
|
1884
1849
|
slippageBps,
|
|
1885
|
-
swapMode
|
|
1850
|
+
swapMode,
|
|
1886
1851
|
});
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1852
|
+
const estimatedCollateralInput = swapQuote.inAmount;
|
|
1853
|
+
utils_1.logger.debug("swapQuote calculated (Decrease)", {
|
|
1854
|
+
targetOutput: finalDebtToRepayBN.toString(),
|
|
1855
|
+
estimatedInput: estimatedCollateralInput,
|
|
1856
|
+
maxInputCalculated: finalCollateralToWithdrawBN.toString(), // Compare Jupiter estimate vs our max calc
|
|
1857
|
+
});
|
|
1858
|
+
const swapIxns = await this.swapper.getSwapIxns(user, swapQuote);
|
|
1859
|
+
// Withdraw the CALCULATED MAXIMUM collateral needed (includes swap input + buffer)
|
|
1860
|
+
const withdrawIx = await this.instructions.withdraw(clendGroup, clendAccount, user, collateralBankData.key, userCollateralAta, collateralTokenProgram, finalCollateralToWithdrawBN, // Use the final adjusted amount from params
|
|
1861
|
+
false, // Not withdrawing all
|
|
1893
1862
|
remainingAccounts);
|
|
1894
|
-
// Repay the
|
|
1895
|
-
const repayIx = await this.instructions.repay(clendGroup, clendAccount, user, debtBankData.key, userDebtAta, debtTokenProgram,
|
|
1863
|
+
// Repay the CALCULATED BUFFERED debt amount
|
|
1864
|
+
const repayIx = await this.instructions.repay(clendGroup, clendAccount, user, debtBankData.key, userDebtAta, debtTokenProgram, finalDebtToRepayBN, // Use the final adjusted amount from params
|
|
1896
1865
|
false, // Not repaying all
|
|
1897
|
-
true, // Use the new repay_up_to_amount flag
|
|
1898
1866
|
remainingAccounts);
|
|
1899
1867
|
instructions.push(withdrawIx, ...swapIxns.ixns, repayIx);
|
|
1900
1868
|
swapLookupTables = swapIxns.luts;
|
|
1901
1869
|
}
|
|
1902
1870
|
// --- Flash Loan Wrapping ---
|
|
1903
|
-
const cuIxns = 2;
|
|
1871
|
+
const cuIxns = 2; // Assuming 2 compute budget instructions are added later
|
|
1872
|
+
// Calculate end index based on actual instructions generated + potential JIT ixns + flash loan ixns
|
|
1904
1873
|
const endIndex = new anchor_1.BN(cuIxns + instructions.length + 1 + additionalIxnCount);
|
|
1905
1874
|
const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, user, endIndex, remainingAccounts);
|
|
1875
|
+
// Create a new array with the flash loan instructions wrapping the existing instructions
|
|
1906
1876
|
const finalInstructions = [
|
|
1907
1877
|
beginFlashLoanIx,
|
|
1908
1878
|
...instructions,
|