@carrot-protocol/clend-rpc 0.1.78-handoff-dev-dd084f2 → 0.1.78-handoff-dev-928428e

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/rpc.js CHANGED
@@ -1497,37 +1497,30 @@ class ClendClient {
1497
1497
  /**
1498
1498
  * Generates instructions for the Handoff Deposit Leverage Flow.
1499
1499
  * Splitting the operation into two phases to bypass CPI restrictions for Squads/Multisigs.
1500
- *
1501
- * @param handoffSigner - The ephemeral keypair/signer that will execute the flash loan.
1502
- * @param jitIxns - Array of JIT liquidity instructions to be injected into the Exec Tx.
1503
- * @returns
1504
- * - setupIxns: User signed (Init Account, Deposit Capital, Transfer Auth to Handoff)
1505
- * - execIxns: Handoff signed (JIT, Flash Loan, Borrow, Swap, Deposit, Return Auth to User)
1506
1500
  */
1507
1501
  async getDepositLeverageHandoffIxns(clendGroup, user, handoffSigner, clendAccount, inputMint, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps, jitIxns = [], swapperOverride) {
1508
1502
  let activeSwapper = swapperOverride || this.swapper;
1509
1503
  const setupIxns = [];
1510
1504
  const execIxns = [];
1511
1505
  const setupSigners = [];
1512
- // 1. Clend Account Initialization (Setup Tx)
1506
+ // 1. Clend Account Initialization
1513
1507
  if (clendAccount === null) {
1514
1508
  const clendAccountSeed = (0, utils_1.randomU32)();
1515
1509
  const { ix, clendAccount: newAccount } = await this.instructions.initializeClendAccountWithSeed(clendGroup, user, clendAccountSeed);
1516
1510
  setupIxns.push(ix);
1517
1511
  clendAccount = newAccount;
1518
1512
  }
1519
- // 2. Fetch Banks & Decimals
1513
+ // 2. Fetch Data
1520
1514
  const debtBank = (0, addresses_1.getBankPda)(clendGroup, debtMint);
1521
1515
  const collateralBank = (0, addresses_1.getBankPda)(clendGroup, collateralMint);
1522
1516
  const inputBank = (0, addresses_1.getBankPda)(clendGroup, inputMint);
1523
- // We fetch these to get decimals and oracle data
1524
1517
  const [debtBankData, collateralBankData] = await this.getBanks([
1525
1518
  debtBank,
1526
1519
  collateralBank,
1527
1520
  ]);
1528
- // 3. Calculate Leverage Params & Swap Amounts
1521
+ // 3. Calculate Params
1529
1522
  let borrowAmount;
1530
- // We only deposit what we get from the swap in the loop, so we don't need totalDepositAmount here
1523
+ // NOTE: This logic mimics the "Standard" flow param calculation
1531
1524
  if (inputMint.equals(collateralMint)) {
1532
1525
  const p = await this.getDepositLeverageFromCollateralParams(user, clendGroup, collateralMint, debtMint, depositAmount, targetLeverage, slippageBps, activeSwapper);
1533
1526
  borrowAmount = p.borrowAmount;
@@ -1541,10 +1534,8 @@ class ClendClient {
1541
1534
  borrowAmount = p.borrowAmount;
1542
1535
  }
1543
1536
  // 4. Setup Transaction (User Signed)
1544
- // A. Deposit initial capital
1545
1537
  const inputTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, inputMint);
1546
1538
  const userInputAta = (0, spl_token_1.getAssociatedTokenAddressSync)(inputMint, user, true, inputTokenProgram);
1547
- // Fetch input bank data if it wasn't already fetched
1548
1539
  let inputBankData = debtBankData.mint.equals(inputMint)
1549
1540
  ? debtBankData
1550
1541
  : collateralBankData.mint.equals(inputMint)
@@ -1552,78 +1543,56 @@ class ClendClient {
1552
1543
  : await this.getBank(inputBank);
1553
1544
  const depositIxns = await this.instructions.deposit(clendGroup, clendAccount, user, inputBankData.key, inputBankData.mint, inputBankData.defaultOracle, userInputAta, inputTokenProgram, depositAmount, true);
1554
1545
  setupIxns.push(...depositIxns);
1555
- // B. Transfer Authority to Handoff Signer
1556
1546
  const transferAuthIx = await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, user, handoffSigner);
1557
1547
  setupIxns.push(transferAuthIx);
1558
1548
  // 5. Execution Transaction (Handoff Signed)
1559
- // A. Inject JIT Instructions (Pre-Flash Loan)
1560
- // These happen first to ensure liquidity is available before we try to borrow.
1561
1549
  if (jitIxns.length > 0) {
1562
1550
  execIxns.push(...jitIxns);
1563
1551
  }
1564
- // B. Prepare Handoff ATAs (Idempotent)
1565
1552
  const liabilityTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, debtMint);
1566
1553
  const assetTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, collateralMint);
