@0dotxyz/p0-ts-sdk 2.2.0-alpha.4 → 2.2.0-alpha.5

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/index.js CHANGED
@@ -10,6 +10,8 @@ import { Buffer as Buffer$1 } from 'buffer';
10
10
  import { deserialize } from 'borsh';
11
11
  import * as borsh from '@coral-xyz/borsh';
12
12
  import { struct as struct$1, bool as bool$1, publicKey as publicKey$1, array as array$1, u64 as u64$1, u8 as u8$1, u32 as u32$1, u128 } from '@coral-xyz/borsh';
13
+ import WebSocket from 'ws';
14
+ import { Encoder, Decoder } from '@msgpack/msgpack';
13
15
  import { SwapApi, Configuration, createJupiterApiClient } from '@jup-ag/api';
14
16
  import { AnchorUtils, PullFeed } from '@switchboard-xyz/on-demand';
15
17
  import { CrossbarClient } from '@switchboard-xyz/common';
@@ -91,10 +93,14 @@ function getConfig(environment = "production", overrides) {
91
93
  var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCode2) => {
92
94
  TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_REPAY"] = "JUPITER_SWAP_SIZE_EXCEEDED_REPAY";
93
95
  TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_LOOP"] = "JUPITER_SWAP_SIZE_EXCEEDED_LOOP";
96
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_LOOP"] = "SWAP_SIZE_EXCEEDED_LOOP";
97
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_REPAY"] = "SWAP_SIZE_EXCEEDED_REPAY";
94
98
  TransactionBuildingErrorCode2["ORACLE_CRANK_FAILED"] = "ORACLE_CRANK_FAILED";
95
99
  TransactionBuildingErrorCode2["KAMINO_RESERVE_NOT_FOUND"] = "KAMINO_RESERVE_NOT_FOUND";
96
100
  TransactionBuildingErrorCode2["DRIFT_STATE_NOT_FOUND"] = "DRIFT_STATE_NOT_FOUND";
97
101
  TransactionBuildingErrorCode2["JUPLEND_STATE_NOT_FOUND"] = "JUPLEND_STATE_NOT_FOUND";
102
+ TransactionBuildingErrorCode2["SWITCHBOARD_FEED_UPDATE_FAILED"] = "SWITCHBOARD_FEED_UPDATE_FAILED";
103
+ TransactionBuildingErrorCode2["SWAP_QUOTE_FAILED"] = "SWAP_QUOTE_FAILED";
98
104
  return TransactionBuildingErrorCode2;
99
105
  })(TransactionBuildingErrorCode || {});
100
106
  var TransactionBuildingError = class _TransactionBuildingError extends Error {
@@ -126,6 +132,20 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
126
132
  { bytes, accountKeys }
127
133
  );
128
134
  }
135
+ static swapSizeExceededLoop(bytes, accountKeys, provider) {
136
+ return new _TransactionBuildingError(
137
+ "SWAP_SIZE_EXCEEDED_LOOP" /* SWAP_SIZE_EXCEEDED_LOOP */,
138
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
139
+ { bytes, accountKeys, provider }
140
+ );
141
+ }
142
+ static swapSizeExceededRepay(bytes, accountKeys, provider) {
143
+ return new _TransactionBuildingError(
144
+ "SWAP_SIZE_EXCEEDED_REPAY" /* SWAP_SIZE_EXCEEDED_REPAY */,
145
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
146
+ { bytes, accountKeys, provider }
147
+ );
148
+ }
129
149
  /**
130
150
  * Failed to crank oracles for one or more banks
131
151
  */
@@ -167,6 +187,26 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
167
187
  { bankAddress, bankMint, bankSymbol }
168
188
  );
169
189
  }
190
+ /**
191
+ * Failed to update Switchboard price feeds
192
+ */
193
+ static switchboardFeedUpdateFailed(oracleKeys, reason) {
194
+ return new _TransactionBuildingError(
195
+ "SWITCHBOARD_FEED_UPDATE_FAILED" /* SWITCHBOARD_FEED_UPDATE_FAILED */,
196
+ `Switchboard feed update failed: ${reason}`,
197
+ { oracleKeys, reason }
198
+ );
199
+ }
200
+ /**
201
+ * Failed to get a swap quote from any provider
202
+ */
203
+ static swapQuoteFailed(provider, inputMint, outputMint, reason) {
204
+ return new _TransactionBuildingError(
205
+ "SWAP_QUOTE_FAILED" /* SWAP_QUOTE_FAILED */,
206
+ `${provider} swap quote failed for ${inputMint} \u2192 ${outputMint}: ${reason}`,
207
+ { provider, inputMint, outputMint, reason }
208
+ );
209
+ }
170
210
  /**
171
211
  * Generic escape hatch for custom errors
172
212
  */
@@ -319,6 +359,7 @@ var MAX_U64 = BigInt("18446744073709551615").toString();
319
359
 
320
360
  // src/constants/transaction.consts.ts
321
361
  var MAX_TX_SIZE = 1232;
362
+ var MAX_ACCOUNT_LOCKS = 64;
322
363
  var BUNDLE_TX_SIZE = 81;
323
364
  var PRIORITY_TX_SIZE = 44;
324
365
  var WSOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
@@ -14867,8 +14908,40 @@ function getTxSize(tx) {
14867
14908
  const signaturesSize = (numRequiredSignatures - numSigners) * 64 + 1;
14868
14909
  try {
14869
14910
  const baseTxSize = isVersioned ? tx.serialize().length : tx.serialize({ requireAllSignatures: false, verifySignatures: false }).length;
14870
- return baseTxSize + feePayerSize + signaturesSize;
14871
- } catch {
14911
+ const totalSize = baseTxSize + feePayerSize + signaturesSize;
14912
+ if (isVersioned && totalSize > 1232) {
14913
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14914
+ const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
14915
+ const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
14916
+ console.warn("[getTxSize] oversized TX", {
14917
+ totalSize,
14918
+ overshoot: totalSize - 1232,
14919
+ staticKeys: staticAccountKeys.length,
14920
+ numSignatures: header.numRequiredSignatures,
14921
+ numLuts: addressTableLookups.length,
14922
+ lutWritable,
14923
+ lutReadonly,
14924
+ totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
14925
+ });
14926
+ }
14927
+ return totalSize;
14928
+ } catch (err) {
14929
+ if (isVersioned) {
14930
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14931
+ const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
14932
+ const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
14933
+ console.warn("[getTxSize] serialize failed", {
14934
+ error: err.message,
14935
+ staticKeys: staticAccountKeys.length,
14936
+ numSignatures: header.numRequiredSignatures,
14937
+ numLuts: addressTableLookups.length,
14938
+ lutWritable,
14939
+ lutReadonly,
14940
+ totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
14941
+ });
14942
+ } else {
14943
+ console.warn("[getTxSize] serialize failed", { error: err.message });
14944
+ }
14872
14945
  return 9999;
14873
14946
  }
14874
14947
  }
@@ -14883,6 +14956,47 @@ function getAccountKeys(tx, lookupTableAccounts) {
14883
14956
  } else {
14884
14957
  return tx.compileMessage().getAccountKeys().length;
14885
14958
  }
14959
+ } catch (err) {
14960
+ console.warn("[getAccountKeys] decompile failed", { error: err.message });
14961
+ return 9999;
14962
+ }
14963
+ }
14964
+ function getWritableAccountKeys(tx) {
14965
+ const isVersioned = isV0Tx(tx);
14966
+ try {
14967
+ if (isVersioned) {
14968
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14969
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
14970
+ const writableLut = addressTableLookups.reduce(
14971
+ (sum, lookup) => sum + lookup.writableIndexes.length,
14972
+ 0
14973
+ );
14974
+ return writableStatic + writableLut;
14975
+ } else {
14976
+ const message = tx.compileMessage();
14977
+ const { numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts } = message.header;
14978
+ const totalKeys = message.accountKeys.length;
14979
+ const writableSigned = numRequiredSignatures - numReadonlySignedAccounts;
14980
+ const writableUnsigned = totalKeys - numRequiredSignatures - numReadonlyUnsignedAccounts;
14981
+ return writableSigned + writableUnsigned;
14982
+ }
14983
+ } catch {
14984
+ return 9999;
14985
+ }
14986
+ }
14987
+ function getTotalAccountKeys(tx) {
14988
+ const isVersioned = isV0Tx(tx);
14989
+ try {
14990
+ if (isVersioned) {
14991
+ const { staticAccountKeys, addressTableLookups } = tx.message;
14992
+ const lutAccounts = addressTableLookups.reduce(
14993
+ (sum, lookup) => sum + lookup.writableIndexes.length + lookup.readonlyIndexes.length,
14994
+ 0
14995
+ );
14996
+ return staticAccountKeys.length + lutAccounts;
14997
+ } else {
14998
+ return tx.compileMessage().accountKeys.length;
14999
+ }
14886
15000
  } catch {
14887
15001
  return 9999;
14888
15002
  }
@@ -20120,6 +20234,14 @@ var HealthCacheSimulationError = class _HealthCacheSimulationError extends Error
20120
20234
  }
20121
20235
  };
20122
20236
 
20237
+ // src/services/account/types/action.types.ts
20238
+ var SwapProvider = /* @__PURE__ */ ((SwapProvider2) => {
20239
+ SwapProvider2["JUPITER"] = "JUPITER";
20240
+ SwapProvider2["TITAN"] = "TITAN";
20241
+ SwapProvider2["DFLOW"] = "DFLOW";
20242
+ return SwapProvider2;
20243
+ })(SwapProvider || {});
20244
+
20123
20245
  // src/services/account/utils/deserialize.utils.ts
20124
20246
  var EMPTY_HEALTH_CACHE = {
20125
20247
  assetValue: {
@@ -44168,6 +44290,330 @@ function makeUpdateJupLendRate({ lendingState }) {
44168
44290
  lendingState.rewardsRateModel
44169
44291
  );
44170
44292
  }
44293
+ var SUBPROTOCOL = "v1.api.titan.ag";
44294
+ var UINT64_MAX = (1n << 64n) - 1n;
44295
+ function toBigInt(value) {
44296
+ if (typeof value === "bigint") {
44297
+ if (value < 0n || value > UINT64_MAX) {
44298
+ throw new RangeError(`Amount out of uint64 range: ${value}`);
44299
+ }
44300
+ return value;
44301
+ }
44302
+ if (!Number.isInteger(value)) {
44303
+ throw new TypeError(`Amount must be a whole number, got ${value}`);
44304
+ }
44305
+ if (value < 0) {
44306
+ throw new RangeError(`Amount must be non-negative, got ${value}`);
44307
+ }
44308
+ return BigInt(value);
44309
+ }
44310
+ var ConnectionClosed = class _ConnectionClosed extends Error {
44311
+ code;
44312
+ reason;
44313
+ constructor(code, reason) {
44314
+ super(`Client WebSocket closed with code ${code}: ${reason}`);
44315
+ this.name = "ConnectionClosed";
44316
+ Object.setPrototypeOf(this, _ConnectionClosed.prototype);
44317
+ this.code = code;
44318
+ this.reason = reason;
44319
+ }
44320
+ };
44321
+ var ErrorResponse = class _ErrorResponse extends Error {
44322
+ response;
44323
+ constructor(response) {
44324
+ super(`Request ${response.requestId} failed with code ${response.code}: ${response.message}`);
44325
+ this.name = "ErrorResponse";
44326
+ Object.setPrototypeOf(this, _ErrorResponse.prototype);
44327
+ this.response = response;
44328
+ }
44329
+ };
44330
+ var StreamError = class _StreamError extends Error {
44331
+ streamId;
44332
+ errorCode;
44333
+ errorMessage;
44334
+ constructor(packet) {
44335
+ const code = packet.errorCode ?? 0;
44336
+ const message = packet.errorMessage ?? "";
44337
+ super(`Stream ${packet.id} ended with error code ${code}: ${message}`);
44338
+ this.name = "StreamError";
44339
+ Object.setPrototypeOf(this, _StreamError.prototype);
44340
+ this.streamId = packet.id;
44341
+ this.errorCode = code;
44342
+ this.errorMessage = message;
44343
+ }
44344
+ };
44345
+ var encoder = new Encoder({ useBigInt64: true });
44346
+ var decoder = new Decoder({ useBigInt64: true });
44347
+ var V1Client = class _V1Client {
44348
+ socket;
44349
+ nextId = 0;
44350
+ _closed = false;
44351
+ _closing = false;
44352
+ pending = /* @__PURE__ */ new Map();
44353
+ streams = /* @__PURE__ */ new Map();
44354
+ streamStopping = /* @__PURE__ */ new Map();
44355
+ closeListeners = [];
44356
+ // --- Static connect ---
44357
+ static connect(url) {
44358
+ return new Promise((resolve, reject) => {
44359
+ const ws = new WebSocket(url, [SUBPROTOCOL]);
44360
+ ws.binaryType = "arraybuffer";
44361
+ ws.on("open", () => {
44362
+ resolve(new _V1Client(ws));
44363
+ });
44364
+ ws.on("error", (err) => {
44365
+ reject(err);
44366
+ });
44367
+ });
44368
+ }
44369
+ // --- Constructor ---
44370
+ constructor(socket) {
44371
+ this.socket = socket;
44372
+ this.socket.on("message", (data) => {
44373
+ this.handleMessage(data);
44374
+ });
44375
+ this.socket.on("close", (code, reason) => {
44376
+ this.handleClose(code, reason.toString());
44377
+ });
44378
+ this.socket.on("error", (err) => {
44379
+ this.handleError(err);
44380
+ });
44381
+ }
44382
+ nextRequestId() {
44383
+ return this.nextId++;
44384
+ }
44385
+ // --- Public API ---
44386
+ get closed() {
44387
+ return this._closed;
44388
+ }
44389
+ close() {
44390
+ if (this._closed) return Promise.resolve();
44391
+ return new Promise((resolve, reject) => {
44392
+ this.closeListeners.push({ resolve, reject });
44393
+ if (!this._closing) {
44394
+ this._closing = true;
44395
+ this.socket.close();
44396
+ }
44397
+ });
44398
+ }
44399
+ newSwapQuoteStream(params) {
44400
+ const requestId = this.nextRequestId();
44401
+ const promise = new Promise(
44402
+ (resolve, reject) => {
44403
+ this.pending.set(requestId, {
44404
+ resolve,
44405
+ reject,
44406
+ kind: "NewSwapQuoteStream"
44407
+ });
44408
+ }
44409
+ );
44410
+ const normalized = {
44411
+ ...params,
44412
+ swap: { ...params.swap, amount: toBigInt(params.swap.amount) }
44413
+ };
44414
+ const message = {
44415
+ id: requestId,
44416
+ data: { NewSwapQuoteStream: normalized }
44417
+ };
44418
+ this.send(message);
44419
+ return promise;
44420
+ }
44421
+ stopStream(streamId) {
44422
+ const requestId = this.nextRequestId();
44423
+ const promise = new Promise((resolve, reject) => {
44424
+ this.pending.set(requestId, {
44425
+ resolve,
44426
+ reject,
44427
+ kind: "StopStream"
44428
+ });
44429
+ });
44430
+ const message = {
44431
+ id: requestId,
44432
+ data: { StopStream: { id: streamId } }
44433
+ };
44434
+ this.send(message);
44435
+ return promise;
44436
+ }
44437
+ // --- Send ---
44438
+ send(message) {
44439
+ try {
44440
+ const encoded = encoder.encode(message);
44441
+ this.socket.send(encoded);
44442
+ } catch (err) {
44443
+ const req = this.pending.get(message.id);
44444
+ if (req) {
44445
+ this.pending.delete(message.id);
44446
+ req.reject(err);
44447
+ }
44448
+ }
44449
+ }
44450
+ // --- Message handling ---
44451
+ handleMessage(raw) {
44452
+ let buf;
44453
+ if (raw instanceof ArrayBuffer) {
44454
+ buf = new Uint8Array(raw);
44455
+ } else if (Buffer.isBuffer(raw)) {
44456
+ buf = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
44457
+ } else if (Array.isArray(raw)) {
44458
+ buf = new Uint8Array(Buffer.concat(raw));
44459
+ } else {
44460
+ return;
44461
+ }
44462
+ let message;
44463
+ try {
44464
+ message = decoder.decode(buf);
44465
+ } catch {
44466
+ this.socket.close(3002, "failed to decode message");
44467
+ return;
44468
+ }
44469
+ if ("Response" in message) {
44470
+ this.handleResponse(message.Response);
44471
+ } else if ("Error" in message) {
44472
+ this.handleResponseError(message.Error);
44473
+ } else if ("StreamData" in message) {
44474
+ this.handleStreamData(message.StreamData);
44475
+ } else if ("StreamEnd" in message) {
44476
+ this.handleStreamEnd(message.StreamEnd);
44477
+ }
44478
+ }
44479
+ handleResponse(msg) {
44480
+ const req = this.pending.get(msg.requestId);
44481
+ if (!req) return;
44482
+ this.pending.delete(msg.requestId);
44483
+ if ("NewSwapQuoteStream" in msg.data && req.kind === "NewSwapQuoteStream") {
44484
+ const streamInfo = msg.stream;
44485
+ if (!streamInfo) {
44486
+ req.reject(new Error("No stream associated with NewSwapQuoteStream response"));
44487
+ return;
44488
+ }
44489
+ const stream = new ReadableStream({
44490
+ start: (controller) => {
44491
+ this.streams.set(streamInfo.id, controller);
44492
+ },
44493
+ cancel: () => {
44494
+ return this.cancelStream(streamInfo.id);
44495
+ }
44496
+ });
44497
+ const result = {
44498
+ response: msg.data.NewSwapQuoteStream,
44499
+ stream,
44500
+ streamId: streamInfo.id
44501
+ };
44502
+ req.resolve(result);
44503
+ } else if ("StreamStopped" in msg.data && req.kind === "StopStream") {
44504
+ req.resolve(msg.data.StreamStopped);
44505
+ } else {
44506
+ req.reject(new Error(`Unexpected response type for ${req.kind}`));
44507
+ }
44508
+ }
44509
+ handleResponseError(error) {
44510
+ const req = this.pending.get(error.requestId);
44511
+ if (!req) return;
44512
+ this.pending.delete(error.requestId);
44513
+ req.reject(new ErrorResponse(error));
44514
+ }
44515
+ handleStreamData(packet) {
44516
+ const controller = this.streams.get(packet.id);
44517
+ if (!controller) return;
44518
+ if (packet.payload.SwapQuotes !== void 0) {
44519
+ controller.enqueue(packet.payload.SwapQuotes);
44520
+ }
44521
+ }
44522
+ handleStreamEnd(packet) {
44523
+ const controller = this.streams.get(packet.id);
44524
+ if (!controller) return;
44525
+ this.streams.delete(packet.id);
44526
+ this.streamStopping.delete(packet.id);
44527
+ if (packet.errorCode !== void 0) {
44528
+ controller.error(new StreamError(packet));
44529
+ } else {
44530
+ controller.close();
44531
+ }
44532
+ }
44533
+ async cancelStream(streamId) {
44534
+ if (this.streamStopping.get(streamId) || !this.streams.has(streamId)) return;
44535
+ this.streamStopping.set(streamId, true);
44536
+ await this.stopStream(streamId);
44537
+ }
44538
+ // --- Connection lifecycle ---
44539
+ rejectAll(error) {
44540
+ for (const req of this.pending.values()) {
44541
+ req.reject(error);
44542
+ }
44543
+ this.pending.clear();
44544
+ for (const controller of this.streams.values()) {
44545
+ controller.error(error);
44546
+ }
44547
+ this.streams.clear();
44548
+ this.streamStopping.clear();
44549
+ }
44550
+ handleClose(code, reason) {
44551
+ this._closed = true;
44552
+ this.rejectAll(new ConnectionClosed(code, reason));
44553
+ for (const listener of this.closeListeners) {
44554
+ listener.resolve();
44555
+ }
44556
+ this.closeListeners = [];
44557
+ }
44558
+ handleError(err) {
44559
+ this.rejectAll(err);
44560
+ this.socket.close(3002);
44561
+ }
44562
+ };
44563
+ function deserializeSerializedInstruction(ix) {
44564
+ return new TransactionInstruction({
44565
+ programId: new PublicKey(Buffer.from(ix.p, "base64")),
44566
+ keys: ix.a.map((account) => ({
44567
+ pubkey: new PublicKey(Buffer.from(account.p, "base64")),
44568
+ isSigner: account.s,
44569
+ isWritable: account.w
44570
+ })),
44571
+ data: Buffer.from(ix.d, "base64")
44572
+ });
44573
+ }
44574
+ function selectBestRoute(quotes, swapMode) {
44575
+ const routes = Object.values(quotes);
44576
+ if (routes.length === 0) return null;
44577
+ return routes.reduce((best, route) => {
44578
+ if (swapMode === "ExactIn") {
44579
+ return route.outAmount > best.outAmount ? route : best;
44580
+ } else {
44581
+ return route.inAmount < best.inAmount ? route : best;
44582
+ }
44583
+ });
44584
+ }
44585
+ function buildSwapQuoteResult(route, swapMode) {
44586
+ const slippageBps = route.slippageBps;
44587
+ let otherAmountThreshold;
44588
+ if (swapMode === "ExactIn") {
44589
+ otherAmountThreshold = String(Math.floor(route.outAmount * (1 - slippageBps / 1e4)));
44590
+ } else {
44591
+ otherAmountThreshold = String(Math.ceil(route.inAmount * (1 + slippageBps / 1e4)));
44592
+ }
44593
+ return {
44594
+ inAmount: String(route.inAmount),
44595
+ outAmount: String(route.outAmount),
44596
+ otherAmountThreshold,
44597
+ slippageBps,
44598
+ platformFee: route.platformFee ? {
44599
+ amount: String(route.platformFee.amount),
44600
+ feeBps: route.platformFee.fee_bps
44601
+ } : void 0,
44602
+ contextSlot: route.contextSlot,
44603
+ timeTaken: route.timeTaken
44604
+ };
44605
+ }
44606
+ async function resolveLookupTables(connection, lutPubkeys) {
44607
+ if (lutPubkeys.length === 0) return [];
44608
+ const lutAccountsRaw = await connection.getMultipleAccountsInfo(lutPubkeys);
44609
+ return lutAccountsRaw.map((accountInfo, index) => {
44610
+ if (!accountInfo) return null;
44611
+ return new AddressLookupTableAccount({
44612
+ key: lutPubkeys[index],
44613
+ state: AddressLookupTableAccount.deserialize(accountInfo.data)
44614
+ });
44615
+ }).filter((account) => account !== null);
44616
+ }
44171
44617
 
44172
44618
  // src/vendor/klend/utils/klend/interest-rate.utils.ts
44173
44619
  function getKaminoTotalSupply(reserve) {
@@ -46457,116 +46903,81 @@ async function makeJuplendDepositTx(params) {
46457
46903
  });
46458
46904
  return solanaTx;
46459
46905
  }