1567
1554
  const handoffDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, handoffSigner, true, liabilityTokenProgram);
1568
1555
  const handoffCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, handoffSigner, true, assetTokenProgram);
1569
1556
  execIxns.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(handoffSigner, handoffDebtAta, handoffSigner, debtMint, liabilityTokenProgram), (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(handoffSigner, handoffCollateralAta, handoffSigner, collateralMint, assetTokenProgram));
1570
- // C. Construct Swap (Debt -> Collateral)
1571
- // We execute the swap *exactly* as calculated in the params step
1557
+ // --- FIX: Adjust Borrow Amount if Input == Debt ---
1558
+ let effectiveBorrowAmount = borrowAmount;
1559
+ if (inputMint.equals(debtMint)) {
1560
+ // If user deposited Debt token, we must borrow it back out to swap it.
1561
+ // Otherwise it just sits in the account reducing the liability.
1562
+ effectiveBorrowAmount = borrowAmount.add(depositAmount);
1563
+ }
1564
+ // --- Swap Calculation ---
1565
+ // The input to the swap is the TOTAL amount we have in the Handoff ATA.
1566
+ // If input==debt, this is (Borrow + Deposit).
1567
+ // If input==collateral, this is (Borrow). (Deposit is already collateral, stays in account).
1568
+ const swapInputAmount = effectiveBorrowAmount;
1572
1569
  const swapQuote = await activeSwapper.getQuote({
1573
1570
  payer: handoffSigner,
1574
1571
  inputMint: debtMint,
1575
1572
  inputMintDecimals: debtBankData.mintDecimals,
1576
1573
  outputMint: collateralMint,
1577
1574
  outputMintDecimals: collateralBankData.mintDecimals,
1578
- inputAmount: borrowAmount,
1575
+ inputAmount: swapInputAmount,
1579
1576
  slippageBps,
1580
1577
  swapMode: "ExactIn",
1581
1578
  });
1582
- // Use the quote output for the deposit amount to ensure strict consistency
1583
1579
  const collateralToDeposit = new anchor_1.BN(swapQuote.outAmount);
1584
1580
  const swapIxns = await activeSwapper.getSwapIxns(swapQuote);
1585
- // D. Construct Active Banks List for Remaining Accounts
1586
1581
  const activeBankList = [debtBankData, collateralBankData];
1587
1582
  if (!inputMint.equals(debtMint) && !inputMint.equals(collateralMint)) {
1588
1583
  activeBankList.push(inputBankData);
1589
1584
  }
1590
1585
  const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankList);
1591
- // E. Build Loop Instructions
1592
- // 1. Borrow Debt (to Handoff ATA)
1593
- const borrowIx = await this.instructions.borrow(clendGroup, clendAccount, handoffSigner, // Signer is Handoff
1594
- debtBankData.key, debtMint, handoffDebtAta, liabilityTokenProgram, borrowAmount, remainingAccounts);
1595
- // 2. Deposit Collateral (from Handoff ATA)
1596
- const loopDepositIx = await this.instructions.deposit(clendGroup, clendAccount, handoffSigner, // Signer is Handoff
1597
- collateralBankData.key, collateralMint, collateralBankData.defaultOracle, handoffCollateralAta, assetTokenProgram, collateralToDeposit, true);
1598
- // F. Wrap in Flash Loan
1586
+ const borrowIx = await this.instructions.borrow(clendGroup, clendAccount, handoffSigner, debtBankData.key, debtMint, handoffDebtAta, liabilityTokenProgram, effectiveBorrowAmount, // <--- Use adjusted amount
1587
+ remainingAccounts);
1588
+ const loopDepositIx = await this.instructions.deposit(clendGroup, clendAccount, handoffSigner, collateralBankData.key, collateralMint, collateralBankData.defaultOracle, handoffCollateralAta, assetTokenProgram, collateralToDeposit, true);
1599
1589
  const innerIxns = [...borrowIx, ...swapIxns.ixns, ...loopDepositIx];
1600
- // Calculate End Index for Flash Loan
1601
- // The index passed to StartFlashLoan is relative to the *entire* transaction instructions array.
1602
- //
1603
- // Preamble Instructions (Caller adds these):
1604
- // 1. Jito Tip (1)
1605
- // 2. Compute Budget Limit (1)
1606
- // 3. Compute Unit Price (1)
1607
- // Total Caller Preamble = 3
1608
- //
1609
- // Instructions added inside this function BEFORE StartFlashLoan:
1610
- // 1. JIT Instructions (jitIxns.length)
1611
- // 2. Create Handoff ATAs (2)
1612
- //
1613
- // Total Instructions before StartFlashLoan = 3 + jitIxns.length + 2
1614
- // StartFlashLoan Index = 5 + jitIxns.length
1615
- // Inner Instructions Start Index = 6 + jitIxns.length
1616
- // EndFlashLoan Index = StartFlashLoan Index + 1 + Inner Length
1617
- const callerPreambleCount = 3; // JitoTip + SetCuLimit + SetCuPrice
1618
- const localPreambleCount = jitIxns.length + 2; // JIT + CreateATAs(2)
1619
- // The instruction index for EndFlashLoan
1620
- // StartFlash is the *next* instruction we push after preamble
1590
+ const callerPreambleCount = 3;
1591
+ const localPreambleCount = jitIxns.length + 2;
1621
1592
  const startIndex = callerPreambleCount + localPreambleCount;
1622
- // endIndex = startIndex + 1 (StartFlash itself) + innerIxns.length
1623
1593
  const endIndex = new anchor_1.BN(startIndex + 1 + innerIxns.length);
1624
1594
  const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, handoffSigner, endIndex, (0, utils_1.getClendAccountRemainingAccounts)(activeBankList));
1625
1595
  execIxns.push(beginFlashLoanIx, ...innerIxns, endFlashLoanIx);
1626
- // G. Return Authority to User
1627
1596
  const returnAuthIx = await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, handoffSigner, user);
1628
1597
  execIxns.push(returnAuthIx);
1629
1598
  return {
@@ -2051,13 +2020,13 @@ class ClendClient {
2051
2020
  switch (selectedMint.toString()) {
2052
2021
  case collateralMint.toString():
2053
2022
  const collateralParams = await this.getNetWithdrawLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll);
2054
- const { ixns: collateralIxns, luts: collateralLuts } = await this.getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralParams.collateralBankData.mintDecimals, collateralParams.debtBankData.mintDecimals, withdrawAll, collateralParams.collateralToWithdraw, withdrawAmount, collateralParams.debtToRepay, slippageBps, 0, swapperOverride);
2023
+ const { ixns: collateralIxns, luts: collateralLuts } = await this.getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, this.address(), collateralMint, debtMint, collateralParams.collateralBankData.mintDecimals, collateralParams.debtBankData.mintDecimals, withdrawAll, collateralParams.collateralToWithdraw, withdrawAmount, collateralParams.debtToRepay, slippageBps, 0, swapperOverride);
2055
2024
  ixns = collateralIxns;
2056
2025
  luts = collateralLuts;
2057
2026
  break;
2058
2027
  case debtMint.toString():
2059
2028
  const debtParams = await this.getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll);
2060
- 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);
2029
+ const { ixns: debtIxns, luts: debtLuts } = await this.getWithdrawLeverageDebtIxns(clendGroup, clendAccount, this.address(), collateralMint, debtMint, debtParams.collateralBankData.mintDecimals, debtParams.debtBankData.mintDecimals, withdrawAll, debtParams.debtToRepay, debtParams.collateralToWithdraw, slippageBps, 0, swapperOverride);
2061
2030
  ixns = debtIxns;
2062
2031
  luts = debtLuts;
2063
2032
  break;
@@ -2067,7 +2036,7 @@ class ClendClient {
2067
2036
  // Send transaction
2068
2037
  return this.send(ixns, [], luts);
2069
2038
  }
2070
- async getWithdrawLeverageDebtIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride) {
2039
+ async getWithdrawLeverageDebtIxns(clendGroup, clendAccount, authority, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride) {
2071
2040
  // override swapper if provided
2072
2041
  let activeSwapper = this.swapper;
2073
2042
  if (swapperOverride) {
@@ -2084,7 +2053,7 @@ class ClendClient {
2084
2053
  const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
2085
2054
  // Get a fresh 'ExactIn' quote for swapping the total collateral to withdraw
2086
2055
  const swapQuote = await activeSwapper.getQuote({
2087
- payer: clendAccountData.authority,
2056
+ payer: authority,
2088
2057
  inputMint: collateralMint,
2089
2058
  inputMintDecimals: collateralDecimals,
2090
2059
  outputMint: debtMint,
@@ -2109,10 +2078,10 @@ class ClendClient {
2109
2078
  // --- ATAs and Clend Instructions ---
2110
2079
  const collateralTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, collateralMint);
2111
2080
  const debtTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, debtMint);
2112
- const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, clendAccountData.authority, true, collateralTokenProgram);
2113
- const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, clendAccountData.authority, true, debtTokenProgram);
2081
+ const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, authority, true, collateralTokenProgram);
2082
+ const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, authority, true, debtTokenProgram);
2114
2083
  // Create withdraw instruction: Withdraw the total collateral calculated by the params function
2115
- const withdrawIxns = await this.instructions.withdraw(clendGroup, clendAccount, clendAccountData.authority, collateralBank, collateralMint, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
2084
+ const withdrawIxns = await this.instructions.withdraw(clendGroup, clendAccount, authority, collateralBank, collateralMint, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
2116
2085
  // if withdrawAll == true we need to make sure we withdraw emissions from both banks before withdrawing all the bank tokens
2117
2086
  const emissionsIxns = [];
2118
2087
  if (withdrawAll) {
@@ -2132,7 +2101,7 @@ class ClendClient {
2132
2101
  state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
2133
2102
  const emissionsMint = collateralBankData.emissionsMint;
2134
2103
  const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
2135
- const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, collateralBank, emissionsMint, emissionsMintTokenProgram);
2104
+ const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, authority, collateralBank, emissionsMint, emissionsMintTokenProgram);
2136
2105
  emissionsIxns.push(...withdrawEmissionsIx);
2137
2106
  }
2138
2107
  // debt bank emissions
@@ -2141,12 +2110,12 @@ class ClendClient {
2141
2110
  debtBankData.flags === state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
2142
2111
  const emissionsMint = debtBankData.emissionsMint;
2143
2112
  const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
2144
- const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, debtBank, emissionsMint, emissionsMintTokenProgram);
2113
+ const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, authority, debtBank, emissionsMint, emissionsMintTokenProgram);
2145
2114
  emissionsIxns.push(...withdrawEmissionsIx);
2146
2115
  }