46460
- async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
46461
- const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
46462
- program.programId,
46463
- {
46464
- marginfiAccount: marginfiAccountPk,
46465
- authority
46466
- },
46467
- { endIndex: new BN11(endIndex) }
46468
- ) : await instructions_default.makeBeginFlashLoanIx(
46906
+ async function makeRepayIx3({
46907
+ program,
46908
+ bank,
46909
+ tokenProgram,
46910
+ amount,
46911
+ authority,
46912
+ accountAddress,
46913
+ repayAll = false,
46914
+ isSync = false,
46915
+ opts = {}
46916
+ }) {
46917
+ const wrapAndUnwrapSol = opts.wrapAndUnwrapSol ?? true;
46918
+ const wSolBalanceUi = opts.wSolBalanceUi ?? 0;
46919
+ const repayIxs = [];
46920
+ const userAta = getAssociatedTokenAddressSync(bank.mint, authority, true, tokenProgram);
46921
+ const remainingAccounts = tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? [{ pubkey: bank.mint, isSigner: false, isWritable: false }] : [];
46922
+ if (bank.mint.equals(NATIVE_MINT) && wrapAndUnwrapSol) {
46923
+ repayIxs.push(...makeWrapSolIxs(authority, new BigNumber(amount).minus(wSolBalanceUi)));
46924
+ }
46925
+ const repayIx = !isSync || !opts.overrideInferAccounts?.group ? await instructions_default.makeRepayIx(
46469
46926
  program,
46470
46927
  {
46471
- marginfiAccount: marginfiAccountPk,
46472
- authority
46928
+ marginfiAccount: accountAddress,
46929
+ signerTokenAccount: userAta,
46930
+ bank: bank.address,
46931
+ tokenProgram,
46932
+ authority: opts.overrideInferAccounts?.authority ?? authority,
46933
+ group: opts.overrideInferAccounts?.group,
46934
+ liquidityVault: opts.overrideInferAccounts?.liquidityVault
46473
46935
  },
46474
- { endIndex: new BN11(endIndex) }
46475
- );
46476
- return { instructions: [ix], keys: [] };
46477
- }
46478
- async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
46479
- const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
46480
- const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
46936
+ { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46937
+ remainingAccounts
46938
+ ) : sync_instructions_default.makeRepayIx(
46481
46939
  program.programId,
46482
46940
  {
46483
- marginfiAccount: marginfiAccountPk,
46484
- authority
46485
- },
46486
- remainingAccounts.map((account) => ({
46487
- pubkey: account,
46488
- isSigner: false,
46489
- isWritable: false
46490
- }))
46491
- ) : await instructions_default.makeEndFlashLoanIx(
46492
- program,
46493
- {
46494
- marginfiAccount: marginfiAccountPk,
46495
- authority
46941
+ marginfiAccount: accountAddress,
46942
+ signerTokenAccount: userAta,
46943
+ bank: bank.address,
46944
+ tokenProgram,
46945
+ authority: opts.overrideInferAccounts?.authority ?? authority,
46946
+ group: opts.overrideInferAccounts?.group
46496
46947
  },
46497
- remainingAccounts.map((account) => ({
46498
- pubkey: account,
46499
- isSigner: false,
46500
- isWritable: false
46501
- }))
46948
+ { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46949
+ remainingAccounts
46502
46950
  );
46503
- return { instructions: [ix], keys: [] };
46951
+ repayIxs.push(repayIx);
46952
+ return {
46953
+ instructions: repayIxs,
46954
+ keys: []
46955
+ };
46504
46956
  }
46505
- async function makeFlashLoanTx({
46506
- program,
46507
- marginfiAccount,
46508
- ixs,
46509
- bankMap,
46510
- blockhash,
46511
- addressLookupTableAccounts,
46512
- signers,
46513
- isSync
46514
- }) {
46515
- const endIndex = ixs.length + 1;
46516
- const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
46517
- marginfiAccount.balances,
46518
- ixs,
46519
- program
46520
- );
46521
- const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
46522
- const b = bankMap.get(account.toBase58());
46523
- if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
46524
- return b;
46525
- });
46526
- const beginFlashLoanIx = await makeBeginFlashLoanIx3(
46527
- program,
46528
- marginfiAccount.address,
46529
- endIndex,
46530
- marginfiAccount.authority,
46531
- isSync
46532
- );
46533
- const endFlashLoanIx = await makeEndFlashLoanIx3(
46534
- program,
46535
- marginfiAccount.address,
46536
- projectedActiveBanks,
46537
- marginfiAccount.authority,
46538
- isSync
46539
- );
46540
- const message = new TransactionMessage({
46541
- payerKey: marginfiAccount.authority,
46542
- recentBlockhash: blockhash,
46543
- instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
46544
- }).compileToV0Message(addressLookupTableAccounts);
46545
- const tx = addTransactionMetadata(new VersionedTransaction(message), {
46546
- addressLookupTables: addressLookupTableAccounts,
46547
- type: "FLASHLOAN" /* FLASHLOAN */,
46548
- signers
46957
+ async function makeRepayTx(params) {
46958
+ const { luts, ...depositIxParams } = params;
46959
+ const ixs = await makeRepayIx3(depositIxParams);
46960
+ const tx = new Transaction().add(...ixs.instructions);
46961
+ tx.feePayer = params.authority;
46962
+ const solanaTx = addTransactionMetadata(tx, {
46963
+ type: "REPAY" /* REPAY */,
46964
+ signers: ixs.keys,
46965
+ addressLookupTables: luts
46549
46966
  });
46550
- if (signers) {
46551
- tx.sign(signers);
46552
- }
46553
- return tx;
46967
+ return solanaTx;
46554
46968
  }
46555
-
46556
- // src/services/account/actions/loop.ts
46557
- async function makeLoopTx(params) {
46969
+ async function makeRepayWithCollatTx(params) {
46558
46970
  const {
46559
46971
  program,
46560
46972
  marginfiAccount,
46561
46973
  bankMap,
46562
- depositOpts,
46563
- borrowOpts,
46974
+ withdrawOpts,
46975
+ repayOpts,
46564
46976
  bankMetadataMap,
46565
46977
  addressLookupTableAccounts,
46566
46978
  connection,
46567
46979
  oraclePrices,
46568
- crossbarUrl,
46569
- additionalIxs = []
46980
+ crossbarUrl
46570
46981
  } = params;
46571
46982
  const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
46572
46983
  const setupIxs = await makeSetupIx({
@@ -46574,34 +46985,34 @@ async function makeLoopTx(params) {
46574
46985
  authority: marginfiAccount.authority,
46575
46986
  tokens: [
46576
46987
  {
46577
- mint: borrowOpts.borrowBank.mint,
46578
- tokenProgram: borrowOpts.tokenProgram
46988
+ mint: repayOpts.repayBank.mint,
46989
+ tokenProgram: repayOpts.tokenProgram
46579
46990
  },
46580
46991
  {
46581
- mint: depositOpts.depositBank.mint,
46582
- tokenProgram: depositOpts.tokenProgram
46992
+ mint: withdrawOpts.withdrawBank.mint,
46993
+ tokenProgram: withdrawOpts.tokenProgram
46583
46994
  }
46584
46995
  ]
46585
46996
  });
46586
- const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
46587
- params.marginfiAccount,
46588
- params.bankMap,
46589
- [depositOpts.depositBank.address],
46590
- params.bankMetadataMap
46997
+ const updateJuplendMarketIxs = makeUpdateJupLendRateIxs(
46998
+ marginfiAccount,
46999
+ bankMap,
47000
+ [withdrawOpts.withdrawBank.address],
47001
+ bankMetadataMap
46591
47002
  );
46592
47003
  const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
46593
- params.marginfiAccount,
46594
- params.bankMap,
46595
- [depositOpts.depositBank.address],
46596
- params.bankMetadataMap
47004
+ marginfiAccount,
47005
+ bankMap,
47006
+ [withdrawOpts.withdrawBank.address],
47007
+ bankMetadataMap
46597
47008
  );
46598
47009
  const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
46599
47010
  marginfiAccount,
46600
47011
  bankMap,
46601
- [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
47012
+ [withdrawOpts.withdrawBank.address, repayOpts.repayBank.address],
46602
47013
  bankMetadataMap
46603
47014
  );
46604
- const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
47015
+ const { flashloanTx, setupInstructions, swapQuote, amountToRepay, withdrawIxs, repayIxs } = await buildRepayWithCollatFlashloanTx({
46605
47016
  ...params,
46606
47017
  blockhash
46607
47018
  });
@@ -46611,7 +47022,7 @@ async function makeLoopTx(params) {
46611
47022
  }
46612
47023
  if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
46613
47024
  const mintKey = ix.keys[3]?.pubkey;
46614
- if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
47025
+ if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(repayOpts.repayBank.mint)) {
46615
47026
  return false;
46616
47027
  }
46617
47028
  }
@@ -46623,24 +47034,18 @@ async function makeLoopTx(params) {
46623
47034
  bankMap,
46624
47035
  oraclePrices,
46625
47036
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
46626
- instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
47037
+ instructions: [...withdrawIxs.instructions, ...repayIxs.instructions],
46627
47038
  program,
46628
47039
  connection,
46629
47040
  crossbarUrl
46630
47041
  });
46631
47042
  let additionalTxs = [];
46632
- if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
46633
- setupIxs.push(
46634
- ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
46635
- );
46636
- }
46637
- if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
47043
+ if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJuplendMarketIxs.instructions.length > 0) {
46638
47044
  const ixs = [
46639
- ...additionalIxs,
46640
47045
  ...setupIxs,
46641
47046
  ...kaminoRefreshIxs.instructions,
46642
47047
  ...updateDriftMarketIxs.instructions,
46643
- ...updateJupLendRateIxs.instructions
47048
+ ...updateJuplendMarketIxs.instructions
46644
47049
  ];
46645
47050
  const txs = splitInstructionsToFitTransactions([], ixs, {
46646
47051
  blockhash,
@@ -46670,300 +47075,835 @@ async function makeLoopTx(params) {
46670
47075
  );
46671
47076
  }
46672
47077
  const transactions = [...additionalTxs, flashloanTx];
46673
- return {
46674
- transactions,
46675
- actionTxIndex: transactions.length - 1,
46676
- quoteResponse: swapQuote
46677
- };
47078
+ return { transactions, swapQuote, amountToRepay };
46678
47079
  }
46679
- async function buildLoopFlashloanTx({
47080
+ async function buildRepayWithCollatFlashloanTx({
46680
47081
  program,
46681
47082
  marginfiAccount,
46682
47083
  bankMap,
46683
- borrowOpts,
46684
- depositOpts,
47084
+ withdrawOpts,
47085
+ repayOpts,
46685
47086
  bankMetadataMap,
47087
+ assetShareValueMultiplierByBank,
46686
47088
  addressLookupTableAccounts,
46687
47089
  connection,
46688
47090
  swapOpts,
46689
47091
  overrideInferAccounts,
46690
47092
  blockhash
46691
47093
  }) {
46692
- const swapResult = [];
46693
47094
  const cuRequestIxs = [
46694
47095
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
46695
47096
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
46696
47097
  ];
46697
- if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
46698
- swapResult.push({
46699
- amountToDeposit: borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0),
46700
- swapInstructions: [],
46701
- setupInstructions: [],
46702
- swapLookupTables: []
46703
- });
47098
+ let amountToRepay;
47099
+ let swapInstructions = [];
47100
+ let setupInstructions = [];
47101
+ let swapLookupTables = [];
47102
+ let swapQuote;
47103
+ let sizeConstraintUsed = 0;
47104
+ if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
47105
+ amountToRepay = withdrawOpts.withdrawAmount;
46704
47106
  } else {
46705
47107
  const destinationTokenAccount = getAssociatedTokenAddressSync(
46706
- new PublicKey(depositOpts.depositBank.mint),
47108
+ new PublicKey(repayOpts.repayBank.mint),
46707
47109
  marginfiAccount.authority,
46708
47110
  true,
46709
- depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47111
+ repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
46710
47112
  );
46711
- const swapResponse = await getJupiterSwapIxsForFlashloan({
46712
- quoteParams: {
46713
- inputMint: borrowOpts.borrowBank.mint.toBase58(),
46714
- outputMint: depositOpts.depositBank.mint.toBase58(),
46715
- amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
46716
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
46717
- slippageBps: swapOpts.jupiterOptions?.slippageBps ?? void 0,
46718
- swapMode: "ExactIn",
46719
- platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps ?? void 0,
46720
- onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
47113
+ const swapConstraints = await computeFlashloanSwapConstraints({
47114
+ program,
47115
+ marginfiAccount,
47116
+ bankMap,
47117
+ bankMetadataMap,
47118
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
47119
+ primaryIx: {
47120
+ type: "withdraw",
47121
+ bank: withdrawOpts.withdrawBank,
47122
+ tokenProgram: withdrawOpts.tokenProgram
47123
+ },
47124
+ secondaryIx: {
47125
+ type: "repay",
47126
+ bank: repayOpts.repayBank,
47127
+ tokenProgram: repayOpts.tokenProgram
46721
47128
  },
47129
+ overrideInferAccounts
47130
+ });
47131
+ const swapResponse = await getSwapIxsForFlashloan({
47132
+ inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
47133
+ outputMint: repayOpts.repayBank.mint.toBase58(),
47134
+ amount: uiToNative(
47135
+ withdrawOpts.withdrawAmount,
47136
+ withdrawOpts.withdrawBank.mintDecimals
47137
+ ).toNumber(),
47138
+ swapMode: "ExactIn",
46722
47139
  authority: marginfiAccount.authority,
46723
47140
  connection,
46724
47141
  destinationTokenAccount,
46725
- configParams: swapOpts.jupiterOptions?.configParams
47142
+ swapOpts,
47143
+ sizeConstraint: swapConstraints.sizeConstraint,
47144
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
46726
47145
  });
46727
- swapResponse.forEach((response) => {
46728
- const outAmountThreshold = nativeToUi(
46729
- response.quoteResponse.otherAmountThreshold,
46730
- depositOpts.depositBank.mintDecimals
46731
- );
46732
- const amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
46733
- swapResult.push({
46734
- amountToDeposit,
46735
- swapInstructions: [response.swapInstruction],
46736
- setupInstructions: response.setupInstructions,
46737
- swapLookupTables: response.addressLookupTableAddresses,
46738
- quoteResponse: response.quoteResponse
47146
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
47147
+ const { quoteResponse } = swapResponse;
47148
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
47149
+ const outAmountThreshold = nativeToUi(
47150
+ quoteResponse.otherAmountThreshold,
47151
+ repayOpts.repayBank.mintDecimals
47152
+ );
47153
+ amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
47154
+ swapInstructions = swapResponse.swapInstructions;
47155
+ swapLookupTables = swapResponse.addressLookupTableAddresses;
47156
+ swapQuote = quoteResponse;
47157
+ }
47158
+ let withdrawIxs;
47159
+ switch (withdrawOpts.withdrawBank.config.assetTag) {
47160
+ case 3 /* KAMINO */: {
47161
+ const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
47162
+ if (!reserve) {
47163
+ throw TransactionBuildingError.kaminoReserveNotFound(
47164
+ withdrawOpts.withdrawBank.address.toBase58(),
47165
+ withdrawOpts.withdrawBank.mint.toBase58(),
47166
+ withdrawOpts.withdrawBank.tokenSymbol
47167
+ );
47168
+ }
47169
+ const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
47170
+ const adjustedAmount = new BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
47171
+ withdrawIxs = await makeKaminoWithdrawIx3({
47172
+ program,
47173
+ bank: withdrawOpts.withdrawBank,
47174
+ bankMap,
47175
+ tokenProgram: withdrawOpts.tokenProgram,
47176
+ cTokenAmount: adjustedAmount,
47177
+ marginfiAccount,
47178
+ authority: marginfiAccount.authority,
47179
+ reserve,
47180
+ withdrawAll: isWholePosition(
47181
+ {
47182
+ amount: withdrawOpts.totalPositionAmount,
47183
+ isLending: true
47184
+ },
47185
+ withdrawOpts.withdrawAmount,
47186
+ withdrawOpts.withdrawBank.mintDecimals
47187
+ ),
47188
+ isSync: false,
47189
+ opts: {
47190
+ createAtas: false,
47191
+ wrapAndUnwrapSol: false,
47192
+ overrideInferAccounts
47193
+ }
46739
47194
  });
46740
- });
47195
+ break;
47196
+ }
47197
+ case 4 /* DRIFT */: {
47198
+ const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
47199
+ if (!driftState) {
47200
+ throw TransactionBuildingError.driftStateNotFound(
47201
+ withdrawOpts.withdrawBank.address.toBase58(),
47202
+ withdrawOpts.withdrawBank.mint.toBase58(),
47203
+ withdrawOpts.withdrawBank.tokenSymbol
47204
+ );
47205
+ }
47206
+ withdrawIxs = await makeDriftWithdrawIx3({
47207
+ program,
47208
+ bank: withdrawOpts.withdrawBank,
47209
+ bankMap,
47210
+ tokenProgram: withdrawOpts.tokenProgram,
47211
+ amount: withdrawOpts.withdrawAmount,
47212
+ marginfiAccount,
47213
+ authority: marginfiAccount.authority,
47214
+ driftSpotMarket: driftState.spotMarketState,
47215
+ userRewards: driftState.userRewards,
47216
+ withdrawAll: isWholePosition(
47217
+ {
47218
+ amount: withdrawOpts.totalPositionAmount,
47219
+ isLending: true
47220
+ },
47221
+ withdrawOpts.withdrawAmount,
47222
+ withdrawOpts.withdrawBank.mintDecimals
47223
+ ),
47224
+ isSync: false,
47225
+ opts: {
47226
+ createAtas: false,
47227
+ wrapAndUnwrapSol: false,
47228
+ overrideInferAccounts
47229
+ }
47230
+ });
47231
+ break;
47232
+ }
47233
+ case 6 /* JUPLEND */: {
47234
+ const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
47235
+ if (!jupLendState) {
47236
+ throw TransactionBuildingError.jupLendStateNotFound(
47237
+ withdrawOpts.withdrawBank.address.toBase58(),
47238
+ withdrawOpts.withdrawBank.mint.toBase58(),
47239
+ withdrawOpts.withdrawBank.tokenSymbol
47240
+ );
47241
+ }
47242
+ withdrawIxs = await makeJuplendWithdrawIx2({
47243
+ program,
47244
+ bank: withdrawOpts.withdrawBank,
47245
+ bankMap,
47246
+ tokenProgram: withdrawOpts.tokenProgram,
47247
+ amount: withdrawOpts.withdrawAmount,
47248
+ marginfiAccount,
47249
+ authority: marginfiAccount.authority,
47250
+ jupLendingState: jupLendState.jupLendingState,
47251
+ withdrawAll: isWholePosition(
47252
+ {
47253
+ amount: withdrawOpts.totalPositionAmount,
47254
+ isLending: true
47255
+ },
47256
+ withdrawOpts.withdrawAmount,
47257
+ withdrawOpts.withdrawBank.mintDecimals
47258
+ ),
47259
+ opts: {
47260
+ createAtas: false,
47261
+ wrapAndUnwrapSol: false,
47262
+ overrideInferAccounts
47263
+ }
47264
+ });
47265
+ break;
47266
+ }
47267
+ default: {
47268
+ withdrawIxs = await makeWithdrawIx3({
47269
+ program,
47270
+ bank: withdrawOpts.withdrawBank,
47271
+ bankMap,
47272
+ tokenProgram: withdrawOpts.tokenProgram,
47273
+ amount: withdrawOpts.withdrawAmount,
47274
+ marginfiAccount,
47275
+ authority: marginfiAccount.authority,
47276
+ withdrawAll: isWholePosition(
47277
+ {
47278
+ amount: withdrawOpts.totalPositionAmount,
47279
+ isLending: true
47280
+ },
47281
+ withdrawOpts.withdrawAmount,
47282
+ withdrawOpts.withdrawBank.mintDecimals
47283
+ ),
47284
+ isSync: false,
47285
+ opts: {
47286
+ createAtas: false,
47287
+ wrapAndUnwrapSol: false,
47288
+ overrideInferAccounts
47289
+ }
47290
+ });
47291
+ break;
47292
+ }
46741
47293
  }
46742
- const borrowIxs = await makeBorrowIx3({
47294
+ const repayIxs = await makeRepayIx3({
46743
47295
  program,
46744
- bank: borrowOpts.borrowBank,
46745
- bankMap,
46746
- tokenProgram: borrowOpts.tokenProgram,
46747
- amount: borrowOpts.borrowAmount,
46748
- marginfiAccount,
47296
+ bank: repayOpts.repayBank,
47297
+ tokenProgram: repayOpts.tokenProgram,
47298
+ amount: amountToRepay,
47299
+ accountAddress: marginfiAccount.address,
46749
47300
  authority: marginfiAccount.authority,
47301
+ repayAll: isWholePosition(
47302
+ {
47303
+ amount: repayOpts.totalPositionAmount,
47304
+ isLending: true
47305
+ },
47306
+ amountToRepay,
47307
+ repayOpts.repayBank.mintDecimals
47308
+ ),
46750
47309
  isSync: false,
46751
47310
  opts: {
46752
- createAtas: false,
46753
47311
  wrapAndUnwrapSol: false,
46754
47312
  overrideInferAccounts
46755
47313
  }
46756
47314
  });
46757
- for (const [index, item] of swapResult.entries()) {
46758
- const {
46759
- amountToDeposit,
46760
- swapInstructions,
46761
- setupInstructions,
46762
- swapLookupTables,
46763
- quoteResponse
46764
- } = item;
46765
- let depositIxs;
46766
- switch (depositOpts.depositBank.config.assetTag) {
46767
- case 3 /* KAMINO */: {
46768
- const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
46769
- if (!reserve) {
46770
- throw TransactionBuildingError.kaminoReserveNotFound(
46771
- depositOpts.depositBank.address.toBase58(),
46772
- depositOpts.depositBank.mint.toBase58(),
46773
- depositOpts.depositBank.tokenSymbol
46774
- );
46775
- }
46776
- depositIxs = await makeKaminoDepositIx3({
46777
- program,
46778
- bank: depositOpts.depositBank,
46779
- tokenProgram: depositOpts.tokenProgram,
46780
- amount: amountToDeposit,
46781
- accountAddress: marginfiAccount.address,
46782
- authority: marginfiAccount.authority,
46783
- group: marginfiAccount.group,
46784
- reserve,
46785
- opts: {
46786
- wrapAndUnwrapSol: false,
46787
- overrideInferAccounts
46788
- }
46789
- });
46790
- break;
46791
- }
46792
- case 4 /* DRIFT */: {
46793
- const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
46794
- if (!driftState) {
46795
- throw TransactionBuildingError.driftStateNotFound(
46796
- depositOpts.depositBank.address.toBase58(),
46797
- depositOpts.depositBank.mint.toBase58(),
46798
- depositOpts.depositBank.tokenSymbol
46799
- );
46800
- }
46801
- const driftMarketIndex = driftState.spotMarketState.marketIndex;
46802
- const driftOracle = driftState.spotMarketState.oracle;
46803
- depositIxs = await makeDriftDepositIx3({
46804
- program,
46805
- bank: depositOpts.depositBank,
46806
- tokenProgram: depositOpts.tokenProgram,
46807
- amount: amountToDeposit,
46808
- accountAddress: marginfiAccount.address,
46809
- authority: marginfiAccount.authority,
46810
- group: marginfiAccount.group,
46811
- driftMarketIndex,
46812
- driftOracle,
46813
- opts: {
46814
- wrapAndUnwrapSol: false,
46815
- overrideInferAccounts
46816
- }
46817
- });
46818
- break;
46819
- }
46820
- case 6 /* JUPLEND */: {
46821
- depositIxs = await makeJuplendDepositIx2({
46822
- program,
46823
- bank: depositOpts.depositBank,
46824
- tokenProgram: depositOpts.tokenProgram,
46825
- amount: amountToDeposit,
46826
- accountAddress: marginfiAccount.address,
46827
- authority: marginfiAccount.authority,
46828
- group: marginfiAccount.group,
46829
- opts: {
46830
- wrapAndUnwrapSol: false,
46831
- overrideInferAccounts
46832
- }
46833
- });
46834
- break;
47315
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47316
+ const allNonFlIxs = [
47317
+ ...cuRequestIxs,
47318
+ ...withdrawIxs.instructions,
47319
+ ...swapInstructions,
47320
+ ...repayIxs.instructions
47321
+ ];
47322
+ if (swapInstructions.length > 0) {
47323
+ compileFlashloanPrecheck({
47324
+ allIxs: allNonFlIxs,
47325
+ payer: marginfiAccount.authority,
47326
+ luts,
47327
+ sizeConstraint: sizeConstraintUsed,
47328
+ swapIxCount: swapInstructions.length,
47329
+ swapLutCount: swapLookupTables.length
47330
+ });
47331
+ }
47332
+ const flashloanTx = await makeFlashLoanTx({
47333
+ program,
47334
+ marginfiAccount,
47335
+ bankMap,
47336
+ addressLookupTableAccounts: luts,
47337
+ blockhash,
47338
+ ixs: allNonFlIxs,
47339
+ isSync: true
47340
+ });
47341
+ const txSize = getTxSize(flashloanTx);
47342
+ const totalKeys = getTotalAccountKeys(flashloanTx);
47343
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
47344
+ throw TransactionBuildingError.swapSizeExceededRepay(
47345
+ txSize,
47346
+ totalKeys,
47347
+ swapOpts.swapConfig?.provider
47348
+ );
47349
+ }
47350
+ return {
47351
+ flashloanTx,
47352
+ setupInstructions,
47353
+ swapQuote,
47354
+ withdrawIxs,
47355
+ repayIxs,
47356
+ amountToRepay
47357
+ };
47358
+ }
47359
+
47360
+ // src/services/account/utils/flashloan-size.utils.ts
47361
+ var SWAP_MERGE_OVERHEAD = 150;
47362
+ var FL_IX_OVERHEAD = 52;
47363
+ function compactU16Size(n) {
47364
+ return n < 128 ? 1 : n < 16384 ? 2 : 3;
47365
+ }
47366
+ function computeV0TxSize(ixs, payerKey, luts) {
47367
+ const keyMap = /* @__PURE__ */ new Map();
47368
+ const payerStr = payerKey.toBase58();
47369
+ keyMap.set(payerStr, { isSigner: true, isWritable: true });
47370
+ const programIds = /* @__PURE__ */ new Set();
47371
+ for (const ix of ixs) {
47372
+ const progStr = ix.programId.toBase58();
47373
+ programIds.add(progStr);
47374
+ if (!keyMap.has(progStr)) {
47375
+ keyMap.set(progStr, { isSigner: false, isWritable: false });
47376
+ }
47377
+ for (const meta of ix.keys) {
47378
+ const keyStr = meta.pubkey.toBase58();
47379
+ const existing = keyMap.get(keyStr);
47380
+ if (existing) {
47381
+ existing.isSigner = existing.isSigner || meta.isSigner;
47382
+ existing.isWritable = existing.isWritable || meta.isWritable;
47383
+ } else {
47384
+ keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
46835
47385
  }
46836
- default: {
46837
- depositIxs = await makeDepositIx3({
46838
- program,
46839
- bank: depositOpts.depositBank,
46840
- tokenProgram: depositOpts.tokenProgram,
46841
- amount: amountToDeposit,
46842
- accountAddress: marginfiAccount.address,
46843
- authority: marginfiAccount.authority,
46844
- group: marginfiAccount.group,
46845
- opts: {
46846
- wrapAndUnwrapSol: false,
46847
- overrideInferAccounts
46848
- }
46849
- });
46850
- break;
47386
+ }
47387
+ }
47388
+ const lutLookup = /* @__PURE__ */ new Map();
47389
+ for (let li = 0; li < luts.length; li++) {
47390
+ const addresses = luts[li].state.addresses;
47391
+ for (let ai = 0; ai < addresses.length; ai++) {
47392
+ const addrStr = addresses[ai].toBase58();
47393
+ if (!lutLookup.has(addrStr)) {
47394
+ lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
46851
47395
  }
46852
47396
  }
46853
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
46854
- const flashloanParams = {
46855
- program,
46856
- marginfiAccount,
46857
- bankMap,
46858
- addressLookupTableAccounts: luts,
46859
- blockhash
46860
- };
46861
- const flashloanTx = await makeFlashLoanTx({
46862
- ...flashloanParams,
46863
- ixs: [
46864
- ...cuRequestIxs,
46865
- ...borrowIxs.instructions,
46866
- ...swapInstructions,
46867
- ...depositIxs.instructions
46868
- ]
46869
- });
46870
- const txSize = getTxSize(flashloanTx);
46871
- const keySize = getAccountKeys(flashloanTx, luts);
46872
- const isLast = index === swapResult.length - 1;
46873
- if (txSize > MAX_TX_SIZE || keySize > 64) {
46874
- if (isLast) {
46875
- throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
47397
+ }
47398
+ let numStaticKeys = 0;
47399
+ let numWritableStaticKeys = 0;
47400
+ const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
47401
+ const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
47402
+ for (const [keyStr, props] of keyMap) {
47403
+ if (props.isSigner || programIds.has(keyStr)) {
47404
+ numStaticKeys++;
47405
+ if (props.isWritable) numWritableStaticKeys++;
47406
+ continue;
47407
+ }
47408
+ const lutEntry = lutLookup.get(keyStr);
47409
+ if (lutEntry) {
47410
+ if (props.isWritable) {
47411
+ lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
46876
47412
  } else {
46877
- continue;
47413
+ lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
46878
47414
  }
46879
47415
  } else {
46880
- return {
46881
- flashloanTx,
46882
- setupInstructions,
46883
- swapQuote: quoteResponse,
46884
- borrowIxs,
46885
- depositIxs,
46886
- amountToDeposit
46887
- };
47416
+ numStaticKeys++;
47417
+ if (props.isWritable) numWritableStaticKeys++;
46888
47418
  }
46889
47419
  }
46890
- throw new Error("Failed to build repay with collateral flashloan tx");
46891
- }
46892
- async function makeRepayIx3({
47420
+ const fixedOverhead = 101;
47421
+ const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
47422
+ let ixSection = compactU16Size(ixs.length);
47423
+ for (const ix of ixs) {
47424
+ const numAccounts = ix.keys.length;
47425
+ ixSection += 1 + // programId index
47426
+ compactU16Size(numAccounts) + numAccounts + // account key indexes
47427
+ compactU16Size(ix.data.length) + ix.data.length;
47428
+ }
47429
+ let numUsedLuts = 0;
47430
+ let lutSection = 0;
47431
+ for (let li = 0; li < luts.length; li++) {
47432
+ const wCount = lutWritableIdxs[li].size;
47433
+ const rCount = lutReadonlyIdxs[li].size;
47434
+ if (wCount === 0 && rCount === 0) continue;
47435
+ numUsedLuts++;
47436
+ lutSection += 32 + // LUT address
47437
+ compactU16Size(wCount) + wCount + // writable indexes
47438
+ compactU16Size(rCount) + rCount;
47439
+ }
47440
+ lutSection += compactU16Size(numUsedLuts);
47441
+ let totalLutKeys = 0;
47442
+ for (let li = 0; li < luts.length; li++) {
47443
+ totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
47444
+ }
47445
+ const accountCount = numStaticKeys + totalLutKeys;
47446
+ let totalLutWritableKeys = 0;
47447
+ for (let li = 0; li < luts.length; li++) {
47448
+ totalLutWritableKeys += lutWritableIdxs[li].size;
47449
+ }
47450
+ const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
47451
+ const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
47452
+ return { size, accountCount, writableAccountCount };
47453
+ }
47454
+ function computeFlashLoanNonSwapBudget({
46893
47455
  program,
46894
- bank,
46895
- tokenProgram,
46896
- amount,
46897
- authority,
46898
- accountAddress,
46899
- repayAll = false,
46900
- isSync = false,
46901
- opts = {}
47456
+ marginfiAccount,
47457
+ ixs,
47458
+ bankMap,
47459
+ addressLookupTableAccounts
46902
47460
  }) {
46903
- const wrapAndUnwrapSol = opts.wrapAndUnwrapSol ?? true;
46904
- const wSolBalanceUi = opts.wSolBalanceUi ?? 0;
46905
- const repayIxs = [];
46906
- const userAta = getAssociatedTokenAddressSync(bank.mint, authority, true, tokenProgram);
46907
- const remainingAccounts = tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? [{ pubkey: bank.mint, isSigner: false, isWritable: false }] : [];
46908
- if (bank.mint.equals(NATIVE_MINT) && wrapAndUnwrapSol) {
46909
- repayIxs.push(...makeWrapSolIxs(authority, new BigNumber(amount).minus(wSolBalanceUi)));
47461
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47462
+ marginfiAccount.balances,
47463
+ ixs,
47464
+ program
47465
+ );
47466
+ const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
47467
+ const b = bankMap.get(key.toBase58());
47468
+ if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
47469
+ return b;
47470
+ });
47471
+ const endIndex = ixs.length + 1;
47472
+ const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
47473
+ program.programId,
47474
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47475
+ { endIndex: new BN11(endIndex) }
47476
+ );
47477
+ const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47478
+ const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
47479
+ program.programId,
47480
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47481
+ endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
47482
+ );
47483
+ const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
47484
+ const nonSwapMsg = new TransactionMessage({
47485
+ payerKey: marginfiAccount.authority,
47486
+ recentBlockhash: PublicKey.default.toBase58(),
47487
+ instructions: allNonSwapIxs
47488
+ }).compileToV0Message(addressLookupTableAccounts);
47489
+ const nonSwapSize = new VersionedTransaction(nonSwapMsg).serialize().length;
47490
+ const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
47491
+ const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
47492
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47493
+ 0
47494
+ );
47495
+ const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
47496
+ const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
47497
+ console.log("[flashloan-budget]", {
47498
+ method: "compiled",
47499
+ nonSwapSize,
47500
+ nonSwapTotal,
47501
+ sizeConstraint,
47502
+ maxSwapTotalAccounts
47503
+ });
47504
+ return { sizeConstraint, maxSwapTotalAccounts };
47505
+ }
47506
+ function compileFlashloanPrecheck({
47507
+ allIxs,
47508
+ payer,
47509
+ luts,
47510
+ sizeConstraint,
47511
+ swapIxCount,
47512
+ swapLutCount
47513
+ }) {
47514
+ const msg = new TransactionMessage({
47515
+ payerKey: payer,
47516
+ recentBlockhash: PublicKey.default.toBase58(),
47517
+ instructions: allIxs
47518
+ }).compileToV0Message(luts);
47519
+ const rawSize = new VersionedTransaction(msg).serialize().length;
47520
+ const fullTxSize = rawSize + FL_IX_OVERHEAD;
47521
+ const overshoot = fullTxSize - MAX_TX_SIZE;
47522
+ const { header, staticAccountKeys, addressTableLookups } = msg;
47523
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
47524
+ const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
47525
+ const writableAccounts = writableStatic + writableLut;
47526
+ const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
47527
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47528
+ 0
47529
+ );
47530
+ console.log("[flashloan-precheck]", {
47531
+ fullTxSize,
47532
+ overshoot,
47533
+ sizeConstraint,
47534
+ writableAccounts,
47535
+ totalAccounts,
47536
+ staticKeys: staticAccountKeys.length,
47537
+ numLuts: addressTableLookups.length,
47538
+ swapIxCount,
47539
+ swapLutCount
47540
+ });
47541
+ return { fullTxSize, overshoot, writableAccounts, totalAccounts };
47542
+ }
47543
+ async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47544
+ const { bank, tokenProgram } = config;
47545
+ switch (config.type) {
47546
+ case "borrow":
47547
+ return makeBorrowIx3({
47548
+ program,
47549
+ bank,
47550
+ bankMap,
47551
+ tokenProgram,
47552
+ amount: 1,
47553
+ marginfiAccount,
47554
+ authority: marginfiAccount.authority,
47555
+ isSync: true,
47556
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
47557
+ });
47558
+ case "repay":
47559
+ return makeRepayIx3({
47560
+ program,
47561
+ bank,
47562
+ tokenProgram,
47563
+ amount: 1,
47564
+ accountAddress: marginfiAccount.address,
47565
+ authority: marginfiAccount.authority,
47566
+ repayAll: false,
47567
+ isSync: true,
47568
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
47569
+ });
47570
+ case "deposit":
47571
+ return buildDepositBudgetIx(
47572
+ config,
47573
+ program,
47574
+ marginfiAccount,
47575
+ bankMetadataMap,
47576
+ overrideInferAccounts
47577
+ );
47578
+ case "withdraw":
47579
+ return buildWithdrawBudgetIx(
47580
+ config,
47581
+ program,
47582
+ marginfiAccount,
47583
+ bankMap,
47584
+ bankMetadataMap,
47585
+ overrideInferAccounts
47586
+ );
46910
47587
  }
46911
- const repayIx = !isSync || !opts.overrideInferAccounts?.group ? await instructions_default.makeRepayIx(
47588
+ }
47589
+ async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
47590
+ const { bank, tokenProgram } = config;
47591
+ const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
47592
+ switch (bank.config.assetTag) {
47593
+ case 3 /* KAMINO */: {
47594
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47595
+ if (!reserve) {
47596
+ throw TransactionBuildingError.kaminoReserveNotFound(
47597
+ bank.address.toBase58(),
47598
+ bank.mint.toBase58(),
47599
+ bank.tokenSymbol
47600
+ );
47601
+ }
47602
+ return makeKaminoDepositIx3({
47603
+ program,
47604
+ bank,
47605
+ tokenProgram,
47606
+ amount: 1,
47607
+ accountAddress: marginfiAccount.address,
47608
+ authority: marginfiAccount.authority,
47609
+ group: marginfiAccount.group,
47610
+ reserve,
47611
+ isSync: true,
47612
+ opts
47613
+ });
47614
+ }
47615
+ case 4 /* DRIFT */: {
47616
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47617
+ if (!driftState) {
47618
+ throw TransactionBuildingError.driftStateNotFound(
47619
+ bank.address.toBase58(),
47620
+ bank.mint.toBase58(),
47621
+ bank.tokenSymbol
47622
+ );
47623
+ }
47624
+ return makeDriftDepositIx3({
47625
+ program,
47626
+ bank,
47627
+ tokenProgram,
47628
+ amount: 1,
47629
+ accountAddress: marginfiAccount.address,
47630
+ authority: marginfiAccount.authority,
47631
+ group: marginfiAccount.group,
47632
+ driftMarketIndex: driftState.spotMarketState.marketIndex,
47633
+ driftOracle: driftState.spotMarketState.oracle,
47634
+ isSync: true,
47635
+ opts
47636
+ });
47637
+ }
47638
+ case 6 /* JUPLEND */: {
47639
+ return makeJuplendDepositIx2({
47640
+ program,
47641
+ bank,
47642
+ tokenProgram,
47643
+ amount: 1,
47644
+ accountAddress: marginfiAccount.address,
47645
+ authority: marginfiAccount.authority,
47646
+ group: marginfiAccount.group,
47647
+ isSync: true,
47648
+ opts
47649
+ });
47650
+ }
47651
+ default: {
47652
+ return makeDepositIx3({
47653
+ program,
47654
+ bank,
47655
+ tokenProgram,
47656
+ amount: 1,
47657
+ accountAddress: marginfiAccount.address,
47658
+ authority: marginfiAccount.authority,
47659
+ group: marginfiAccount.group,
47660
+ isSync: true,
47661
+ opts
47662
+ });
47663
+ }
47664
+ }
47665
+ }
47666
+ async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47667
+ const { bank, tokenProgram } = config;
47668
+ const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
47669
+ switch (bank.config.assetTag) {
47670
+ case 3 /* KAMINO */: {
47671
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47672
+ if (!reserve) {
47673
+ throw TransactionBuildingError.kaminoReserveNotFound(
47674
+ bank.address.toBase58(),
47675
+ bank.mint.toBase58(),
47676
+ bank.tokenSymbol
47677
+ );
47678
+ }
47679
+ return makeKaminoWithdrawIx3({
47680
+ program,
47681
+ bank,
47682
+ bankMap,
47683
+ tokenProgram,
47684
+ cTokenAmount: 1,
47685
+ marginfiAccount,
47686
+ authority: marginfiAccount.authority,
47687
+ reserve,
47688
+ withdrawAll: false,
47689
+ isSync: true,
47690
+ opts
47691
+ });
47692
+ }
47693
+ case 4 /* DRIFT */: {
47694
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47695
+ if (!driftState) {
47696
+ throw TransactionBuildingError.driftStateNotFound(
47697
+ bank.address.toBase58(),
47698
+ bank.mint.toBase58(),
47699
+ bank.tokenSymbol
47700
+ );
47701
+ }
47702
+ return makeDriftWithdrawIx3({
47703
+ program,
47704
+ bank,
47705
+ bankMap,
47706
+ tokenProgram,
47707
+ amount: 1,
47708
+ marginfiAccount,
47709
+ authority: marginfiAccount.authority,
47710
+ driftSpotMarket: driftState.spotMarketState,
47711
+ userRewards: driftState.userRewards,
47712
+ withdrawAll: false,
47713
+ isSync: true,
47714
+ opts
47715
+ });
47716
+ }
47717
+ case 6 /* JUPLEND */: {
47718
+ const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
47719
+ if (!jupLendState) {
47720
+ throw TransactionBuildingError.jupLendStateNotFound(
47721
+ bank.address.toBase58(),
47722
+ bank.mint.toBase58(),
47723
+ bank.tokenSymbol
47724
+ );
47725
+ }
47726
+ return makeJuplendWithdrawIx2({
47727
+ program,
47728
+ bank,
47729
+ bankMap,
47730
+ tokenProgram,
47731
+ amount: 1,
47732
+ marginfiAccount,
47733
+ authority: marginfiAccount.authority,
47734
+ jupLendingState: jupLendState.jupLendingState,
47735
+ withdrawAll: false,
47736
+ opts
47737
+ });
47738
+ }
47739
+ default: {
47740
+ return makeWithdrawIx3({
47741
+ program,
47742
+ bank,
47743
+ bankMap,
47744
+ tokenProgram,
47745
+ amount: 1,
47746
+ marginfiAccount,
47747
+ authority: marginfiAccount.authority,
47748
+ withdrawAll: false,
47749
+ isSync: true,
47750
+ opts
47751
+ });
47752
+ }
47753
+ }
47754
+ }
47755
+ async function computeFlashloanSwapConstraints({
47756
+ program,
47757
+ marginfiAccount,
47758
+ bankMap,
47759
+ addressLookupTableAccounts,
47760
+ bankMetadataMap,
47761
+ primaryIx,
47762
+ secondaryIx,
47763
+ overrideInferAccounts
47764
+ }) {
47765
+ const cuRequestIxs = [
47766
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47767
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47768
+ ];
47769
+ const [primaryResult, secondaryResult] = await Promise.all([
47770
+ buildBudgetIx(
47771
+ primaryIx,
47772
+ program,
47773
+ marginfiAccount,
47774
+ bankMap,
47775
+ bankMetadataMap,
47776
+ overrideInferAccounts
47777
+ ),
47778
+ buildBudgetIx(
47779
+ secondaryIx,
47780
+ program,
47781
+ marginfiAccount,
47782
+ bankMap,
47783
+ bankMetadataMap,
47784
+ overrideInferAccounts
47785
+ )
47786
+ ]);
47787
+ return computeFlashLoanNonSwapBudget({
46912
47788
  program,
47789
+ marginfiAccount,
47790
+ bankMap,
47791
+ addressLookupTableAccounts,
47792
+ ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
47793
+ });
47794
+ }
47795
+
47796
+ // src/services/account/actions/flash-loan.ts
47797
+ async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
47798
+ const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
47799
+ program.programId,
46913
47800
  {
46914
- marginfiAccount: accountAddress,
46915
- signerTokenAccount: userAta,
46916
- bank: bank.address,
46917
- tokenProgram,
46918
- authority: opts.overrideInferAccounts?.authority ?? authority,
46919
- group: opts.overrideInferAccounts?.group,
46920
- liquidityVault: opts.overrideInferAccounts?.liquidityVault
47801
+ marginfiAccount: marginfiAccountPk,
47802
+ authority
46921
47803
  },
46922
- { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46923
- remainingAccounts
46924
- ) : sync_instructions_default.makeRepayIx(
47804
+ { endIndex: new BN11(endIndex) }
47805
+ ) : await instructions_default.makeBeginFlashLoanIx(
47806
+ program,
47807
+ {
47808
+ marginfiAccount: marginfiAccountPk,
47809
+ authority
47810
+ },
47811
+ { endIndex: new BN11(endIndex) }
47812
+ );
47813
+ return { instructions: [ix], keys: [] };
47814
+ }
47815
+ async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
47816
+ const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47817
+ const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
46925
47818
  program.programId,
46926
47819
  {
46927
- marginfiAccount: accountAddress,
46928
- signerTokenAccount: userAta,
46929
- bank: bank.address,
46930
- tokenProgram,
46931
- authority: opts.overrideInferAccounts?.authority ?? authority,
46932
- group: opts.overrideInferAccounts?.group
47820
+ marginfiAccount: marginfiAccountPk,
47821
+ authority
46933
47822
  },
46934
- { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46935
- remainingAccounts
47823
+ remainingAccounts.map((account) => ({
47824
+ pubkey: account,
47825
+ isSigner: false,
47826
+ isWritable: false
47827
+ }))
47828
+ ) : await instructions_default.makeEndFlashLoanIx(
47829
+ program,
47830
+ {
47831
+ marginfiAccount: marginfiAccountPk,
47832
+ authority
47833
+ },
47834
+ remainingAccounts.map((account) => ({
47835
+ pubkey: account,
47836
+ isSigner: false,
47837
+ isWritable: false
47838
+ }))
46936
47839
  );
46937
- repayIxs.push(repayIx);
46938
- return {
46939
- instructions: repayIxs,
46940
- keys: []
46941
- };
47840
+ return { instructions: [ix], keys: [] };
46942
47841
  }
46943
- async function makeRepayTx(params) {
46944
- const { luts, ...depositIxParams } = params;
46945
- const ixs = await makeRepayIx3(depositIxParams);
46946
- const tx = new Transaction().add(...ixs.instructions);
46947
- tx.feePayer = params.authority;
46948
- const solanaTx = addTransactionMetadata(tx, {
46949
- type: "REPAY" /* REPAY */,
46950
- signers: ixs.keys,
46951
- addressLookupTables: luts
47842
+ async function makeFlashLoanTx({
47843
+ program,
47844
+ marginfiAccount,
47845
+ ixs,
47846
+ bankMap,
47847
+ blockhash,
47848
+ addressLookupTableAccounts,
47849
+ signers,
47850
+ isSync
47851
+ }) {
47852
+ const endIndex = ixs.length + 1;
47853
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47854
+ marginfiAccount.balances,
47855
+ ixs,
47856
+ program
47857
+ );
47858
+ const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
47859
+ const b = bankMap.get(account.toBase58());
47860
+ if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
47861
+ return b;
46952
47862
  });
46953
- return solanaTx;
47863
+ const beginFlashLoanIx = await makeBeginFlashLoanIx3(
47864
+ program,
47865
+ marginfiAccount.address,
47866
+ endIndex,
47867
+ marginfiAccount.authority,
47868
+ isSync
47869
+ );
47870
+ const endFlashLoanIx = await makeEndFlashLoanIx3(
47871
+ program,
47872
+ marginfiAccount.address,
47873
+ projectedActiveBanks,
47874
+ marginfiAccount.authority,
47875
+ isSync
47876
+ );
47877
+ const message = new TransactionMessage({
47878
+ payerKey: marginfiAccount.authority,
47879
+ recentBlockhash: blockhash,
47880
+ instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
47881
+ }).compileToV0Message(addressLookupTableAccounts);
47882
+ const tx = addTransactionMetadata(new VersionedTransaction(message), {
47883
+ addressLookupTables: addressLookupTableAccounts,
47884
+ type: "FLASHLOAN" /* FLASHLOAN */,
47885
+ signers
47886
+ });
47887
+ if (signers) {
47888
+ tx.sign(signers);
47889
+ }
47890
+ return tx;
46954
47891
  }
46955
- async function makeRepayWithCollatTx(params) {
47892
+
47893
+ // src/services/account/actions/loop.ts
47894
+ async function makeLoopTx(params) {
46956
47895
  const {
46957
47896
  program,
46958
47897
  marginfiAccount,
46959
47898
  bankMap,
46960
- withdrawOpts,
46961
- repayOpts,
47899
+ depositOpts,
47900
+ borrowOpts,
46962
47901
  bankMetadataMap,
46963
47902
  addressLookupTableAccounts,
46964
47903
  connection,
46965
47904
  oraclePrices,
46966
- crossbarUrl
47905
+ crossbarUrl,
47906
+ additionalIxs = []
46967
47907
  } = params;
46968
47908
  const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
46969
47909
  const setupIxs = await makeSetupIx({
@@ -46971,34 +47911,34 @@ async function makeRepayWithCollatTx(params) {
46971
47911
  authority: marginfiAccount.authority,
46972
47912
  tokens: [
46973
47913
  {
46974
- mint: repayOpts.repayBank.mint,
46975
- tokenProgram: repayOpts.tokenProgram
47914
+ mint: borrowOpts.borrowBank.mint,
47915
+ tokenProgram: borrowOpts.tokenProgram
46976
47916
  },
46977
47917
  {
46978
- mint: withdrawOpts.withdrawBank.mint,
46979
- tokenProgram: withdrawOpts.tokenProgram
47918
+ mint: depositOpts.depositBank.mint,
47919
+ tokenProgram: depositOpts.tokenProgram
46980
47920
  }
46981
47921
  ]
46982
47922
  });
46983
- const updateJuplendMarketIxs = makeUpdateJupLendRateIxs(
46984
- marginfiAccount,
46985
- bankMap,
46986
- [withdrawOpts.withdrawBank.address],
46987
- bankMetadataMap
47923
+ const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
47924
+ params.marginfiAccount,
47925
+ params.bankMap,
47926
+ [depositOpts.depositBank.address],
47927
+ params.bankMetadataMap
46988
47928
  );
46989
47929
  const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
46990
- marginfiAccount,
46991
- bankMap,
46992
- [withdrawOpts.withdrawBank.address],
46993
- bankMetadataMap
47930
+ params.marginfiAccount,
47931
+ params.bankMap,
47932
+ [depositOpts.depositBank.address],
47933
+ params.bankMetadataMap
46994
47934
  );
46995
47935
  const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
46996
47936
  marginfiAccount,
46997
47937
  bankMap,
46998
- [withdrawOpts.withdrawBank.address, repayOpts.repayBank.address],
47938
+ [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
46999
47939
  bankMetadataMap
47000
47940
  );
47001
- const { flashloanTx, setupInstructions, swapQuote, amountToRepay, withdrawIxs, repayIxs } = await buildRepayWithCollatFlashloanTx({
47941
+ const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
47002
47942
  ...params,
47003
47943
  blockhash
47004
47944
  });
@@ -47008,7 +47948,7 @@ async function makeRepayWithCollatTx(params) {
47008
47948
  }
47009
47949
  if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
47010
47950
  const mintKey = ix.keys[3]?.pubkey;
47011
- if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(repayOpts.repayBank.mint)) {
47951
+ if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
47012
47952
  return false;
47013
47953
  }
47014
47954
  }
@@ -47020,18 +47960,24 @@ async function makeRepayWithCollatTx(params) {
47020
47960
  bankMap,
47021
47961
  oraclePrices,
47022
47962
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
47023
- instructions: [...withdrawIxs.instructions, ...repayIxs.instructions],
47963
+ instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
47024
47964
  program,
47025
47965
  connection,
47026
47966
  crossbarUrl
47027
47967
  });
47028
47968
  let additionalTxs = [];
47029
- if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJuplendMarketIxs.instructions.length > 0) {
47969
+ if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
47970
+ setupIxs.push(
47971
+ ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
47972
+ );
47973
+ }
47974
+ if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
47030
47975
  const ixs = [
47976
+ ...additionalIxs,
47031
47977
  ...setupIxs,
47032
47978
  ...kaminoRefreshIxs.instructions,
47033
47979
  ...updateDriftMarketIxs.instructions,
47034
- ...updateJuplendMarketIxs.instructions
47980
+ ...updateJupLendRateIxs.instructions
47035
47981
  ];
47036
47982
  const txs = splitInstructionsToFitTransactions([], ixs, {
47037
47983
  blockhash,
@@ -47061,110 +48007,121 @@ async function makeRepayWithCollatTx(params) {
47061
48007
  );
47062
48008
  }
47063
48009
  const transactions = [...additionalTxs, flashloanTx];
47064
- return { transactions, swapQuote, amountToRepay };
48010
+ return {
48011
+ transactions,
48012
+ actionTxIndex: transactions.length - 1,
48013
+ quoteResponse: swapQuote
48014
+ };
47065
48015
  }
47066
- async function buildRepayWithCollatFlashloanTx({
48016
+ async function buildLoopFlashloanTx({
47067
48017
  program,
47068
48018
  marginfiAccount,
47069
48019
  bankMap,
47070
- withdrawOpts,
47071
- repayOpts,
48020
+ borrowOpts,
48021
+ depositOpts,
47072
48022
  bankMetadataMap,
47073
- assetShareValueMultiplierByBank,
47074
48023
  addressLookupTableAccounts,
47075
48024
  connection,
47076
48025
  swapOpts,
47077
48026
  overrideInferAccounts,
47078
48027
  blockhash
47079
48028
  }) {
47080
- const swapResult = [];
47081
48029
  const cuRequestIxs = [
47082
48030
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47083
48031
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47084
48032
  ];
47085
- if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
47086
- swapResult.push({
47087
- amountToRepay: withdrawOpts.withdrawAmount,
47088
- swapInstructions: [],
47089
- setupInstructions: [],
47090
- swapLookupTables: []
47091
- });
48033
+ let amountToDeposit;
48034
+ let swapInstructions = [];
48035
+ let setupInstructions = [];
48036
+ let swapLookupTables = [];
48037
+ let swapQuote;
48038
+ let sizeConstraintUsed = 0;
48039
+ if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
48040
+ amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47092
48041
  } else {
47093
48042
  const destinationTokenAccount = getAssociatedTokenAddressSync(
47094
- new PublicKey(repayOpts.repayBank.mint),
48043
+ new PublicKey(depositOpts.depositBank.mint),
47095
48044
  marginfiAccount.authority,
47096
48045
  true,
47097
- repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
48046
+ depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47098
48047
  );
47099
- const swapResponse = await getJupiterSwapIxsForFlashloan({
47100
- quoteParams: {
47101
- inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
47102
- outputMint: repayOpts.repayBank.mint.toBase58(),
47103
- amount: uiToNative(
47104
- withdrawOpts.withdrawAmount,
47105
- withdrawOpts.withdrawBank.mintDecimals
47106
- ).toNumber(),
47107
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
47108
- slippageBps: swapOpts.jupiterOptions?.slippageBps ?? void 0,
47109
- swapMode: "ExactIn",
47110
- platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps ?? void 0,
47111
- onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
48048
+ const swapConstraints = await computeFlashloanSwapConstraints({
48049
+ program,
48050
+ marginfiAccount,
48051
+ bankMap,
48052
+ bankMetadataMap,
48053
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48054
+ primaryIx: {
48055
+ type: "borrow",
48056
+ bank: borrowOpts.borrowBank,
48057
+ tokenProgram: borrowOpts.tokenProgram
48058
+ },
48059
+ secondaryIx: {
48060
+ type: "deposit",
48061
+ bank: depositOpts.depositBank,
48062
+ tokenProgram: depositOpts.tokenProgram
47112
48063
  },
48064
+ overrideInferAccounts
48065
+ });
48066
+ const swapResponse = await getSwapIxsForFlashloan({
48067
+ inputMint: borrowOpts.borrowBank.mint.toBase58(),
48068
+ outputMint: depositOpts.depositBank.mint.toBase58(),
48069
+ amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
48070
+ swapMode: "ExactIn",
47113
48071
  authority: marginfiAccount.authority,
47114
48072
  connection,
47115
48073
  destinationTokenAccount,
47116
- configParams: swapOpts.jupiterOptions?.configParams
47117
- });
47118
- swapResponse.forEach((response) => {
47119
- const { swapInstruction, addressLookupTableAddresses, quoteResponse } = response;
47120
- const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
47121
- const outAmountThreshold = nativeToUi(
47122
- quoteResponse.otherAmountThreshold,
47123
- repayOpts.repayBank.mintDecimals
47124
- );
47125
- const amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
47126
- swapResult.push({
47127
- amountToRepay,
47128
- swapInstructions: [swapInstruction],
47129
- setupInstructions: [],
47130
- swapLookupTables: addressLookupTableAddresses,
47131
- quoteResponse
47132
- });
48074
+ swapOpts,
48075
+ sizeConstraint: swapConstraints.sizeConstraint,
48076
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47133
48077
  });
48078
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
48079
+ const outAmountThreshold = nativeToUi(
48080
+ swapResponse.quoteResponse.otherAmountThreshold,
48081
+ depositOpts.depositBank.mintDecimals
48082
+ );
48083
+ amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
48084
+ swapInstructions = swapResponse.swapInstructions;
48085
+ setupInstructions = swapResponse.setupInstructions;
48086
+ swapLookupTables = swapResponse.addressLookupTableAddresses;
48087
+ swapQuote = swapResponse.quoteResponse;
47134
48088
  }
47135
- let withdrawIxs;
47136
- switch (withdrawOpts.withdrawBank.config.assetTag) {
48089
+ const borrowIxs = await makeBorrowIx3({
48090
+ program,
48091
+ bank: borrowOpts.borrowBank,
48092
+ bankMap,
48093
+ tokenProgram: borrowOpts.tokenProgram,
48094
+ amount: borrowOpts.borrowAmount,
48095
+ marginfiAccount,
48096
+ authority: marginfiAccount.authority,
48097
+ isSync: false,
48098
+ opts: {
48099
+ createAtas: false,
48100
+ wrapAndUnwrapSol: false,
48101
+ overrideInferAccounts
48102
+ }
48103
+ });
48104
+ let depositIxs;
48105
+ switch (depositOpts.depositBank.config.assetTag) {
47137
48106
  case 3 /* KAMINO */: {
47138
- const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
48107
+ const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
47139
48108
  if (!reserve) {
47140
48109
  throw TransactionBuildingError.kaminoReserveNotFound(
47141
- withdrawOpts.withdrawBank.address.toBase58(),
47142
- withdrawOpts.withdrawBank.mint.toBase58(),
47143
- withdrawOpts.withdrawBank.tokenSymbol
48110
+ depositOpts.depositBank.address.toBase58(),
48111
+ depositOpts.depositBank.mint.toBase58(),
48112
+ depositOpts.depositBank.tokenSymbol
47144
48113
  );
47145
48114
  }
47146
- const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
47147
- const adjustedAmount = new BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
47148
- withdrawIxs = await makeKaminoWithdrawIx3({
48115
+ depositIxs = await makeKaminoDepositIx3({
47149
48116
  program,
47150
- bank: withdrawOpts.withdrawBank,
47151
- bankMap,
47152
- tokenProgram: withdrawOpts.tokenProgram,
47153
- cTokenAmount: adjustedAmount,
47154
- marginfiAccount,
48117
+ bank: depositOpts.depositBank,
48118
+ tokenProgram: depositOpts.tokenProgram,
48119
+ amount: amountToDeposit,
48120
+ accountAddress: marginfiAccount.address,
47155
48121
  authority: marginfiAccount.authority,
48122
+ group: marginfiAccount.group,
47156
48123
  reserve,
47157
- withdrawAll: isWholePosition(
47158
- {
47159
- amount: withdrawOpts.totalPositionAmount,
47160
- isLending: true
47161
- },
47162
- withdrawOpts.withdrawAmount,
47163
- withdrawOpts.withdrawBank.mintDecimals
47164
- ),
47165
- isSync: false,
47166
48124
  opts: {
47167
- createAtas: false,
47168
48125
  wrapAndUnwrapSol: false,
47169
48126
  overrideInferAccounts
47170
48127
  }
@@ -47172,35 +48129,27 @@ async function buildRepayWithCollatFlashloanTx({
47172
48129
  break;
47173
48130
  }
47174
48131
  case 4 /* DRIFT */: {
47175
- const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
48132
+ const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
47176
48133
  if (!driftState) {
47177
48134
  throw TransactionBuildingError.driftStateNotFound(
47178
- withdrawOpts.withdrawBank.address.toBase58(),
47179
- withdrawOpts.withdrawBank.mint.toBase58(),
47180
- withdrawOpts.withdrawBank.tokenSymbol
48135
+ depositOpts.depositBank.address.toBase58(),
48136
+ depositOpts.depositBank.mint.toBase58(),
48137
+ depositOpts.depositBank.tokenSymbol
47181
48138
  );
47182
48139
  }
47183
- withdrawIxs = await makeDriftWithdrawIx3({
48140
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
48141
+ const driftOracle = driftState.spotMarketState.oracle;
48142
+ depositIxs = await makeDriftDepositIx3({
47184
48143
  program,
47185
- bank: withdrawOpts.withdrawBank,
47186
- bankMap,
47187
- tokenProgram: withdrawOpts.tokenProgram,
47188
- amount: withdrawOpts.withdrawAmount,
47189
- marginfiAccount,
48144
+ bank: depositOpts.depositBank,
48145
+ tokenProgram: depositOpts.tokenProgram,
48146
+ amount: amountToDeposit,
48147
+ accountAddress: marginfiAccount.address,
47190
48148
  authority: marginfiAccount.authority,
47191
- driftSpotMarket: driftState.spotMarketState,
47192
- userRewards: driftState.userRewards,
47193
- withdrawAll: isWholePosition(
47194
- {
47195
- amount: withdrawOpts.totalPositionAmount,
47196
- isLending: true
47197
- },
47198
- withdrawOpts.withdrawAmount,
47199
- withdrawOpts.withdrawBank.mintDecimals
47200
- ),
47201
- isSync: false,
48149
+ group: marginfiAccount.group,
48150
+ driftMarketIndex,
48151
+ driftOracle,
47202
48152
  opts: {
47203
- createAtas: false,
47204
48153
  wrapAndUnwrapSol: false,
47205
48154
  overrideInferAccounts
47206
48155
  }
@@ -47208,33 +48157,15 @@ async function buildRepayWithCollatFlashloanTx({
47208
48157
  break;
47209
48158
  }
47210
48159
  case 6 /* JUPLEND */: {
47211
- const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
47212
- if (!jupLendState) {
47213
- throw TransactionBuildingError.jupLendStateNotFound(
47214
- withdrawOpts.withdrawBank.address.toBase58(),
47215
- withdrawOpts.withdrawBank.mint.toBase58(),
47216
- withdrawOpts.withdrawBank.tokenSymbol
47217
- );
47218
- }
47219
- withdrawIxs = await makeJuplendWithdrawIx2({
48160
+ depositIxs = await makeJuplendDepositIx2({
47220
48161
  program,
47221
- bank: withdrawOpts.withdrawBank,
47222
- bankMap,
47223
- tokenProgram: withdrawOpts.tokenProgram,
47224
- amount: withdrawOpts.withdrawAmount,
47225
- marginfiAccount,
48162
+ bank: depositOpts.depositBank,
48163
+ tokenProgram: depositOpts.tokenProgram,
48164
+ amount: amountToDeposit,
48165
+ accountAddress: marginfiAccount.address,
47226
48166
  authority: marginfiAccount.authority,
47227
- jupLendingState: jupLendState.jupLendingState,
47228
- withdrawAll: isWholePosition(
47229
- {
47230
- amount: withdrawOpts.totalPositionAmount,
47231
- isLending: true
47232
- },
47233
- withdrawOpts.withdrawAmount,
47234
- withdrawOpts.withdrawBank.mintDecimals
47235
- ),
48167
+ group: marginfiAccount.group,
47236
48168
  opts: {
47237
- createAtas: false,
47238
48169
  wrapAndUnwrapSol: false,
47239
48170
  overrideInferAccounts
47240
48171
  }
@@ -47242,25 +48173,15 @@ async function buildRepayWithCollatFlashloanTx({
47242
48173
  break;
47243
48174
  }
47244
48175
  default: {
47245
- withdrawIxs = await makeWithdrawIx3({
48176
+ depositIxs = await makeDepositIx3({
47246
48177
  program,
47247
- bank: withdrawOpts.withdrawBank,
47248
- bankMap,
47249
- tokenProgram: withdrawOpts.tokenProgram,
47250
- amount: withdrawOpts.withdrawAmount,
47251
- marginfiAccount,
48178
+ bank: depositOpts.depositBank,
48179
+ tokenProgram: depositOpts.tokenProgram,
48180
+ amount: amountToDeposit,
48181
+ accountAddress: marginfiAccount.address,
47252
48182
  authority: marginfiAccount.authority,
47253
- withdrawAll: isWholePosition(
47254
- {
47255
- amount: withdrawOpts.totalPositionAmount,
47256
- isLending: true
47257
- },
47258
- withdrawOpts.withdrawAmount,
47259
- withdrawOpts.withdrawBank.mintDecimals
47260
- ),
47261
- isSync: false,
48183
+ group: marginfiAccount.group,
47262
48184
  opts: {
47263
- createAtas: false,
47264
48185
  wrapAndUnwrapSol: false,
47265
48186
  overrideInferAccounts
47266
48187
  }
@@ -47268,68 +48189,48 @@ async function buildRepayWithCollatFlashloanTx({
47268
48189
  break;
47269
48190
  }
47270
48191
  }
47271
- for (const [index, item] of swapResult.entries()) {
47272
- const { amountToRepay, swapInstructions, setupInstructions, swapLookupTables, quoteResponse } = item;
47273
- const repayIxs = await makeRepayIx3({
47274
- program,
47275
- bank: repayOpts.repayBank,
47276
- tokenProgram: repayOpts.tokenProgram,
47277
- amount: amountToRepay,
47278
- accountAddress: marginfiAccount.address,
47279
- authority: marginfiAccount.authority,
47280
- repayAll: isWholePosition(
47281
- {
47282
- amount: repayOpts.totalPositionAmount,
47283
- isLending: true
47284
- },
47285
- amountToRepay,
47286
- repayOpts.repayBank.mintDecimals
47287
- ),
47288
- isSync: false,
47289
- opts: {
47290
- wrapAndUnwrapSol: false,
47291
- overrideInferAccounts
47292
- }
47293
- });
47294
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47295
- const flashloanParams = {
47296
- program,
47297
- marginfiAccount,
47298
- bankMap,
47299
- addressLookupTableAccounts: luts,
47300
- blockhash
47301
- };
47302
- const flashloanTx = await makeFlashLoanTx({
47303
- ...flashloanParams,
47304
- ixs: [
47305
- ...cuRequestIxs,
47306
- ...withdrawIxs.instructions,
47307
- ...swapInstructions,
47308
- ...repayIxs.instructions
47309
- ],
47310
- isSync: true
48192
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48193
+ const allNonFlIxs = [
48194
+ ...cuRequestIxs,
48195
+ ...borrowIxs.instructions,
48196
+ ...swapInstructions,
48197
+ ...depositIxs.instructions
48198
+ ];
48199
+ if (swapInstructions.length > 0) {
48200
+ compileFlashloanPrecheck({
48201
+ allIxs: allNonFlIxs,
48202
+ payer: marginfiAccount.authority,
48203
+ luts,
48204
+ sizeConstraint: sizeConstraintUsed,
48205
+ swapIxCount: swapInstructions.length,
48206
+ swapLutCount: swapLookupTables.length
47311
48207
  });
47312
- const txSize = getTxSize(flashloanTx);
47313
- const keySize = getAccountKeys(flashloanTx, luts);
47314
- const isLast = index === swapResult.length - 1;
47315
- if (txSize > MAX_TX_SIZE || keySize > 64) {
47316
- if (isLast) {
47317
- throw TransactionBuildingError.jupiterSwapSizeExceededRepay(txSize, keySize);
47318
- } else {
47319
- continue;
47320
- }
47321
- } else {
47322
- return {
47323
- flashloanTx,
47324
- setupInstructions,
47325
- swapQuote: quoteResponse,
47326
- withdrawIxs,
47327
- repayIxs,
47328
- amountToRepay
47329
- };
47330
- }
47331
48208
  }
47332
- throw new Error("Failed to build repay with collateral flashloan tx");
48209
+ const flashloanTx = await makeFlashLoanTx({
48210
+ program,
48211
+ marginfiAccount,
48212
+ bankMap,
48213
+ addressLookupTableAccounts: luts,
48214
+ blockhash,
48215
+ ixs: allNonFlIxs
48216
+ });
48217
+ const txSize = getTxSize(flashloanTx);
48218
+ const totalKeys = getTotalAccountKeys(flashloanTx);
48219
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48220
+ throw TransactionBuildingError.swapSizeExceededLoop(
48221
+ txSize,
48222
+ totalKeys,
48223
+ swapOpts.swapConfig?.provider
48224
+ );
48225
+ }
48226
+ return {
48227
+ flashloanTx,
48228
+ setupInstructions,
48229
+ swapQuote,
48230
+ borrowIxs,
48231
+ depositIxs,
48232
+ amountToDeposit
48233
+ };
47333
48234
  }
47334
48235
 
47335
48236
  // src/services/account/actions/emissions.ts
@@ -47483,11 +48384,16 @@ async function buildSwapCollateralFlashloanTx({
47483
48384
  actualWithdrawAmount,
47484
48385
  withdrawBank.mintDecimals
47485
48386
  );
47486
- const swapResult = [];
47487
48387
  const cuRequestIxs = [
47488
48388
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47489
48389
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47490
48390
  ];
48391
+ let amountToDeposit;
48392
+ let swapInstructions = [];
48393
+ let setupInstructions = [];
48394
+ let swapLookupTables = [];
48395
+ let swapQuote;
48396
+ let sizeConstraintUsed = 0;
47491
48397
  let withdrawIxs;
47492
48398
  switch (withdrawOpts.withdrawBank.config.assetTag) {
47493
48399
  case 3 /* KAMINO */: {
@@ -47597,12 +48503,7 @@ async function buildSwapCollateralFlashloanTx({
47597
48503
  }
47598
48504
  }
47599
48505
  if (depositBank.mint.equals(withdrawBank.mint)) {
47600
- swapResult.push({
47601
- amountToDeposit: actualWithdrawAmount,
47602
- swapInstructions: [],
47603
- setupInstructions: [],
47604
- swapLookupTables: []
47605
- });
48506
+ amountToDeposit = actualWithdrawAmount;
47606
48507
  } else {
47607
48508
  const destinationTokenAccount = getAssociatedTokenAddressSync(
47608
48509
  depositBank.mint,
@@ -47610,175 +48511,168 @@ async function buildSwapCollateralFlashloanTx({
47610
48511
  true,
47611
48512
  depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47612
48513
  );
47613
- const swapResponses = await getJupiterSwapIxsForFlashloan({
47614
- quoteParams: {
47615
- inputMint: withdrawBank.mint.toBase58(),
47616
- outputMint: depositBank.mint.toBase58(),
47617
- amount: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
47618
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
47619
- slippageBps: swapOpts.jupiterOptions?.slippageBps,
47620
- swapMode: "ExactIn",
47621
- platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
47622
- onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
47623
- },
48514
+ const swapConstraints = await computeFlashloanSwapConstraints({
48515
+ program,
48516
+ marginfiAccount,
48517
+ bankMap,
48518
+ bankMetadataMap,
48519
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48520
+ primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
48521
+ secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
48522
+ overrideInferAccounts
48523
+ });
48524
+ const swapResponses = await getSwapIxsForFlashloan({
48525
+ inputMint: withdrawBank.mint.toBase58(),
48526
+ outputMint: depositBank.mint.toBase58(),
48527
+ amount: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
48528
+ swapMode: "ExactIn",
47624
48529
  authority: marginfiAccount.authority,
47625
48530
  connection,
47626
48531
  destinationTokenAccount,
47627
- configParams: swapOpts.jupiterOptions?.configParams
48532
+ swapOpts,
48533
+ sizeConstraint: swapConstraints.sizeConstraint,
48534
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47628
48535
  });
47629
- swapResponses.forEach((response) => {
47630
- const outAmountThreshold = nativeToUi(
47631
- response.quoteResponse.otherAmountThreshold,
47632
- depositBank.mintDecimals
47633
- );
47634
- swapResult.push({
47635
- amountToDeposit: outAmountThreshold,
47636
- swapInstructions: [response.swapInstruction],
47637
- setupInstructions: response.setupInstructions,
47638
- swapLookupTables: response.addressLookupTableAddresses,
47639
- quoteResponse: response.quoteResponse
47640
- });
47641
- });
47642
- }
47643
- if (swapResult.length === 0) {
47644
- throw new Error(
47645
- `No swap routes found for ${withdrawBank.mint.toBase58()} -> ${depositBank.mint.toBase58()}`
48536
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
48537
+ amountToDeposit = nativeToUi(
48538
+ swapResponses.quoteResponse.otherAmountThreshold,
48539
+ depositBank.mintDecimals
47646
48540
  );
48541
+ swapInstructions = swapResponses.swapInstructions;
48542
+ setupInstructions = swapResponses.setupInstructions;
48543
+ swapLookupTables = swapResponses.addressLookupTableAddresses;
48544
+ swapQuote = swapResponses.quoteResponse;
47647
48545
  }
47648
- for (const [index, item] of swapResult.entries()) {
47649
- const {
47650
- amountToDeposit,
47651
- swapInstructions,
47652
- setupInstructions,
47653
- swapLookupTables,
47654
- quoteResponse
47655
- } = item;
47656
- let depositIxs;
47657
- switch (depositBank.config.assetTag) {
47658
- case 3 /* KAMINO */: {
47659
- const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
47660
- if (!reserve) {
47661
- throw TransactionBuildingError.kaminoReserveNotFound(
47662
- depositBank.address.toBase58(),
47663
- depositBank.mint.toBase58(),
47664
- depositBank.tokenSymbol
47665
- );
47666
- }
47667
- depositIxs = await makeKaminoDepositIx3({
47668
- program,
47669
- bank: depositBank,
47670
- tokenProgram: depositTokenProgram,
47671
- amount: amountToDeposit,
47672
- accountAddress: marginfiAccount.address,
47673
- authority: marginfiAccount.authority,
47674
- group: marginfiAccount.group,
47675
- reserve,
47676
- opts: {
47677
- wrapAndUnwrapSol: false,
47678
- overrideInferAccounts
47679
- }
47680
- });
47681
- break;
48546
+ let depositIxs;
48547
+ switch (depositBank.config.assetTag) {
48548
+ case 3 /* KAMINO */: {
48549
+ const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
48550
+ if (!reserve) {
48551
+ throw TransactionBuildingError.kaminoReserveNotFound(
48552
+ depositBank.address.toBase58(),
48553
+ depositBank.mint.toBase58(),
48554
+ depositBank.tokenSymbol
48555
+ );
47682
48556
  }
47683
- case 4 /* DRIFT */: {
47684
- const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
47685
- if (!driftState) {
47686
- throw TransactionBuildingError.driftStateNotFound(
47687
- depositBank.address.toBase58(),
47688
- depositBank.mint.toBase58(),
47689
- depositBank.tokenSymbol
47690
- );
48557
+ depositIxs = await makeKaminoDepositIx3({
48558
+ program,
48559
+ bank: depositBank,
48560
+ tokenProgram: depositTokenProgram,
48561
+ amount: amountToDeposit,
48562
+ accountAddress: marginfiAccount.address,
48563
+ authority: marginfiAccount.authority,
48564
+ group: marginfiAccount.group,
48565
+ reserve,
48566
+ opts: {
48567
+ wrapAndUnwrapSol: false,
48568
+ overrideInferAccounts
47691
48569
  }
47692
- const driftMarketIndex = driftState.spotMarketState.marketIndex;
47693
- const driftOracle = driftState.spotMarketState.oracle;
47694
- depositIxs = await makeDriftDepositIx3({
47695
- program,
47696
- bank: depositBank,
47697
- tokenProgram: depositTokenProgram,
47698
- amount: amountToDeposit,
47699
- accountAddress: marginfiAccount.address,
47700
- authority: marginfiAccount.authority,
47701
- group: marginfiAccount.group,
47702
- driftMarketIndex,
47703
- driftOracle,
47704
- opts: {
47705
- wrapAndUnwrapSol: false,
47706
- overrideInferAccounts
47707
- }
47708
- });
47709
- break;
47710
- }
47711
- case 6 /* JUPLEND */: {
47712
- depositIxs = await makeJuplendDepositIx2({
47713
- program,
47714
- bank: depositBank,
47715
- tokenProgram: depositTokenProgram,
47716
- amount: amountToDeposit,
47717
- accountAddress: marginfiAccount.address,
47718
- authority: marginfiAccount.authority,
47719
- group: marginfiAccount.group,
47720
- opts: {
47721
- wrapAndUnwrapSol: false,
47722
- overrideInferAccounts
47723
- }
47724
- });
47725
- break;
47726
- }
47727
- default: {
47728
- depositIxs = await makeDepositIx3({
47729
- program,
47730
- bank: depositBank,
47731
- tokenProgram: depositTokenProgram,
47732
- amount: amountToDeposit,
47733
- accountAddress: marginfiAccount.address,
47734
- authority: marginfiAccount.authority,
47735
- group: marginfiAccount.group,
47736
- opts: {
47737
- wrapAndUnwrapSol: false,
47738
- overrideInferAccounts
47739
- }
47740
- });
47741
- break;
47742
- }
48570
+ });
48571
+ break;
47743
48572
  }
47744
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47745
- const flashloanParams = {
47746
- program,
47747
- marginfiAccount,
47748
- bankMap,
47749
- addressLookupTableAccounts: luts,
47750
- blockhash
47751
- };
47752
- const flashloanTx = await makeFlashLoanTx({
47753
- ...flashloanParams,
47754
- ixs: [
47755
- ...cuRequestIxs,
47756
- ...withdrawIxs.instructions,
47757
- ...swapInstructions,
47758
- ...depositIxs.instructions
47759
- ],
47760
- isSync: true
47761
- });
47762
- const txSize = getTxSize(flashloanTx);
47763
- const keySize = getAccountKeys(flashloanTx, luts);
47764
- const isLast = index === swapResult.length - 1;
47765
- if (txSize > MAX_TX_SIZE || keySize > 64) {
47766
- if (isLast) {
47767
- throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
47768
- } else {
47769
- continue;
48573
+ case 4 /* DRIFT */: {
48574
+ const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
48575
+ if (!driftState) {
48576
+ throw TransactionBuildingError.driftStateNotFound(
48577
+ depositBank.address.toBase58(),
48578
+ depositBank.mint.toBase58(),
48579
+ depositBank.tokenSymbol
48580
+ );
47770
48581
  }
47771
- } else {
47772
- return {
47773
- flashloanTx,
47774
- setupInstructions,
47775
- swapQuote: quoteResponse,
47776
- withdrawIxs,
47777
- depositIxs
47778
- };
48582
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
48583
+ const driftOracle = driftState.spotMarketState.oracle;
48584
+ depositIxs = await makeDriftDepositIx3({
48585
+ program,
48586
+ bank: depositBank,
48587
+ tokenProgram: depositTokenProgram,
48588
+ amount: amountToDeposit,
48589
+ accountAddress: marginfiAccount.address,
48590
+ authority: marginfiAccount.authority,
48591
+ group: marginfiAccount.group,
48592
+ driftMarketIndex,
48593
+ driftOracle,
48594
+ opts: {
48595
+ wrapAndUnwrapSol: false,
48596
+ overrideInferAccounts
48597
+ }
48598
+ });
48599
+ break;
48600
+ }
48601
+ case 6 /* JUPLEND */: {
48602
+ depositIxs = await makeJuplendDepositIx2({
48603
+ program,
48604
+ bank: depositBank,
48605
+ tokenProgram: depositTokenProgram,
48606
+ amount: amountToDeposit,
48607
+ accountAddress: marginfiAccount.address,
48608
+ authority: marginfiAccount.authority,
48609
+ group: marginfiAccount.group,
48610
+ opts: {
48611
+ wrapAndUnwrapSol: false,
48612
+ overrideInferAccounts
48613
+ }
48614
+ });
48615
+ break;
48616
+ }
48617
+ default: {
48618
+ depositIxs = await makeDepositIx3({
48619
+ program,
48620
+ bank: depositBank,
48621
+ tokenProgram: depositTokenProgram,
48622
+ amount: amountToDeposit,
48623
+ accountAddress: marginfiAccount.address,
48624
+ authority: marginfiAccount.authority,
48625
+ group: marginfiAccount.group,
48626
+ opts: {
48627
+ wrapAndUnwrapSol: false,
48628
+ overrideInferAccounts
48629
+ }
48630
+ });
48631
+ break;
47779
48632
  }
47780
48633
  }
47781
- throw new Error("Failed to build swap collateral flashloan tx");
48634
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48635
+ const allNonFlIxs = [
48636
+ ...cuRequestIxs,
48637
+ ...withdrawIxs.instructions,
48638
+ ...swapInstructions,
48639
+ ...depositIxs.instructions
48640
+ ];
48641
+ if (swapInstructions.length > 0) {
48642
+ compileFlashloanPrecheck({
48643
+ allIxs: allNonFlIxs,
48644
+ payer: marginfiAccount.authority,
48645
+ luts,
48646
+ sizeConstraint: sizeConstraintUsed,
48647
+ swapIxCount: swapInstructions.length,
48648
+ swapLutCount: swapLookupTables.length
48649
+ });
48650
+ }
48651
+ const flashloanTx = await makeFlashLoanTx({
48652
+ program,
48653
+ marginfiAccount,
48654
+ bankMap,
48655
+ addressLookupTableAccounts: luts,
48656
+ blockhash,
48657
+ ixs: allNonFlIxs,
48658
+ isSync: true
48659
+ });
48660
+ const txSize = getTxSize(flashloanTx);
48661
+ const totalKeys = getTotalAccountKeys(flashloanTx);
48662
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48663
+ throw TransactionBuildingError.swapSizeExceededLoop(
48664
+ txSize,
48665
+ totalKeys,
48666
+ swapOpts.swapConfig?.provider
48667
+ );
48668
+ }
48669
+ return {
48670
+ flashloanTx,
48671
+ setupInstructions,
48672
+ swapQuote,
48673
+ withdrawIxs,
48674
+ depositIxs
48675
+ };
47782
48676
  }
47783
48677
  async function makeSwapDebtTx(params) {
47784
48678
  const {
@@ -47916,7 +48810,6 @@ async function buildSwapDebtFlashloanTx({
47916
48810
  throw new Error("repayAmount must be greater than 0");
47917
48811
  }
47918
48812
  const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
47919
- const swapResult = [];
47920
48813
  const cuRequestIxs = [
47921
48814
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47922
48815
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
@@ -47927,140 +48820,120 @@ async function buildSwapDebtFlashloanTx({
47927
48820
  true,
47928
48821
  repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47929
48822
  );
47930
- const jupiterApiClient = swapOpts.jupiterOptions?.configParams?.basePath ? new SwapApi(new Configuration(swapOpts.jupiterOptions.configParams)) : createJupiterApiClient(swapOpts.jupiterOptions?.configParams);
47931
- const estimateQuote = await jupiterApiClient.quoteGet({
48823
+ const { otherAmountThreshold } = await getExactOutEstimate({
47932
48824
  inputMint: borrowBank.mint.toBase58(),
47933
48825
  outputMint: repayBank.mint.toBase58(),
47934
48826
  amount: uiToNative(actualRepayAmount, repayBank.mintDecimals).toNumber(),
47935
- swapMode: "ExactOut",
47936
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
47937
- slippageBps: swapOpts.jupiterOptions?.slippageBps
48827
+ swapOpts,
48828
+ connection
47938
48829
  });
47939
- const estimatedBorrowAmount = nativeToUi(
47940
- estimateQuote.otherAmountThreshold,
47941
- borrowBank.mintDecimals
47942
- );
47943
- const swapResponses = await getJupiterSwapIxsForFlashloan({
47944
- quoteParams: {
47945
- inputMint: borrowBank.mint.toBase58(),
47946
- outputMint: repayBank.mint.toBase58(),
47947
- amount: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
47948
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
47949
- slippageBps: swapOpts.jupiterOptions?.slippageBps,
47950
- swapMode: "ExactIn",
47951
- platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
47952
- onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
47953
- },
48830
+ const estimatedBorrowAmount = nativeToUi(otherAmountThreshold, borrowBank.mintDecimals);
48831
+ const swapConstraints = await computeFlashloanSwapConstraints({
48832
+ program,
48833
+ marginfiAccount,
48834
+ bankMap,
48835
+ bankMetadataMap,
48836
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48837
+ primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
48838
+ secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
48839
+ overrideInferAccounts
48840
+ });
48841
+ const swapResponses = await getSwapIxsForFlashloan({
48842
+ inputMint: borrowBank.mint.toBase58(),
48843
+ outputMint: repayBank.mint.toBase58(),
48844
+ amount: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
48845
+ swapMode: "ExactIn",
47954
48846
  authority: marginfiAccount.authority,
47955
48847
  connection,
47956
48848
  destinationTokenAccount,
47957
- configParams: swapOpts.jupiterOptions?.configParams
48849
+ swapOpts,
48850
+ sizeConstraint: swapConstraints.sizeConstraint,
48851
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47958
48852
  });
47959
- swapResponses.forEach((response) => {
47960
- const outAmount = nativeToUi(response.quoteResponse.outAmount, repayBank.mintDecimals);
47961
- const outAmountThreshold = nativeToUi(
47962
- response.quoteResponse.otherAmountThreshold,
47963
- repayBank.mintDecimals
47964
- );
47965
- const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
47966
- const borrowAmount = nativeToUi(response.quoteResponse.inAmount, borrowBank.mintDecimals);
47967
- swapResult.push({
47968
- amountToRepay,
47969
- borrowAmount,
47970
- swapInstructions: [response.swapInstruction],
47971
- setupInstructions: response.setupInstructions,
47972
- swapLookupTables: response.addressLookupTableAddresses,
47973
- quoteResponse: response.quoteResponse
47974
- });
48853
+ const { quoteResponse } = swapResponses;
48854
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
48855
+ const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
48856
+ const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
48857
+ const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
48858
+ const borrowIxs = await makeBorrowIx3({
48859
+ program,
48860
+ bank: borrowBank,
48861
+ bankMap,
48862
+ tokenProgram: borrowTokenProgram,
48863
+ amount: borrowAmount,
48864
+ marginfiAccount,
48865
+ authority: marginfiAccount.authority,
48866
+ isSync: true,
48867
+ opts: {
48868
+ createAtas: false,
48869
+ wrapAndUnwrapSol: false,
48870
+ overrideInferAccounts
48871
+ }
47975
48872
  });
47976
- if (swapResult.length === 0) {
47977
- throw new Error(
47978
- `No swap routes found for ${borrowBank.mint.toBase58()} -> ${repayBank.mint.toBase58()}`
47979
- );
47980
- }
47981
- for (const [index, item] of swapResult.entries()) {
47982
- const {
48873
+ const repayIxs = await makeRepayIx3({
48874
+ program,
48875
+ bank: repayBank,
48876
+ tokenProgram: repayTokenProgram,
48877
+ amount: amountToRepay,
48878
+ accountAddress: marginfiAccount.address,
48879
+ authority: marginfiAccount.authority,
48880
+ repayAll: isWholePosition(
48881
+ {
48882
+ amount: totalPositionAmount,
48883
+ isLending: false
48884
+ },
47983
48885
  amountToRepay,
47984
- borrowAmount,
47985
- swapInstructions,
47986
- setupInstructions,
47987
- swapLookupTables,
47988
- quoteResponse
47989
- } = item;
47990
- const borrowIxs = await makeBorrowIx3({
47991
- program,
47992
- bank: borrowBank,
47993
- bankMap,
47994
- tokenProgram: borrowTokenProgram,
47995
- amount: borrowAmount,
47996
- marginfiAccount,
47997
- authority: marginfiAccount.authority,
47998
- isSync: true,
47999
- opts: {
48000
- createAtas: false,
48001
- wrapAndUnwrapSol: false,
48002
- overrideInferAccounts
48003
- }
48004
- });
48005
- const repayIxs = await makeRepayIx3({
48006
- program,
48007
- bank: repayBank,
48008
- tokenProgram: repayTokenProgram,
48009
- amount: amountToRepay,
48010
- accountAddress: marginfiAccount.address,
48011
- authority: marginfiAccount.authority,
48012
- repayAll: isWholePosition(
48013
- {
48014
- amount: totalPositionAmount,
48015
- isLending: false
48016
- },
48017
- amountToRepay,
48018
- repayBank.mintDecimals
48019
- ),
48020
- isSync: true,
48021
- opts: {
48022
- wrapAndUnwrapSol: false,
48023
- overrideInferAccounts
48024
- }
48025
- });
48026
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48027
- const flashloanParams = {
48028
- program,
48029
- marginfiAccount,
48030
- bankMap,
48031
- addressLookupTableAccounts: luts,
48032
- blockhash
48033
- };
48034
- const flashloanTx = await makeFlashLoanTx({
48035
- ...flashloanParams,
48036
- ixs: [
48037
- ...cuRequestIxs,
48038
- ...borrowIxs.instructions,
48039
- ...swapInstructions,
48040
- ...repayIxs.instructions
48041
- ],
48042
- isSync: true
48043
- });
48044
- const txSize = getTxSize(flashloanTx);
48045
- const keySize = getAccountKeys(flashloanTx, luts);
48046
- const isLast = index === swapResult.length - 1;
48047
- if (txSize > MAX_TX_SIZE || keySize > 64) {
48048
- if (isLast) {
48049
- throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
48050
- } else {
48051
- continue;
48052
- }
48053
- } else {
48054
- return {
48055
- flashloanTx,
48056
- setupInstructions,
48057
- swapQuote: quoteResponse,
48058
- borrowIxs,
48059
- repayIxs
48060
- };
48886
+ repayBank.mintDecimals
48887
+ ),
48888
+ isSync: true,
48889
+ opts: {
48890
+ wrapAndUnwrapSol: false,
48891
+ overrideInferAccounts
48061
48892
  }
48893
+ });
48894
+ const luts = [
48895
+ ...addressLookupTableAccounts ?? [],
48896
+ ...swapResponses.addressLookupTableAddresses
48897
+ ];
48898
+ const allNonFlIxs = [
48899
+ ...cuRequestIxs,
48900
+ ...borrowIxs.instructions,
48901
+ ...swapResponses.swapInstructions,
48902
+ ...repayIxs.instructions
48903
+ ];
48904
+ compileFlashloanPrecheck({
48905
+ allIxs: allNonFlIxs,
48906
+ payer: marginfiAccount.authority,
48907
+ luts,
48908
+ sizeConstraint: swapConstraints.sizeConstraint,
48909
+ swapIxCount: swapResponses.swapInstructions.length,
48910
+ swapLutCount: swapResponses.addressLookupTableAddresses.length
48911
+ });
48912
+ const flashloanTx = await makeFlashLoanTx({
48913
+ program,
48914
+ marginfiAccount,
48915
+ bankMap,
48916
+ addressLookupTableAccounts: luts,
48917
+ blockhash,
48918
+ ixs: allNonFlIxs,
48919
+ isSync: true
48920
+ });
48921
+ const txSize = getTxSize(flashloanTx);
48922
+ const totalKeys = getTotalAccountKeys(flashloanTx);
48923
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48924
+ throw TransactionBuildingError.swapSizeExceededLoop(
48925
+ txSize,
48926
+ totalKeys,
48927
+ swapOpts.swapConfig?.provider
48928
+ );
48062
48929
  }
48063
- throw new Error("Failed to build swap debt flashloan tx");
48930
+ return {
48931
+ flashloanTx,
48932
+ setupInstructions: swapResponses.setupInstructions,
48933
+ swapQuote: quoteResponse,
48934
+ borrowIxs,
48935
+ repayIxs
48936
+ };
48064
48937
  }
48065
48938
  var SYSVAR_CLOCK_ID2 = new PublicKey("SysvarC1ock11111111111111111111111111111111");
48066
48939
  async function makeMintStakedLstIx(params) {
@@ -48859,17 +49732,528 @@ function computeMaxWithdrawForBank(params) {
48859
49732
  const maxWithdraw = initUntiedCollateralForBank.div(initWeightedPrice);
48860
49733
  return maxWithdraw;
48861
49734
  }
49735
+ var TITAN_FEE_WALLET = new PublicKey("6ryqDDCwKFZfSiHQrYRkjTEarbsLjg9TmuFg1RJorBk3");
49736
+ var getTitanFeeAccount = (mint) => {
49737
+ return getAssociatedTokenAddressSync(mint, TITAN_FEE_WALLET, true);
49738
+ };
49739
+ var checkTitanFeeAccount = async (connection, mint) => {
49740
+ const feeAccount = getTitanFeeAccount(mint);
49741
+ const hasFeeAccount = !!await connection.getAccountInfo(feeAccount);
49742
+ return { feeAccount, hasFeeAccount, feeWallet: TITAN_FEE_WALLET };
49743
+ };
49744
+ function deserializeTitanInstruction(ix) {
49745
+ return new TransactionInstruction({
49746
+ programId: new PublicKey(ix.p),
49747
+ keys: ix.a.map((account) => ({
49748
+ pubkey: new PublicKey(account.p),
49749
+ isSigner: account.s,
49750
+ isWritable: account.w
49751
+ })),
49752
+ data: Buffer.from(ix.d)
49753
+ });
49754
+ }
49755
+ var getTitanSwapIxsForFlashloan = async ({
49756
+ quoteParams,
49757
+ authority,
49758
+ connection,
49759
+ destinationTokenAccount,
49760
+ apiConfig
49761
+ }) => {
49762
+ const basePath = apiConfig?.basePath ?? "";
49763
+ const feeMint = new PublicKey(
49764
+ quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint
49765
+ );
49766
+ const { feeAccount, hasFeeAccount } = await checkTitanFeeAccount(connection, feeMint);
49767
+ let finalQuoteParams = quoteParams;
49768
+ if (!hasFeeAccount) {
49769
+ console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
49770
+ finalQuoteParams = {
49771
+ ...quoteParams,
49772
+ platformFeeBps: void 0
49773
+ };
49774
+ }
49775
+ if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
49776
+ return getTitanSwapIxsViaWebSocket(
49777
+ { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49778
+ hasFeeAccount ? feeAccount : void 0
49779
+ );
49780
+ } else {
49781
+ return getTitanSwapIxsViaHttpProxy(
49782
+ { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49783
+ hasFeeAccount ? feeAccount : void 0
49784
+ );
49785
+ }
49786
+ };
49787
+ async function getTitanSwapIxsViaWebSocket(params, feeAccount) {
49788
+ const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
49789
+ const {
49790
+ inputMint,
49791
+ outputMint,
49792
+ amount,
49793
+ swapMode,
49794
+ slippageBps,
49795
+ platformFeeBps,
49796
+ directRoutesOnly,
49797
+ sizeConstraint,
49798
+ maxSwapAccounts,
49799
+ maxSwapTotalAccounts
49800
+ } = quoteParams;
49801
+ const wsUrl = apiConfig?.basePath;
49802
+ if (!wsUrl) {
49803
+ throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
49804
+ }
49805
+ const txParams = {
49806
+ userPublicKey: authority.toBytes(),
49807
+ outputAccount: destinationTokenAccount.toBytes()
49808
+ };
49809
+ if (feeAccount && platformFeeBps) {
49810
+ txParams.feeBps = platformFeeBps;
49811
+ txParams.feeAccount = feeAccount.toBytes();
49812
+ }
49813
+ const client = await V1Client.connect(wsUrl);
49814
+ try {
49815
+ const { stream } = await client.newSwapQuoteStream({
49816
+ swap: {
49817
+ inputMint: new PublicKey(inputMint).toBytes(),
49818
+ outputMint: new PublicKey(outputMint).toBytes(),
49819
+ amount,
49820
+ swapMode,
49821
+ slippageBps,
49822
+ onlyDirectRoutes: directRoutesOnly,
49823
+ addSizeConstraint: sizeConstraint !== void 0,
49824
+ sizeConstraint,
49825
+ accountsLimitWritable: maxSwapAccounts,
49826
+ accountsLimitTotal: maxSwapTotalAccounts
49827
+ },
49828
+ transaction: txParams,
49829
+ update: {
49830
+ num_quotes: 3
49831
+ }
49832
+ });
49833
+ const reader = stream.getReader();
49834
+ const { value: swapQuotes, done } = await reader.read();
49835
+ reader.releaseLock();
49836
+ if (done || !swapQuotes) {
49837
+ throw new Error("Titan swap quote stream ended without data");
49838
+ }
49839
+ const quotes = swapQuotes;
49840
+ const bestRoute = selectBestRoute(quotes.quotes, swapMode);
49841
+ if (!bestRoute) {
49842
+ throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
49843
+ }
49844
+ const swapInstructions = bestRoute.instructions.map(deserializeTitanInstruction);
49845
+ const lutPubkeys = bestRoute.addressLookupTables.map((lutBytes) => new PublicKey(lutBytes));
49846
+ const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
49847
+ const quoteResponse = {
49848
+ ...buildSwapQuoteResult(bestRoute, swapMode),
49849
+ provider: "TITAN" /* TITAN */
49850
+ };
49851
+ return {
49852
+ swapInstructions,
49853
+ setupInstructions: [],
49854
+ addressLookupTableAddresses,
49855
+ quoteResponse
49856
+ };
49857
+ } finally {
49858
+ if (!client.closed) {
49859
+ await client.close();
49860
+ }
49861
+ }
49862
+ }
49863
+ async function getTitanSwapIxsViaHttpProxy(params, feeAccount) {
49864
+ const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
49865
+ const {
49866
+ inputMint,
49867
+ outputMint,
49868
+ amount,
49869
+ swapMode,
49870
+ slippageBps,
49871
+ platformFeeBps,
49872
+ directRoutesOnly,
49873
+ sizeConstraint,
49874
+ maxSwapAccounts,
49875
+ maxSwapTotalAccounts
49876
+ } = quoteParams;
49877
+ const basePath = apiConfig?.basePath;
49878
+ if (!basePath) {
49879
+ throw new Error("Titan proxy URL is required (apiConfig.basePath)");
49880
+ }
49881
+ const txBody = {
49882
+ userPublicKey: authority.toBase58(),
49883
+ outputAccount: destinationTokenAccount.toBase58()
49884
+ };
49885
+ if (feeAccount && platformFeeBps) {
49886
+ txBody.feeBps = platformFeeBps;
49887
+ txBody.feeAccount = feeAccount.toBase58();
49888
+ }
49889
+ const response = await fetch(`${basePath}/swap-quote`, {
49890
+ method: "POST",
49891
+ headers: {
49892
+ "Content-Type": "application/json",
49893
+ ...apiConfig?.headers ?? {}
49894
+ },
49895
+ body: JSON.stringify({
49896
+ swap: {
49897
+ inputMint,
49898
+ outputMint,
49899
+ amount,
49900
+ swapMode,
49901
+ slippageBps,
49902
+ onlyDirectRoutes: directRoutesOnly,
49903
+ addSizeConstraint: sizeConstraint !== void 0,
49904
+ sizeConstraint,
49905
+ accountsLimitWritable: maxSwapAccounts,
49906
+ accountsLimitTotal: maxSwapTotalAccounts
49907
+ },
49908
+ transaction: txBody
49909
+ })
49910
+ });
49911
+ if (!response.ok) {
49912
+ const errorData = await response.json().catch(() => ({}));
49913
+ throw new Error(
49914
+ `Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
49915
+ );
49916
+ }
49917
+ const data = await response.json();
49918
+ const bestRoute = selectBestRoute(data.quotes, swapMode);
49919
+ if (!bestRoute) {
49920
+ throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
49921
+ }
49922
+ const swapInstructions = bestRoute.instructions.map(deserializeSerializedInstruction);
49923
+ const lutPubkeys = bestRoute.addressLookupTables.map(
49924
+ (b64) => new PublicKey(Buffer.from(b64, "base64"))
49925
+ );
49926
+ const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
49927
+ const quoteResponse = {
49928
+ ...buildSwapQuoteResult(bestRoute, swapMode),
49929
+ provider: "TITAN" /* TITAN */
49930
+ };
49931
+ return {
49932
+ swapInstructions,
49933
+ setupInstructions: [],
49934
+ addressLookupTableAddresses,
49935
+ quoteResponse
49936
+ };
49937
+ }
49938
+ var getTitanExactOutEstimate = async (params) => {
49939
+ const basePath = params.apiConfig?.basePath ?? "";
49940
+ if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
49941
+ return getTitanExactOutViaWebSocket(params);
49942
+ } else {
49943
+ return getTitanExactOutViaHttpProxy(params);
49944
+ }
49945
+ };
49946
+ async function getTitanExactOutViaWebSocket(params) {
49947
+ const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
49948
+ const wsUrl = apiConfig?.basePath;
49949
+ if (!wsUrl) {
49950
+ throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
49951
+ }
49952
+ const client = await V1Client.connect(wsUrl);
49953
+ try {
49954
+ const { stream } = await client.newSwapQuoteStream({
49955
+ swap: {
49956
+ inputMint: new PublicKey(inputMint).toBytes(),
49957
+ outputMint: new PublicKey(outputMint).toBytes(),
49958
+ amount,
49959
+ swapMode: "ExactOut",
49960
+ slippageBps
49961
+ },
49962
+ transaction: {
49963
+ userPublicKey: new Uint8Array(32)
49964
+ // placeholder, not executing
49965
+ },
49966
+ update: {
49967
+ num_quotes: 1
49968
+ }
49969
+ });
49970
+ const reader = stream.getReader();
49971
+ const { value: swapQuotes, done } = await reader.read();
49972
+ reader.releaseLock();
49973
+ if (done || !swapQuotes) {
49974
+ throw new Error("Titan ExactOut estimate stream ended without data");
49975
+ }
49976
+ const quotes = swapQuotes;
49977
+ const bestRoute = selectBestRoute(quotes.quotes, "ExactOut");
49978
+ if (!bestRoute) {
49979
+ throw new Error(`No Titan ExactOut routes found for ${inputMint} -> ${outputMint}`);
49980
+ }
49981
+ const quoteResult = {
49982
+ ...buildSwapQuoteResult(bestRoute, "ExactOut"),
49983
+ provider: "TITAN" /* TITAN */
49984
+ };
49985
+ return {
49986
+ otherAmountThreshold: quoteResult.otherAmountThreshold,
49987
+ quoteResult
49988
+ };
49989
+ } finally {
49990
+ if (!client.closed) {
49991
+ await client.close();
49992
+ }
49993
+ }
49994
+ }
49995
+ async function getTitanExactOutViaHttpProxy(params) {
49996
+ const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
49997
+ const basePath = apiConfig?.basePath;
49998
+ if (!basePath) {
49999
+ throw new Error("Titan proxy URL is required (apiConfig.basePath)");
50000
+ }
50001
+ const response = await fetch(`${basePath}/exact-out-estimate`, {
50002
+ method: "POST",
50003
+ headers: {
50004
+ "Content-Type": "application/json",
50005
+ ...apiConfig?.headers ?? {}
50006
+ },
50007
+ body: JSON.stringify({
50008
+ inputMint,
50009
+ outputMint,
50010
+ amount,
50011
+ slippageBps
50012
+ })
50013
+ });
50014
+ if (!response.ok) {
50015
+ const errorData = await response.json().catch(() => ({}));
50016
+ throw new Error(
50017
+ `Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
50018
+ );
50019
+ }
50020
+ const data = await response.json();
50021
+ const quoteResult = {
50022
+ inAmount: String(data.inAmount),
50023
+ outAmount: String(data.outAmount),
50024
+ otherAmountThreshold: data.otherAmountThreshold,
50025
+ slippageBps: data.slippageBps,
50026
+ provider: "TITAN" /* TITAN */
50027
+ };
50028
+ return {
50029
+ otherAmountThreshold: data.otherAmountThreshold,
50030
+ quoteResult
50031
+ };
50032
+ }
50033
+
50034
+ // src/services/account/utils/swap.utils.ts
50035
+ function getSwapProviderFn({
50036
+ attemptProvider,
50037
+ maxSwapTotalAccounts,
50038
+ inputMint,
50039
+ outputMint,
50040
+ amount,
50041
+ swapMode,
50042
+ authority,
50043
+ connection,
50044
+ destinationTokenAccount,
50045
+ swapOpts,
50046
+ sizeConstraint
50047
+ }) {
50048
+ switch (attemptProvider) {
50049
+ case "TITAN" /* TITAN */:
50050
+ return (apiConfig) => getTitanSwapIxsForFlashloan({
50051
+ quoteParams: {
50052
+ inputMint,
50053
+ outputMint,
50054
+ amount,
50055
+ swapMode,
50056
+ slippageBps: swapOpts.swapConfig?.slippageBps,
50057
+ platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
50058
+ directRoutesOnly: swapOpts.swapConfig?.directRoutesOnly,
50059
+ sizeConstraint,
50060
+ maxSwapTotalAccounts
50061
+ },
50062
+ authority,
50063
+ connection,
50064
+ destinationTokenAccount,
50065
+ apiConfig
50066
+ });
50067
+ case "JUPITER" /* JUPITER */:
50068
+ return (apiConfig) => getJupiterSwapIxsForFlashloan({
50069
+ quoteParams: {
50070
+ inputMint,
50071
+ outputMint,
50072
+ amount,
50073
+ swapMode,
50074
+ dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
50075
+ slippageBps: swapOpts.swapConfig?.slippageBps,
50076
+ platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
50077
+ onlyDirectRoutes: swapOpts.swapConfig?.directRoutesOnly ?? false
50078
+ },
50079
+ authority,
50080
+ connection,
50081
+ destinationTokenAccount,
50082
+ apiConfig,
50083
+ maxSwapAccounts: maxSwapTotalAccounts
50084
+ });
50085
+ default:
50086
+ return void 0;
50087
+ }
50088
+ }
50089
+ function getExactOutProviderFn({
50090
+ attemptProvider,
50091
+ inputMint,
50092
+ outputMint,
50093
+ amount,
50094
+ swapOpts,
50095
+ apiConfig
50096
+ }) {
50097
+ switch (attemptProvider) {
50098
+ case "TITAN" /* TITAN */:
50099
+ return () => getTitanExactOutEstimate({
50100
+ inputMint,
50101
+ outputMint,
50102
+ amount,
50103
+ slippageBps: swapOpts.swapConfig?.slippageBps,
50104
+ apiConfig
50105
+ });
50106
+ case "JUPITER" /* JUPITER */:
50107
+ return async () => {
50108
+ const configParams = toJupiterConfig(apiConfig);
50109
+ const jupiterApiClient = configParams?.basePath ? new SwapApi(new Configuration(configParams)) : createJupiterApiClient(configParams);
50110
+ const estimateQuote = await jupiterApiClient.quoteGet({
50111
+ inputMint,
50112
+ outputMint,
50113
+ amount,
50114
+ swapMode: "ExactOut",
50115
+ dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
50116
+ slippageBps: swapOpts.swapConfig?.slippageBps
50117
+ });
50118
+ const quoteResult = mapJupiterQuoteToSwapQuoteResult(estimateQuote);
50119
+ return { otherAmountThreshold: quoteResult.otherAmountThreshold, quoteResult };
50120
+ };
50121
+ default:
50122
+ return void 0;
50123
+ }
50124
+ }
50125
+ var getSwapIxsForFlashloan = async (params) => {
50126
+ const {
50127
+ inputMint,
50128
+ outputMint,
50129
+ amount,
50130
+ swapMode,
50131
+ authority,
50132
+ connection,
50133
+ destinationTokenAccount,
50134
+ swapOpts,
50135
+ sizeConstraint,
50136
+ maxSwapTotalAccounts
50137
+ } = params;
50138
+ if (swapOpts.swapIxs) {
50139
+ return {
50140
+ swapInstructions: swapOpts.swapIxs.instructions,
50141
+ setupInstructions: [],
50142
+ addressLookupTableAddresses: swapOpts.swapIxs.lookupTables,
50143
+ quoteResponse: {
50144
+ inAmount: String(amount),
50145
+ outAmount: "0",
50146
+ otherAmountThreshold: "0",
50147
+ slippageBps: 0
50148
+ }
50149
+ };
50150
+ }
50151
+ const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
50152
+ const attempts = [
50153
+ { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
50154
+ ...swapOpts.swapConfig?.fallbackProviders ?? []
50155
+ ];
50156
+ let lastError;
50157
+ for (const { provider: attemptProvider, apiConfig } of attempts) {
50158
+ const fn = getSwapProviderFn({
50159
+ attemptProvider,
50160
+ maxSwapTotalAccounts: params.maxSwapTotalAccounts,
50161
+ inputMint,
50162
+ outputMint,
50163
+ amount,
50164
+ swapMode,
50165
+ authority,
50166
+ connection,
50167
+ destinationTokenAccount,
50168
+ swapOpts,
50169
+ sizeConstraint
50170
+ });
50171
+ if (!fn) continue;
50172
+ try {
50173
+ return await fn(apiConfig);
50174
+ } catch (err) {
50175
+ if (err instanceof TransactionBuildingError) throw err;
50176
+ lastError = err;
50177
+ console.warn(`[swap] ${attemptProvider} failed:`, err instanceof Error ? err.message : err);
50178
+ }
50179
+ }
50180
+ const firstProvider = attempts[0]?.provider ?? "Swap";
50181
+ throw TransactionBuildingError.swapQuoteFailed(
50182
+ firstProvider,
50183
+ inputMint,
50184
+ outputMint,
50185
+ lastError?.message ?? "No swap route available"
50186
+ );
50187
+ };
50188
+ var getExactOutEstimate = async (params) => {
50189
+ const { inputMint, outputMint, amount, swapOpts, connection } = params;
50190
+ const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
50191
+ const attempts = [
50192
+ { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
50193
+ ...swapOpts.swapConfig?.fallbackProviders ?? []
50194
+ ];
50195
+ let lastError;
50196
+ for (const { provider: attemptProvider, apiConfig } of attempts) {
50197
+ const fn = getExactOutProviderFn({
50198
+ attemptProvider,
50199
+ inputMint,
50200
+ outputMint,
50201
+ amount,
50202
+ swapOpts,
50203
+ apiConfig
50204
+ });
50205
+ if (!fn) continue;
50206
+ try {
50207
+ return await fn(apiConfig);
50208
+ } catch (err) {
50209
+ if (err instanceof TransactionBuildingError) throw err;
50210
+ lastError = err;
50211
+ console.warn(
50212
+ `[exactout] ${attemptProvider} failed:`,
50213
+ err instanceof Error ? err.message : err
50214
+ );
50215
+ }
50216
+ }
50217
+ const firstProvider = attempts[0]?.provider ?? "Swap";
50218
+ throw TransactionBuildingError.swapQuoteFailed(
50219
+ firstProvider,
50220
+ inputMint,
50221
+ outputMint,
50222
+ lastError?.message ?? "No swap route available"
50223
+ );
50224
+ };
50225
+ function mapJupiterQuoteToSwapQuoteResult(quote) {
50226
+ return {
50227
+ inAmount: quote.inAmount,
50228
+ outAmount: quote.outAmount,
50229
+ otherAmountThreshold: quote.otherAmountThreshold,
50230
+ slippageBps: quote.slippageBps,
50231
+ platformFee: quote.platformFee ? {
50232
+ amount: quote.platformFee.amount ?? "0",
50233
+ feeBps: quote.platformFee.feeBps ?? 0
50234
+ } : void 0,
50235
+ priceImpactPct: quote.priceImpactPct,
50236
+ contextSlot: quote.contextSlot,
50237
+ timeTaken: quote.timeTaken,
50238
+ provider: "JUPITER" /* JUPITER */
50239
+ };
50240
+ }
50241
+
50242
+ // src/services/account/utils/jupiter.utils.ts
48862
50243
  var REFERRAL_PROGRAM_ID = new PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
48863
50244
  var REFERRAL_ACCOUNT_PUBKEY = new PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
48864
50245
  var getFeeAccount = (mint) => {
48865
- const referralProgramPubkey = REFERRAL_PROGRAM_ID;
48866
- const referralAccountPubkey = REFERRAL_ACCOUNT_PUBKEY;
48867
50246
  const [feeAccount] = PublicKey.findProgramAddressSync(
48868
- [Buffer.from("referral_ata"), referralAccountPubkey.toBuffer(), mint.toBuffer()],
48869
- referralProgramPubkey
50247
+ [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
50248
+ REFERRAL_PROGRAM_ID
48870
50249
  );
48871
50250
  return feeAccount.toBase58();
48872
50251
  };
50252
+ var checkFeeAccount = async (connection, mint) => {
50253
+ const feeAccount = getFeeAccount(mint);
50254
+ const hasFeeAccount = !!await connection.getAccountInfo(new PublicKey(feeAccount));
50255
+ return { feeAccount, hasFeeAccount };
50256
+ };
48873
50257
  function deserializeJupiterInstruction(instruction) {
48874
50258
  return new TransactionInstruction({
48875
50259
  programId: new PublicKey(instruction.programId),
@@ -48881,17 +50265,26 @@ function deserializeJupiterInstruction(instruction) {
48881
50265
  data: Buffer.from(instruction.data, "base64")
48882
50266
  });
48883
50267
  }
50268
+ function toJupiterConfig(apiConfig) {
50269
+ if (!apiConfig) return void 0;
50270
+ return {
50271
+ basePath: apiConfig.basePath,
50272
+ apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
50273
+ headers: apiConfig.headers
50274
+ };
50275
+ }
48884
50276
  var getJupiterSwapIxsForFlashloan = async ({
48885
50277
  quoteParams,
48886
50278
  authority,
48887
50279
  connection,
48888
50280
  destinationTokenAccount,
48889
- configParams
50281
+ apiConfig,
50282
+ maxSwapAccounts
48890
50283
  }) => {
50284
+ const configParams = toJupiterConfig(apiConfig);
48891
50285
  const jupiterApiClient = configParams?.basePath ? new SwapApi(new Configuration(configParams)) : createJupiterApiClient(configParams);
48892
50286
  const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
48893
- const feeAccount = getFeeAccount(new PublicKey(feeMint));
48894
- const hasFeeAccount = !!await connection.getAccountInfo(new PublicKey(feeAccount));
50287
+ const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new PublicKey(feeMint));
48895
50288
  const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
48896
50289
  let finalQuoteParams = quoteParams;
48897
50290
  if (!hasFeeAccount) {
@@ -48901,67 +50294,44 @@ var getJupiterSwapIxsForFlashloan = async ({
48901
50294
  platformFeeBps: void 0
48902
50295
  };
48903
50296
  }
48904
- const maxAccountsArr = [40, 30];
48905
- const swapQuotes = await Promise.all(
48906
- maxAccountsArr.map((maxAccounts) => {
48907
- return jupiterApiClient.quoteGet({
48908
- ...finalQuoteParams,
48909
- maxAccounts
48910
- });
48911
- })
48912
- );
48913
- hasFeeAccount && finalQuoteParams.platformFeeBps && finalQuoteParams.platformFeeBps > 0;
48914
- const swapInstructionResponses = await Promise.all(
48915
- swapQuotes.map(
48916
- (quote) => jupiterApiClient.swapInstructionsPost({
48917
- swapRequest: {
48918
- quoteResponse: quote,
48919
- userPublicKey: authority.toBase58(),
48920
- feeAccount: hasFeeAccount ? feeAccount : void 0,
48921
- wrapAndUnwrapSol: false,
48922
- destinationTokenAccount: destinationTokenAccount.toBase58()
48923
- }
48924
- })
48925
- )
48926
- );
48927
- const lutAddresses = swapInstructionResponses.map(
48928
- (swapInstructionResponse) => swapInstructionResponse.addressLookupTableAddresses
48929
- );
50297
+ const maxAccounts = maxSwapAccounts ?? 40;
50298
+ const swapQuote = await jupiterApiClient.quoteGet({
50299
+ ...finalQuoteParams,
50300
+ maxAccounts
50301
+ });
50302
+ const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
50303
+ swapRequest: {
50304
+ quoteResponse: swapQuote,
50305
+ userPublicKey: authority.toBase58(),
50306
+ feeAccount: hasFeeAccount ? feeAccount : void 0,
50307
+ wrapAndUnwrapSol: false,
50308
+ destinationTokenAccount: destinationTokenAccount.toBase58()
50309
+ }
50310
+ });
50311
+ const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
48930
50312
  const lutAccountsRaw = await connection.getMultipleAccountsInfo(
48931
- lutAddresses.flat().map((address) => new PublicKey(address))
50313
+ lutAddresses.map((address) => new PublicKey(address))
48932
50314
  );
48933
- let currentIndex = 0;
48934
- const jupiterSwapIxs = [];
48935
- for (let i = 0; i < swapInstructionResponses.length; i++) {
48936
- const response = swapInstructionResponses[i];
48937
- const quote = swapQuotes[i];
48938
- if (!response || !quote) continue;
48939
- const address = response.addressLookupTableAddresses;
48940
- const addressesLength = address.length;
48941
- const addressesStartIndex = currentIndex;
48942
- const addressesEndIndex = addressesStartIndex + addressesLength;
48943
- currentIndex = addressesEndIndex;
48944
- const lutAccounts = lutAccountsRaw.slice(addressesStartIndex, addressesEndIndex);
48945
- const addressLookupTableAccounts = lutAccounts.map((accountInfo, index) => {
48946
- const addressLookupTableAddress = address[index];
48947
- if (!accountInfo || !addressLookupTableAddress) {
48948
- return null;
48949
- }
48950
- return new AddressLookupTableAccount({
48951
- key: new PublicKey(addressLookupTableAddress),
48952
- state: AddressLookupTableAccount.deserialize(accountInfo.data)
48953
- });
48954
- }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
48955
- const instruction = deserializeJupiterInstruction(response.swapInstruction);
48956
- const setupInstructions = response.setupInstructions.map(deserializeJupiterInstruction);
48957
- jupiterSwapIxs.push({
48958
- swapInstruction: instruction,
48959
- setupInstructions,
48960
- addressLookupTableAddresses: addressLookupTableAccounts,
48961
- quoteResponse: quote
50315
+ const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
50316
+ const addressLookupTableAddress = lutAddresses[index];
50317
+ if (!accountInfo || !addressLookupTableAddress) {
50318
+ return null;
50319
+ }
50320
+ return new AddressLookupTableAccount({
50321
+ key: new PublicKey(addressLookupTableAddress),
50322
+ state: AddressLookupTableAccount.deserialize(accountInfo.data)
48962
50323
  });
48963
- }
48964
- return jupiterSwapIxs;
50324
+ }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
50325
+ const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
50326
+ const setupInstructions = swapInstructionResponse.setupInstructions.map(
50327
+ deserializeJupiterInstruction
50328
+ );
50329
+ return {
50330
+ swapInstructions: [instruction],
50331
+ setupInstructions,
50332
+ addressLookupTableAddresses: addressLookupTableAccounts,
50333
+ quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
50334
+ };
48965
50335
  };
48966
50336
 
48967
50337
  // src/services/account/utils/misc.utils.ts
@@ -50182,7 +51552,7 @@ function computeMaxLeverage(depositBank, borrowBank, opts) {
50182
51552
  ltv
50183
51553
  };
50184
51554
  }
50185
- function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositOracleInfo, borrowOracleInfo, opts) {
51555
+ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositPriceUsd, borrowPriceUsd, opts) {
50186
51556
  const initialCollateral = toBigNumber(principal);
50187
51557
  const { maxLeverage } = computeMaxLeverage(depositBank, borrowBank, opts);
50188
51558
  let clampedLeverage = targetLeverage;
@@ -50197,7 +51567,7 @@ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank
50197
51567
  }
50198
51568
  const totalDepositAmount = initialCollateral.times(new BigNumber3(clampedLeverage));
50199
51569
  const additionalDepositAmount = totalDepositAmount.minus(initialCollateral);
50200
- const totalBorrowAmount = additionalDepositAmount.times(depositOracleInfo.priceWeighted.lowestPrice).div(borrowOracleInfo.priceWeighted.highestPrice);
51570
+ const totalBorrowAmount = additionalDepositAmount.times(new BigNumber3(depositPriceUsd)).div(new BigNumber3(borrowPriceUsd));
50201
51571
  return {
50202
51572
  totalBorrowAmount: totalBorrowAmount.decimalPlaces(
50203
51573
  borrowBank.mintDecimals,
@@ -52664,7 +54034,7 @@ var MarginfiAccount = class _MarginfiAccount {
52664
54034
  * @param params.oraclePrices - Map of current oracle prices
52665
54035
  * @param params.depositOpts - Deposit configuration (bank, amount, mode)
52666
54036
  * @param params.borrowOpts - Borrow configuration (bank, amount)
52667
- * @param params.swapOpts - Jupiter swap configuration (slippage, fees)
54037
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52668
54038
  * @param params.addressLookupTableAccounts - Address lookup tables
52669
54039
  * @param params.overrideInferAccounts - Optional account overrides
52670
54040
  * @param params.additionalIxs - Additional instructions to include
@@ -52702,7 +54072,7 @@ var MarginfiAccount = class _MarginfiAccount {
52702
54072
  * @param params.oraclePrices - Map of current oracle prices
52703
54073
  * @param params.withdrawOpts - Withdraw configuration (bank, amount)
52704
54074
  * @param params.repayOpts - Repay configuration (bank, optional amount)
52705
- * @param params.swapOpts - Jupiter swap configuration
54075
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52706
54076
  * @param params.addressLookupTableAccounts - Address lookup tables
52707
54077
  * @param params.overrideInferAccounts - Optional account overrides
52708
54078
  * @param params.additionalIxs - Additional instructions to include
@@ -52742,7 +54112,7 @@ var MarginfiAccount = class _MarginfiAccount {
52742
54112
  * @param params.oraclePrices - Map of current oracle prices
52743
54113
  * @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
52744
54114
  * @param params.depositOpts - Deposit configuration (bank, tokenProgram)
52745
- * @param params.swapOpts - Jupiter swap configuration
54115
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52746
54116
  * @param params.addressLookupTableAccounts - Address lookup tables
52747
54117
  * @param params.overrideInferAccounts - Optional account overrides
52748
54118
  * @param params.additionalIxs - Additional instructions to include
@@ -52782,7 +54152,7 @@ var MarginfiAccount = class _MarginfiAccount {
52782
54152
  * @param params.oraclePrices - Map of current oracle prices
52783
54153
  * @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
52784
54154
  * @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
52785
- * @param params.swapOpts - Jupiter swap configuration
54155
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52786
54156
  * @param params.addressLookupTableAccounts - Address lookup tables
52787
54157
  * @param params.overrideInferAccounts - Optional account overrides
52788
54158
  * @param params.additionalIxs - Additional instructions to include
@@ -54097,6 +55467,6 @@ var EmodeSettings = class _EmodeSettings {
54097
55467
  }
54098
55468
  };
54099
55469
 
54100
- export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_ORACLE_MAX_AGE, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkMultipleOraclesCrankability, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBaseInterestRate, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeHealthComponentsWithoutBiasFromBalances, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountAddresses, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isFlashloan, isV0Tx, isWeightedPrice, isWholePosition, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBundleTipIx, makeClearEmissionsIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSwapCollateralTx, makeSwapDebtTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, resolveAmount, serializeBankConfigOpt, serializeInterestRateConfig, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, toBankConfigDto, toBankDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toNumber, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
55470
+ export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_ORACLE_MAX_AGE, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_ACCOUNT_LOCKS, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, SwapProvider, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkMultipleOraclesCrankability, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, compileFlashloanPrecheck, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBaseInterestRate, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFlashLoanNonSwapBudget, computeFlashloanSwapConstraints, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeHealthComponentsWithoutBiasFromBalances, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, computeV0TxSize, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountAddresses, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getExactOutEstimate, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getSwapIxsForFlashloan, getTitanExactOutEstimate, getTitanSwapIxsForFlashloan, getTotalAccountKeys, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, getWritableAccountKeys, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isFlashloan, isV0Tx, isWeightedPrice, isWholePosition, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBundleTipIx, makeClearEmissionsIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSwapCollateralTx, makeSwapDebtTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapJupiterQuoteToSwapQuoteResult, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, resolveAmount, serializeBankConfigOpt, serializeInterestRateConfig, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, toBankConfigDto, toBankDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toJupiterConfig, toNumber, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
54101
55471
  //# sourceMappingURL=index.js.map
54102
55472
  //# sourceMappingURL=index.js.map