2147
2116
  }
2148
2117
  // Create repay instruction: Repay the debt portion using the guaranteed swap output
2149
- const repayIxns = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, debtMint, userDebtAta, debtTokenProgram, finalDebtToRepay, // Use the slippage-protected amount from the final quote
2118
+ const repayIxns = await this.instructions.repay(clendGroup, clendAccount, authority, debtBank, debtMint, userDebtAta, debtTokenProgram, finalDebtToRepay, // Use the slippage-protected amount from the final quote
2150
2119
  withdrawAll, true, remainingAccounts);
2151
2120
  // Assemble instructions
2152
2121
  const ixnsWithoutFlashLoan = [
@@ -2159,7 +2128,7 @@ class ClendClient {
2159
2128
  const cuIxns = 2;
2160
2129
  const endIndex = new anchor_1.BN(cuIxns + ixnsWithoutFlashLoan.length + 1 + additionalIxnCount);
2161
2130
  const remainingAccountsForFlashLoan = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
2162
- const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, clendAccountData.authority, endIndex, remainingAccountsForFlashLoan);
2131
+ const { beginFlashLoanIx, endFlashLoanIx } = await this.instructions.createFlashLoanInstructions(clendAccount, authority, endIndex, remainingAccountsForFlashLoan);
2163
2132
  const instructions = [
2164
2133
  beginFlashLoanIx,
2165
2134
  ...ixnsWithoutFlashLoan,
@@ -2241,7 +2210,7 @@ class ClendClient {
2241
2210
  debtBankData,
2242
2211
  };
2243
2212
  }
2244
- async getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, collateralToWithdraw, desiredNetCollateralToReceive, debtToRepay, slippageBps, additionalIxnCount, swapperOverride) {
2213
+ async getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, authority, collateralMint, debtMint, collateralDecimals, debtDecimals, withdrawAll, collateralToWithdraw, desiredNetCollateralToReceive, debtToRepay, slippageBps, additionalIxnCount, swapperOverride) {
2245
2214
  // override swapper if provided
2246
2215
  let activeSwapper = this.swapper;
2247
2216
  if (swapperOverride) {
@@ -2265,7 +2234,7 @@ class ClendClient {
2265
2234
  let collateralToSwap = collateralToWithdraw.sub(desiredNetCollateralToReceive);
2266
2235
  // again for partial withdraws
2267
2236
  let swapQuote = await activeSwapper.getQuote({
2268
- payer: clendAccountData.authority,
2237
+ payer: authority,
2269
2238
  inputMint: collateralMint,
2270
2239
  inputMintDecimals: collateralDecimals,
2271
2240
  outputMint: debtMint,
@@ -2278,7 +2247,7 @@ class ClendClient {
2278
2247
  // Step 1: Get the current price via a nominal 1-token quote.
2279
2248
  const oneToken = (0, clend_common_1.uiToAmount)(1, collateralDecimals);
2280
2249
  const nominalQuote = await activeSwapper.getQuote({
2281
- payer: clendAccountData.authority,
2250
+ payer: authority,
2282
2251
  inputMint: collateralMint,
2283
2252
  inputMintDecimals: collateralDecimals,
2284
2253
  outputMint: debtMint,
@@ -2295,7 +2264,7 @@ class ClendClient {
2295
2264
  collateralToSwap = (0, clend_common_1.adjustAmountForSlippage)(collateralToSwap_ideal, slippageBps);
2296
2265
  // Step 4 (Final Quote): Get the real quote for the buffered amount.
2297
2266
  swapQuote = await activeSwapper.getQuote({
2298
- payer: clendAccountData.authority,
2267
+ payer: authority,
2299
2268
  inputMint: collateralMint,
2300
2269
  inputMintDecimals: collateralDecimals,
2301
2270
  outputMint: debtMint,
@@ -2316,10 +2285,10 @@ class ClendClient {
2316
2285
  utils_1.logger.info(`swapIxns fetched`);
2317
2286
  const collateralTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, collateralMint);
2318
2287
  const debtTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, debtMint);
2319
- const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, clendAccountData.authority, true, collateralTokenProgram);
2320
- const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, clendAccountData.authority, true, debtTokenProgram);
2288
+ const userCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, authority, true, collateralTokenProgram);
2289
+ const userDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, authority, true, debtTokenProgram);
2321
2290
  utils_1.logger.info(`begin crafting ixns`);
2322
- const withdrawIxns = await this.instructions.withdraw(clendGroup, clendAccount, clendAccountData.authority, collateralBank, collateralMint, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
2291
+ const withdrawIxns = await this.instructions.withdraw(clendGroup, clendAccount, authority, collateralBank, collateralMint, userCollateralAta, collateralTokenProgram, collateralToWithdraw, withdrawAll, remainingAccounts);
2323
2292
  utils_1.logger.info(`withdrawIx set`);
2324
2293
  // if withdrawAll == true we need to make sure we withdraw emissions from both banks before withdrawing all the bank tokens
2325
2294
  const emissionsIxns = [];
@@ -2340,7 +2309,7 @@ class ClendClient {
2340
2309
  state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
2341
2310
  const emissionsMint = collateralBankData.emissionsMint;
2342
2311
  const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
2343
- const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, collateralBank, emissionsMint, emissionsMintTokenProgram);
2312
+ const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, authority, collateralBank, emissionsMint, emissionsMintTokenProgram);
2344
2313
  emissionsIxns.push(...withdrawEmissionsIx);
2345
2314
  }
2346
2315
  // debt bank emissions
@@ -2349,12 +2318,12 @@ class ClendClient {
2349
2318
  debtBankData.flags === state_1.BankFlags.LendingAndBorrowingEmissionsActive)) {
2350
2319
  const emissionsMint = debtBankData.emissionsMint;
2351
2320
  const emissionsMintTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, emissionsMint);
2352
- const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, clendAccountData.authority, debtBank, emissionsMint, emissionsMintTokenProgram);
2321
+ const withdrawEmissionsIx = await this.instructions.withdrawEmissions(clendGroup, clendAccount, authority, debtBank, emissionsMint, emissionsMintTokenProgram);
2353
2322
  emissionsIxns.push(...withdrawEmissionsIx);
2354
2323
  }
2355
2324
  }
2356
2325
  // Create repay instruction with the amount from the 'ExactIn' swap
2357
- const repayIxns = await this.instructions.repay(clendGroup, clendAccount, clendAccountData.authority, debtBank, debtMint, userDebtAta, debtTokenProgram, finalDebtToRepay, withdrawAll, true, remainingAccounts);
2326
+ const repayIxns = await this.instructions.repay(clendGroup, clendAccount, authority, debtBank, debtMint, userDebtAta, debtTokenProgram, finalDebtToRepay, withdrawAll, true, remainingAccounts);
2358
2327
  utils_1.logger.info(`repayIx set`);
2359
2328
  const ixnsWithoutFlashLoan = [
2360
2329
  ...emissionsIxns,
@@ -2569,7 +2538,7 @@ class ClendClient {
2569
2538
  fundingBankData,
2570
2539
  };
2571
2540
  }
2572
- async getWithdrawLeverageFundingIxns(clendGroup, clendAccount, collateralMint, debtMint, fundingMint, collateralDecimals, debtDecimals, fundingDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride) {
2541
+ async getWithdrawLeverageFundingIxns(clendGroup, clendAccount, authority, collateralMint, debtMint, fundingMint, collateralDecimals, debtDecimals, fundingDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride) {
2573
2542
  let activeSwapper = this.swapper;
2574
2543
  if (swapperOverride)
2575
2544
  activeSwapper = swapperOverride;
@@ -2579,7 +2548,6 @@ class ClendClient {
2579
2548
  if (!clendAccountData) {
2580
2549
  throw new Error(`Clend account not found: ${clendAccount.toString()}`);
2581
2550
  }
2582
- const authority = clendAccountData.authority;
2583
2551
  const activeBanks = (0, utils_1.getClendAccountActiveBanks)(clendAccountData);
2584
2552
  const activeBankData = await Promise.all(activeBanks.map((bankPk) => this.getBank(bankPk)));
2585
2553
  const remainingAccounts = (0, utils_1.getClendAccountRemainingAccounts)(activeBankData);
@@ -2753,6 +2721,135 @@ class ClendClient {
2753
2721
  }
2754
2722
  return { ixns: instructions, luts: dedupedLuts };
2755
2723
  }
2724
+ async getWithdrawLeverageHandoffIxns(clendGroup, clendAccount, user, handoffSigner, outputMint, collateralMint, debtMint, withdrawAmount, withdrawAll, slippageBps, swapperOverride) {
2725
+ // 1. Calculate Params & Identify Flow Type
2726
+ let debtToRepay;
2727
+ let collateralToWithdraw;
2728
+ let debtBankData;
2729
+ let collateralBankData;
2730
+ let flowType;
2731
+ let outputDecimals;
2732
+ if (outputMint.equals(collateralMint)) {
2733
+ flowType = "collateral";
2734
+ const p = await this.getNetWithdrawLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll);
2735
+ debtToRepay = p.debtToRepay;
2736
+ collateralToWithdraw = p.collateralToWithdraw;
2737
+ debtBankData = p.debtBankData;
2738
+ collateralBankData = p.collateralBankData;
2739
+ outputDecimals = collateralBankData.mintDecimals;
2740
+ }
2741
+ else if (outputMint.equals(debtMint)) {
2742
+ flowType = "debt";
2743
+ const p = await this.getNetWithdrawLeverageDebtParams(clendGroup, clendAccount, collateralMint, debtMint, withdrawAmount, withdrawAll);
2744
+ debtToRepay = p.debtToRepay;
2745
+ collateralToWithdraw = p.collateralToWithdraw;
2746
+ debtBankData = p.debtBankData;
2747
+ collateralBankData = p.collateralBankData;
2748
+ outputDecimals = debtBankData.mintDecimals;
2749
+ }
2750
+ else {
2751
+ flowType = "funding";
2752
+ const fundingMintDecimals = await (0, utils_1.getTokenDecimalsForMintFromRpc)(this.connection, outputMint);
2753
+ const p = await this.getNetWithdrawLeverageFundingParams(clendGroup, clendAccount, collateralMint, debtMint, outputMint, withdrawAmount, withdrawAll);
2754
+ debtToRepay = p.debtToRepay;
2755
+ collateralToWithdraw = p.collateralToWithdraw;
2756
+ debtBankData = p.debtBankData;
2757
+ collateralBankData = p.collateralBankData;
2758
+ outputDecimals = fundingMintDecimals;
2759
+ }
2760
+ // 2. Setup Transaction (User Signed)
2761
+ const setupIxns = [
2762
+ await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, user, handoffSigner),
2763
+ ];
2764
+ // 3. Execution Transaction (Handoff Signed)
2765
+ const execIxns = [];
2766
+ // A. Create Handoff ATAs
2767
+ // We need ATAs for Collateral and Debt (for the loop) and Output (to receive funds).
2768
+ const debtTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, debtMint);
2769
+ const collateralTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, collateralMint);
2770
+ const outputTokenProgram = await (0, utils_1.getTokenProgramForMintFromRpc)(this.connection, outputMint);
2771
+ const handoffDebtAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtMint, handoffSigner, true, debtTokenProgram);
2772
+ const handoffCollateralAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collateralMint, handoffSigner, true, collateralTokenProgram);
2773
+ //execIxns.push(
2774
+ // createAssociatedTokenAccountIdempotentInstruction(
2775
+ // handoffSigner,
2776
+ // handoffDebtAta,
2777
+ // handoffSigner,
2778
+ // debtMint,
2779
+ // debtTokenProgram,
2780
+ // ),
2781
+ // createAssociatedTokenAccountIdempotentInstruction(
2782
+ // handoffSigner,
2783
+ // handoffCollateralAta,
2784
+ // handoffSigner,
2785
+ // collateralMint,
2786
+ // collateralTokenProgram,
2787
+ // ),
2788
+ //);
2789
+ // If output is different from debt/collateral, create that ATA too
2790
+ let handoffOutputAta = handoffCollateralAta; // Default fallback
2791
+ if (flowType === "funding") {
2792
+ handoffOutputAta = (0, spl_token_1.getAssociatedTokenAddressSync)(outputMint, handoffSigner, true, outputTokenProgram);
2793
+ //execIxns.push(
2794
+ // createAssociatedTokenAccountIdempotentInstruction(
2795
+ // handoffSigner,
2796
+ // handoffOutputAta,
2797
+ // handoffSigner,
2798
+ // outputMint,
2799
+ // outputTokenProgram,
2800
+ // ),
2801
+ //);
2802
+ }
2803
+ else if (flowType === "debt") {
2804
+ handoffOutputAta = handoffDebtAta;
2805
+ }
2806
+ // B. Calculate Flash Loan Offset
2807
+ const additionalIxnCount = execIxns.length + 1;
2808
+ // C. Generate Inner Withdraw Logic
2809
+ let logicResult;
2810
+ if (flowType === "collateral") {
2811
+ logicResult = await this.getWithdrawLeverageCollateralIxns(clendGroup, clendAccount, handoffSigner, collateralMint, debtMint, collateralBankData.mintDecimals, debtBankData.mintDecimals, withdrawAll, collateralToWithdraw, withdrawAmount, debtToRepay, slippageBps, additionalIxnCount, swapperOverride);
2812
+ }
2813
+ else if (flowType === "debt") {
2814
+ logicResult = await this.getWithdrawLeverageDebtIxns(clendGroup, clendAccount, handoffSigner, collateralMint, debtMint, collateralBankData.mintDecimals, debtBankData.mintDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride);
2815
+ }
2816
+ else {
2817
+ const fundingMintDecimals = outputDecimals;
2818
+ logicResult = await this.getWithdrawLeverageFundingIxns(clendGroup, clendAccount, handoffSigner, collateralMint, debtMint, outputMint, collateralBankData.mintDecimals, debtBankData.mintDecimals, fundingMintDecimals, withdrawAll, debtToRepay, collateralToWithdraw, slippageBps, additionalIxnCount, swapperOverride);
2819
+ }
2820
+ execIxns.push(...logicResult.ixns);
2821
+ // D. Final Transfer: Handoff -> User
2822
+ // We simply transfer the calculated `withdrawAmount` back to the user.
2823
+ // If there is dust remaining (e.g. from favorable slippage), it stays in the ephemeral signer.
2824
+ // Ensure User ATA exists
2825
+ const userOutputAta = (0, spl_token_1.getAssociatedTokenAddressSync)(outputMint, user, true, outputTokenProgram);
2826
+ // 1. Calculate 99.7% of the amount (0.3% reduction)
2827
+ // We multiply by 997 and divide by 1000 to avoid floating point issues
2828
+ const safeTransferAmount = withdrawAmount
2829
+ .mul(new anchor_1.BN(997))
2830
+ .div(new anchor_1.BN(1000));
2831
+ utils_1.logger.info(`Adjusted transfer amount (0.1% buffer)`, {
2832
+ original: withdrawAmount.toString(),
2833
+ adjusted: safeTransferAmount.toString(),
2834
+ });
2835
+ // 2. Use the adjusted amount in your Instruction #12
2836
+ const transferIx = (0, spl_token_1.createTransferCheckedInstruction)(handoffOutputAta, // source (handoff)
2837
+ outputMint, // mint
2838
+ userOutputAta, // destination (user)
2839
+ handoffSigner, // owner
2840
+ BigInt(safeTransferAmount.toString()), // adjusted amount
2841
+ outputDecimals, // decimals
2842
+ [], outputTokenProgram);
2843
+ execIxns.push(transferIx);
2844
+ // E. Return Authority
2845
+ const returnAuthIx = await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, handoffSigner, user);
2846
+ execIxns.push(returnAuthIx);
2847
+ return {
2848
+ setupIxns,
2849
+ execIxns,
2850
+ luts: logicResult.luts,
2851
+ };
2852
+ }
2756
2853
  async getWithdrawToTargetLeverageCollateralParams(clendGroup, clendAccount, collateralMint, debtMint, desiredOutputAmount, // user-facing COLLATERAL amount
2757
2854
  targetLeverage) {
2758
2855
  utils_1.logger.info("getWithdrawToTargetLeverageCollateralParams", {
@@ -3167,7 +3264,7 @@ class ClendClient {
3167
3264
  const collateralToWithdrawBN = (0, clend_common_1.uiToAmount)(finalCollateralDeltaUi, collateralBankData.mintDecimals);
3168
3265
  // 2. Get a fresh 'ExactIn' quote for swapping that collateral amount.
3169
3266
  const swapQuote = await activeSwapper.getQuote({
3170
- payer: clendAccountData.authority,
3267
+ payer: user,
3171
3268
  inputMint: collateralBankData.mint,
3172
3269
  inputMintDecimals: collateralBankData.mintDecimals,
3173
3270
  outputMint: debtBankData.mint,
@@ -3203,6 +3300,86 @@ class ClendClient {
3203
3300
  ];
3204
3301
  return { ixns: finalInstructions, luts: swapLookupTables };
3205
3302
  }
3303
+ async getAdjustLeverageHandoffIxns(clendGroup, clendAccount, user, handoffSigner, collateralMint, debtMint, targetLeverage, slippageBps, jitIxns = [], swapperOverride) {
3304
+ // 1. Calculate Params using existing logic
3305
+ // We pass the Handoff Signer as the user here just for param calculation context if needed,
3306
+ // though getAdjustLeverageParams mainly checks on-chain state.
3307
+ const params = await this.getAdjustLeverageParams(clendGroup, clendAccount, collateralMint, debtMint, targetLeverage, slippageBps);
3308
+ utils_1.logger.debug("AdjustLeverageParams", params);
3309
+ const { debtBankData, collateralBankData, isIncrease, finalDebtDeltaUi, finalCollateralDeltaUi, } = params;
3310
+ // 2. Setup Transaction (User Signed)
3311
+ // Just transfer authority to the Handoff Signer
3312
+ const transferAuthIx = await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, user, handoffSigner);
3313
+ const setupIxns = [transferAuthIx];
3314
+ // 3. Execution Transaction (Handoff Signed)
3315
+ const execIxns = [];
3316
+ // A. Inject JIT Instructions (Only for Increase Leverage)
3317
+ // JIT fetches liquidity *before* we borrow.
3318
+ if (isIncrease && jitIxns.length > 0) {
3319
+ execIxns.push(...jitIxns);
3320
+ }
3321
+ // B. Create Handoff ATAs
3322
+ // The Handoff signer needs ATAs to hold funds temporarily during the Swap/FlashLoan.
3323
+ //const debtTokenProgram = await getTokenProgramForMintFromRpc(
3324
+ // this.connection,
3325
+ // debtMint,
3326
+ //);
3327
+ //const collateralTokenProgram = await getTokenProgramForMintFromRpc(
3328
+ // this.connection,
3329
+ // collateralMint,
3330
+ //);
3331
+ //const handoffDebtAta = getAssociatedTokenAddressSync(
3332
+ // debtMint,
3333
+ // handoffSigner,
3334
+ // true,
3335
+ // debtTokenProgram,
3336
+ //);
3337
+ //const handoffCollateralAta = getAssociatedTokenAddressSync(
3338
+ // collateralMint,
3339
+ // handoffSigner,
3340
+ // true,
3341
+ // collateralTokenProgram,
3342
+ //);
3343
+ //const createHandoffDebtAtaIx =
3344
+ // createAssociatedTokenAccountIdempotentInstruction(
3345
+ // handoffSigner,
3346
+ // handoffDebtAta,
3347
+ // handoffSigner,
3348
+ // debtMint,
3349
+ // debtTokenProgram,
3350
+ // );
3351
+ //const createHandoffCollateralAtaIx =
3352
+ // createAssociatedTokenAccountIdempotentInstruction(
3353
+ // handoffSigner,
3354
+ // handoffCollateralAta,
3355
+ // handoffSigner,
3356
+ // collateralMint,
3357
+ // collateralTokenProgram,
3358
+ // );
3359
+ //execIxns.push(createHandoffDebtAtaIx, createHandoffCollateralAtaIx);
3360
+ // C. Calculate Flash Loan Index Offset
3361
+ // The inner logic (getAdjustLeverageIxns) needs to know exactly where the Flash Loan instruction starts
3362
+ // relative to the *entire* bundle to calculate the EndFlashLoan index correctly.
3363
+ // Preamble: JitoTip(1) + ComputeLimit(1) + ComputePrice(1) = 3
3364
+ // Local Preamble: JIT Instructions + 2 ATA Creations
3365
+ const callerPreamble = 1;
3366
+ const additionalIxnCount = callerPreamble + jitIxns.length; // +2 for the ATAs added above
3367
+ // D. Generate Inner Logic
3368
+ // We pass `handoffSigner` as the `user` so the inner logic builds instructions utilizing the Handoff's ATAs/Auth.
3369
+ const { ixns: leverageIxns, luts } = await this.getAdjustLeverageIxns(clendGroup, clendAccount, handoffSigner, // <--- Handoff is the actor here
3370
+ debtBankData, collateralBankData, isIncrease, finalDebtDeltaUi, finalCollateralDeltaUi, slippageBps, additionalIxnCount, // <--- Pass the calculated offset
3371
+ swapperOverride);
3372
+ execIxns.push(...leverageIxns);
3373
+ // E. Return Authority to User
3374
+ // This must happen after the flash loan is closed (which is inside leverageIxns)
3375
+ const returnAuthIx = await this.instructions.setNewAccountAuthority(clendGroup, clendAccount, handoffSigner, user);
3376
+ execIxns.push(returnAuthIx);
3377
+ return {
3378
+ setupIxns,
3379
+ execIxns,
3380
+ luts,
3381
+ };
3382
+ }
3206
3383
  async handleBankruptcy(clendAccount, bank) {
3207
3384
  const bankState = await this.getBank(bank);
3208
3385
  if (!bankState) {
@@ -3225,9 +3402,19 @@ class ClendClient {
3225
3402
  if (!clendAccountState) {
3226
3403
  throw new Error(`Clend account not found: ${clendAccount.toString()}`);
3227
3404
  }
3405
+ console.log("Clend account state: ", clendAccountState);
3228
3406
  const ix = await this.instructions.setNewAccountAuthority(clendAccountState.group, clendAccount, clendAccountState.authority, newAuthority);
3229
3407
  return this.send([ix]);
3230
3408
  }
3409
+ async takeoverAccount(clendAccount, newAuthority) {
3410
+ const clendAccountState = await this.getClendAccount(clendAccount);
3411
+ if (!clendAccountState) {
3412
+ throw new Error(`Clend account not found: ${clendAccount.toString()}`);
3413
+ }
3414
+ const groupState = await this.getClendGroup(clendAccountState.group);
3415
+ const ix = await this.instructions.takeoverAccount(clendAccountState.group, groupState.admin, clendAccount, newAuthority);
3416
+ return this.send([ix]);
3417
+ }
3231
3418
  async getAccountsForAuthority(group, authority) {
3232
3419
  const accounts = await this.instructions.program.account.clendAccount.all([
3233
3420
  {