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

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
@@ -1,4 +1,4 @@
1
- import { PublicKey, SolanaJSONRPCError, ComputeBudgetProgram, SystemProgram, TransactionMessage, VersionedTransaction, Transaction, StakeProgram, Keypair, StakeAuthorizationLayout, AddressLookupTableAccount, SYSVAR_RENT_PUBKEY, TransactionInstruction, LAMPORTS_PER_SOL, SYSVAR_INSTRUCTIONS_PUBKEY, STAKE_CONFIG_ID as STAKE_CONFIG_ID$1 } from '@solana/web3.js';
1
+ import { PublicKey, SolanaJSONRPCError, ComputeBudgetProgram, SystemProgram, TransactionMessage, VersionedTransaction, Transaction, AddressLookupTableAccount, SYSVAR_RENT_PUBKEY, StakeProgram, TransactionInstruction, LAMPORTS_PER_SOL, Keypair, StakeAuthorizationLayout, SYSVAR_INSTRUCTIONS_PUBKEY, STAKE_CONFIG_ID as STAKE_CONFIG_ID$1 } from '@solana/web3.js';
2
2
  import { object, string, enums, array, assert } from 'superstruct';
3
3
  import BigNumber3, { BigNumber } from 'bignumber.js';
4
4
  import BN11, { BN } from 'bn.js';
@@ -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';
@@ -89,12 +91,15 @@ function getConfig(environment = "production", overrides) {
89
91
 
90
92
  // src/errors/transaction-building.errors.ts
91
93
  var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCode2) => {
92
- TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_REPAY"] = "JUPITER_SWAP_SIZE_EXCEEDED_REPAY";
93
- TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_LOOP"] = "JUPITER_SWAP_SIZE_EXCEEDED_LOOP";
94
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_LOOP"] = "SWAP_SIZE_EXCEEDED_LOOP";
95
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_REPAY"] = "SWAP_SIZE_EXCEEDED_REPAY";
96
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_POSITION_SWAP"] = "SWAP_SIZE_EXCEEDED_POSITION_SWAP";
94
97
  TransactionBuildingErrorCode2["ORACLE_CRANK_FAILED"] = "ORACLE_CRANK_FAILED";
95
98
  TransactionBuildingErrorCode2["KAMINO_RESERVE_NOT_FOUND"] = "KAMINO_RESERVE_NOT_FOUND";
96
99
  TransactionBuildingErrorCode2["DRIFT_STATE_NOT_FOUND"] = "DRIFT_STATE_NOT_FOUND";
97
100
  TransactionBuildingErrorCode2["JUPLEND_STATE_NOT_FOUND"] = "JUPLEND_STATE_NOT_FOUND";
101
+ TransactionBuildingErrorCode2["SWITCHBOARD_FEED_UPDATE_FAILED"] = "SWITCHBOARD_FEED_UPDATE_FAILED";
102
+ TransactionBuildingErrorCode2["SWAP_QUOTE_FAILED"] = "SWAP_QUOTE_FAILED";
98
103
  return TransactionBuildingErrorCode2;
99
104
  })(TransactionBuildingErrorCode || {});
100
105
  var TransactionBuildingError = class _TransactionBuildingError extends Error {
@@ -109,21 +114,25 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
109
114
  Error.captureStackTrace(this, _TransactionBuildingError);
110
115
  }
111
116
  }
112
- /**
113
- * Jupiter swap instruction size exceeds available transaction size
114
- */
115
- static jupiterSwapSizeExceededLoop(bytes, accountKeys) {
117
+ static swapSizeExceededLoop(bytes, accountKeys, provider) {
118
+ return new _TransactionBuildingError(
119
+ "SWAP_SIZE_EXCEEDED_LOOP" /* SWAP_SIZE_EXCEEDED_LOOP */,
120
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
121
+ { bytes, accountKeys, provider }
122
+ );
123
+ }
124
+ static swapSizeExceededRepay(bytes, accountKeys, provider) {
116
125
  return new _TransactionBuildingError(
117
- "JUPITER_SWAP_SIZE_EXCEEDED_LOOP" /* JUPITER_SWAP_SIZE_EXCEEDED_LOOP */,
118
- "Jupiter swap instruction size exceeds available transaction size",
119
- { bytes, accountKeys }
126
+ "SWAP_SIZE_EXCEEDED_REPAY" /* SWAP_SIZE_EXCEEDED_REPAY */,
127
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
128
+ { bytes, accountKeys, provider }
120
129
  );
121
130
  }
122
- static jupiterSwapSizeExceededRepay(bytes, accountKeys) {
131
+ static swapSizeExceededPositionSwap(bytes, accountKeys, provider) {
123
132
  return new _TransactionBuildingError(
124
- "JUPITER_SWAP_SIZE_EXCEEDED_REPAY" /* JUPITER_SWAP_SIZE_EXCEEDED_REPAY */,
125
- "Jupiter swap instruction size exceeds available transaction size",
126
- { bytes, accountKeys }
133
+ "SWAP_SIZE_EXCEEDED_POSITION_SWAP" /* SWAP_SIZE_EXCEEDED_POSITION_SWAP */,
134
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
135
+ { bytes, accountKeys, provider }
127
136
  );
128
137
  }
129
138
  /**
@@ -167,6 +176,26 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
167
176
  { bankAddress, bankMint, bankSymbol }
168
177
  );
169
178
  }
179
+ /**
180
+ * Failed to update Switchboard price feeds
181
+ */
182
+ static switchboardFeedUpdateFailed(oracleKeys, reason) {
183
+ return new _TransactionBuildingError(
184
+ "SWITCHBOARD_FEED_UPDATE_FAILED" /* SWITCHBOARD_FEED_UPDATE_FAILED */,
185
+ `Switchboard feed update failed: ${reason}`,
186
+ { oracleKeys, reason }
187
+ );
188
+ }
189
+ /**
190
+ * Failed to get a swap quote from any provider
191
+ */
192
+ static swapQuoteFailed(provider, inputMint, outputMint, reason) {
193
+ return new _TransactionBuildingError(
194
+ "SWAP_QUOTE_FAILED" /* SWAP_QUOTE_FAILED */,
195
+ `${provider} swap quote failed for ${inputMint} \u2192 ${outputMint}: ${reason}`,
196
+ { provider, inputMint, outputMint, reason }
197
+ );
198
+ }
170
199
  /**
171
200
  * Generic escape hatch for custom errors
172
201
  */
@@ -319,6 +348,7 @@ var MAX_U64 = BigInt("18446744073709551615").toString();
319
348
 
320
349
  // src/constants/transaction.consts.ts
321
350
  var MAX_TX_SIZE = 1232;
351
+ var MAX_ACCOUNT_LOCKS = 64;
322
352
  var BUNDLE_TX_SIZE = 81;
323
353
  var PRIORITY_TX_SIZE = 44;
324
354
  var WSOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
@@ -14867,8 +14897,40 @@ function getTxSize(tx) {
14867
14897
  const signaturesSize = (numRequiredSignatures - numSigners) * 64 + 1;
14868
14898
  try {
14869
14899
  const baseTxSize = isVersioned ? tx.serialize().length : tx.serialize({ requireAllSignatures: false, verifySignatures: false }).length;
14870
- return baseTxSize + feePayerSize + signaturesSize;
14871
- } catch {
14900
+ const totalSize = baseTxSize + feePayerSize + signaturesSize;
14901
+ if (isVersioned && totalSize > 1232) {
14902
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14903
+ const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
14904
+ const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
14905
+ console.warn("[getTxSize] oversized TX", {
14906
+ totalSize,
14907
+ overshoot: totalSize - 1232,
14908
+ staticKeys: staticAccountKeys.length,
14909
+ numSignatures: header.numRequiredSignatures,
14910
+ numLuts: addressTableLookups.length,
14911
+ lutWritable,
14912
+ lutReadonly,
14913
+ totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
14914
+ });
14915
+ }
14916
+ return totalSize;
14917
+ } catch (err) {
14918
+ if (isVersioned) {
14919
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14920
+ const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
14921
+ const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
14922
+ console.warn("[getTxSize] serialize failed", {
14923
+ error: err.message,
14924
+ staticKeys: staticAccountKeys.length,
14925
+ numSignatures: header.numRequiredSignatures,
14926
+ numLuts: addressTableLookups.length,
14927
+ lutWritable,
14928
+ lutReadonly,
14929
+ totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
14930
+ });
14931
+ } else {
14932
+ console.warn("[getTxSize] serialize failed", { error: err.message });
14933
+ }
14872
14934
  return 9999;
14873
14935
  }
14874
14936
  }
@@ -14883,6 +14945,47 @@ function getAccountKeys(tx, lookupTableAccounts) {
14883
14945
  } else {
14884
14946
  return tx.compileMessage().getAccountKeys().length;
14885
14947
  }
14948
+ } catch (err) {
14949
+ console.warn("[getAccountKeys] decompile failed", { error: err.message });
14950
+ return 9999;
14951
+ }
14952
+ }
14953
+ function getWritableAccountKeys(tx) {
14954
+ const isVersioned = isV0Tx(tx);
14955
+ try {
14956
+ if (isVersioned) {
14957
+ const { header, staticAccountKeys, addressTableLookups } = tx.message;
14958
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
14959
+ const writableLut = addressTableLookups.reduce(
14960
+ (sum, lookup) => sum + lookup.writableIndexes.length,
14961
+ 0
14962
+ );
14963
+ return writableStatic + writableLut;
14964
+ } else {
14965
+ const message = tx.compileMessage();
14966
+ const { numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts } = message.header;
14967
+ const totalKeys = message.accountKeys.length;
14968
+ const writableSigned = numRequiredSignatures - numReadonlySignedAccounts;
14969
+ const writableUnsigned = totalKeys - numRequiredSignatures - numReadonlyUnsignedAccounts;
14970
+ return writableSigned + writableUnsigned;
14971
+ }
14972
+ } catch {
14973
+ return 9999;
14974
+ }
14975
+ }
14976
+ function getTotalAccountKeys(tx) {
14977
+ const isVersioned = isV0Tx(tx);
14978
+ try {
14979
+ if (isVersioned) {
14980
+ const { staticAccountKeys, addressTableLookups } = tx.message;
14981
+ const lutAccounts = addressTableLookups.reduce(
14982
+ (sum, lookup) => sum + lookup.writableIndexes.length + lookup.readonlyIndexes.length,
14983
+ 0
14984
+ );
14985
+ return staticAccountKeys.length + lutAccounts;
14986
+ } else {
14987
+ return tx.compileMessage().accountKeys.length;
14988
+ }
14886
14989
  } catch {
14887
14990
  return 9999;
14888
14991
  }
@@ -20120,6 +20223,14 @@ var HealthCacheSimulationError = class _HealthCacheSimulationError extends Error
20120
20223
  }
20121
20224
  };
20122
20225
 
20226
+ // src/services/account/types/action.types.ts
20227
+ var SwapProvider = /* @__PURE__ */ ((SwapProvider2) => {
20228
+ SwapProvider2["JUPITER"] = "JUPITER";
20229
+ SwapProvider2["TITAN"] = "TITAN";
20230
+ SwapProvider2["DFLOW"] = "DFLOW";
20231
+ return SwapProvider2;
20232
+ })(SwapProvider || {});
20233
+
20123
20234
  // src/services/account/utils/deserialize.utils.ts
20124
20235
  var EMPTY_HEALTH_CACHE = {
20125
20236
  assetValue: {
@@ -44168,6 +44279,346 @@ function makeUpdateJupLendRate({ lendingState }) {
44168
44279
  lendingState.rewardsRateModel
44169
44280
  );
44170
44281
  }
44282
+ var SUBPROTOCOL = "v1.api.titan.ag";
44283
+ var UINT64_MAX = (1n << 64n) - 1n;
44284
+ function toBigInt(value) {
44285
+ if (typeof value === "bigint") {
44286
+ if (value < 0n || value > UINT64_MAX) {
44287
+ throw new RangeError(`Amount out of uint64 range: ${value}`);
44288
+ }
44289
+ return value;
44290
+ }
44291
+ if (!Number.isInteger(value)) {
44292
+ throw new TypeError(`Amount must be a whole number, got ${value}`);
44293
+ }
44294
+ if (value < 0) {
44295
+ throw new RangeError(`Amount must be non-negative, got ${value}`);
44296
+ }
44297
+ return BigInt(value);
44298
+ }
44299
+ var ConnectionClosed = class _ConnectionClosed extends Error {
44300
+ code;
44301
+ reason;
44302
+ constructor(code, reason) {
44303
+ super(`Client WebSocket closed with code ${code}: ${reason}`);
44304
+ this.name = "ConnectionClosed";
44305
+ Object.setPrototypeOf(this, _ConnectionClosed.prototype);
44306
+ this.code = code;
44307
+ this.reason = reason;
44308
+ }
44309
+ };
44310
+ var ErrorResponse = class _ErrorResponse extends Error {
44311
+ response;
44312
+ constructor(response) {
44313
+ super(`Request ${response.requestId} failed with code ${response.code}: ${response.message}`);
44314
+ this.name = "ErrorResponse";
44315
+ Object.setPrototypeOf(this, _ErrorResponse.prototype);
44316
+ this.response = response;
44317
+ }
44318
+ };
44319
+ var StreamError = class _StreamError extends Error {
44320
+ streamId;
44321
+ errorCode;
44322
+ errorMessage;
44323
+ constructor(packet) {
44324
+ const code = packet.errorCode ?? 0;
44325
+ const message = packet.errorMessage ?? "";
44326
+ super(`Stream ${packet.id} ended with error code ${code}: ${message}`);
44327
+ this.name = "StreamError";
44328
+ Object.setPrototypeOf(this, _StreamError.prototype);
44329
+ this.streamId = packet.id;
44330
+ this.errorCode = code;
44331
+ this.errorMessage = message;
44332
+ }
44333
+ };
44334
+ var encoder = new Encoder({ useBigInt64: true });
44335
+ var decoder = new Decoder({ useBigInt64: true });
44336
+ var V1Client = class _V1Client {
44337
+ socket;
44338
+ nextId = 0;
44339
+ _closed = false;
44340
+ _closing = false;
44341
+ pending = /* @__PURE__ */ new Map();
44342
+ streams = /* @__PURE__ */ new Map();
44343
+ streamStopping = /* @__PURE__ */ new Map();
44344
+ closeListeners = [];
44345
+ // --- Static connect ---
44346
+ static connect(url) {
44347
+ return new Promise((resolve, reject) => {
44348
+ const ws = new WebSocket(url, [SUBPROTOCOL]);
44349
+ ws.binaryType = "arraybuffer";
44350
+ const onOpen = () => {
44351
+ ws.off("error", onError);
44352
+ ws.off("close", onClose);
44353
+ resolve(new _V1Client(ws));
44354
+ };
44355
+ const onError = (err) => {
44356
+ ws.off("open", onOpen);
44357
+ ws.off("close", onClose);
44358
+ reject(err);
44359
+ };
44360
+ const onClose = (code, reason) => {
44361
+ ws.off("open", onOpen);
44362
+ ws.off("error", onError);
44363
+ reject(
44364
+ new Error(
44365
+ `WebSocket closed before open (code=${code}${reason.length ? `, reason=${reason.toString()}` : ""})`
44366
+ )
44367
+ );
44368
+ };
44369
+ ws.once("open", onOpen);
44370
+ ws.once("error", onError);
44371
+ ws.once("close", onClose);
44372
+ });
44373
+ }
44374
+ // --- Constructor ---
44375
+ constructor(socket) {
44376
+ this.socket = socket;
44377
+ this.socket.on("message", (data) => {
44378
+ this.handleMessage(data);
44379
+ });
44380
+ this.socket.on("close", (code, reason) => {
44381
+ this.handleClose(code, reason.toString());
44382
+ });
44383
+ this.socket.on("error", (err) => {
44384
+ this.handleError(err);
44385
+ });
44386
+ }
44387
+ nextRequestId() {
44388
+ return this.nextId++;
44389
+ }
44390
+ // --- Public API ---
44391
+ get closed() {
44392
+ return this._closed;
44393
+ }
44394
+ close() {
44395
+ if (this._closed) return Promise.resolve();
44396
+ return new Promise((resolve, reject) => {
44397
+ this.closeListeners.push({ resolve, reject });
44398
+ if (!this._closing) {
44399
+ this._closing = true;
44400
+ this.socket.close();
44401
+ }
44402
+ });
44403
+ }
44404
+ newSwapQuoteStream(params) {
44405
+ const requestId = this.nextRequestId();
44406
+ const promise = new Promise(
44407
+ (resolve, reject) => {
44408
+ this.pending.set(requestId, {
44409
+ resolve,
44410
+ reject,
44411
+ kind: "NewSwapQuoteStream"
44412
+ });
44413
+ }
44414
+ );
44415
+ const normalized = {
44416
+ ...params,
44417
+ swap: { ...params.swap, amount: toBigInt(params.swap.amount) }
44418
+ };
44419
+ const message = {
44420
+ id: requestId,
44421
+ data: { NewSwapQuoteStream: normalized }
44422
+ };
44423
+ this.send(message);
44424
+ return promise;
44425
+ }
44426
+ stopStream(streamId) {
44427
+ const requestId = this.nextRequestId();
44428
+ const promise = new Promise((resolve, reject) => {
44429
+ this.pending.set(requestId, {
44430
+ resolve,
44431
+ reject,
44432
+ kind: "StopStream"
44433
+ });
44434
+ });
44435
+ const message = {
44436
+ id: requestId,
44437
+ data: { StopStream: { id: streamId } }
44438
+ };
44439
+ this.send(message);
44440
+ return promise;
44441
+ }
44442
+ // --- Send ---
44443
+ send(message) {
44444
+ try {
44445
+ const encoded = encoder.encode(message);
44446
+ this.socket.send(encoded);
44447
+ } catch (err) {
44448
+ const req = this.pending.get(message.id);
44449
+ if (req) {
44450
+ this.pending.delete(message.id);
44451
+ req.reject(err);
44452
+ }
44453
+ }
44454
+ }
44455
+ // --- Message handling ---
44456
+ handleMessage(raw) {
44457
+ let buf;
44458
+ if (raw instanceof ArrayBuffer) {
44459
+ buf = new Uint8Array(raw);
44460
+ } else if (Buffer.isBuffer(raw)) {
44461
+ buf = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
44462
+ } else if (Array.isArray(raw)) {
44463
+ buf = new Uint8Array(Buffer.concat(raw));
44464
+ } else {
44465
+ return;
44466
+ }
44467
+ let message;
44468
+ try {
44469
+ message = decoder.decode(buf);
44470
+ } catch {
44471
+ this.socket.close(3002, "failed to decode message");
44472
+ return;
44473
+ }
44474
+ if ("Response" in message) {
44475
+ this.handleResponse(message.Response);
44476
+ } else if ("Error" in message) {
44477
+ this.handleResponseError(message.Error);
44478
+ } else if ("StreamData" in message) {
44479
+ this.handleStreamData(message.StreamData);
44480
+ } else if ("StreamEnd" in message) {
44481
+ this.handleStreamEnd(message.StreamEnd);
44482
+ }
44483
+ }
44484
+ handleResponse(msg) {
44485
+ const req = this.pending.get(msg.requestId);
44486
+ if (!req) return;
44487
+ this.pending.delete(msg.requestId);
44488
+ if ("NewSwapQuoteStream" in msg.data && req.kind === "NewSwapQuoteStream") {
44489
+ const streamInfo = msg.stream;
44490
+ if (!streamInfo) {
44491
+ req.reject(new Error("No stream associated with NewSwapQuoteStream response"));
44492
+ return;
44493
+ }
44494
+ const stream = new ReadableStream({
44495
+ start: (controller) => {
44496
+ this.streams.set(streamInfo.id, controller);
44497
+ },
44498
+ cancel: () => {
44499
+ return this.cancelStream(streamInfo.id);
44500
+ }
44501
+ });
44502
+ const result = {
44503
+ response: msg.data.NewSwapQuoteStream,
44504
+ stream,
44505
+ streamId: streamInfo.id
44506
+ };
44507
+ req.resolve(result);
44508
+ } else if ("StreamStopped" in msg.data && req.kind === "StopStream") {
44509
+ req.resolve(msg.data.StreamStopped);
44510
+ } else {
44511
+ req.reject(new Error(`Unexpected response type for ${req.kind}`));
44512
+ }
44513
+ }
44514
+ handleResponseError(error) {
44515
+ const req = this.pending.get(error.requestId);
44516
+ if (!req) return;
44517
+ this.pending.delete(error.requestId);
44518
+ req.reject(new ErrorResponse(error));
44519
+ }
44520
+ handleStreamData(packet) {
44521
+ const controller = this.streams.get(packet.id);
44522
+ if (!controller) return;
44523
+ if (packet.payload.SwapQuotes !== void 0) {
44524
+ controller.enqueue(packet.payload.SwapQuotes);
44525
+ }
44526
+ }
44527
+ handleStreamEnd(packet) {
44528
+ const controller = this.streams.get(packet.id);
44529
+ if (!controller) return;
44530
+ this.streams.delete(packet.id);
44531
+ this.streamStopping.delete(packet.id);
44532
+ if (packet.errorCode !== void 0) {
44533
+ controller.error(new StreamError(packet));
44534
+ } else {
44535
+ controller.close();
44536
+ }
44537
+ }
44538
+ async cancelStream(streamId) {
44539
+ if (this.streamStopping.get(streamId) || !this.streams.has(streamId)) return;
44540
+ this.streamStopping.set(streamId, true);
44541
+ await this.stopStream(streamId);
44542
+ }
44543
+ // --- Connection lifecycle ---
44544
+ rejectAll(error) {
44545
+ for (const req of this.pending.values()) {
44546
+ req.reject(error);
44547
+ }
44548
+ this.pending.clear();
44549
+ for (const controller of this.streams.values()) {
44550
+ controller.error(error);
44551
+ }
44552
+ this.streams.clear();
44553
+ this.streamStopping.clear();
44554
+ }
44555
+ handleClose(code, reason) {
44556
+ this._closed = true;
44557
+ this.rejectAll(new ConnectionClosed(code, reason));
44558
+ for (const listener of this.closeListeners) {
44559
+ listener.resolve();
44560
+ }
44561
+ this.closeListeners = [];
44562
+ }
44563
+ handleError(err) {
44564
+ this.rejectAll(err);
44565
+ this.socket.close(3002);
44566
+ }
44567
+ };
44568
+ function deserializeSerializedInstruction(ix) {
44569
+ return new TransactionInstruction({
44570
+ programId: new PublicKey(Buffer.from(ix.p, "base64")),
44571
+ keys: ix.a.map((account) => ({
44572
+ pubkey: new PublicKey(Buffer.from(account.p, "base64")),
44573
+ isSigner: account.s,
44574
+ isWritable: account.w
44575
+ })),
44576
+ data: Buffer.from(ix.d, "base64")
44577
+ });
44578
+ }
44579
+ function selectBestRoute(quotes, swapMode) {
44580
+ const routes = Object.values(quotes);
44581
+ if (routes.length === 0) return null;
44582
+ return routes.reduce((best, route) => {
44583
+ if (swapMode === "ExactIn") {
44584
+ return route.outAmount > best.outAmount ? route : best;
44585
+ } else {
44586
+ return route.inAmount < best.inAmount ? route : best;
44587
+ }
44588
+ });
44589
+ }
44590
+ function buildSwapQuoteResult(route, swapMode) {
44591
+ const slippageBps = route.slippageBps;
44592
+ let otherAmountThreshold;
44593
+ if (swapMode === "ExactIn") {
44594
+ otherAmountThreshold = String(Math.floor(route.outAmount * (1 - slippageBps / 1e4)));
44595
+ } else {
44596
+ otherAmountThreshold = String(Math.ceil(route.inAmount * (1 + slippageBps / 1e4)));
44597
+ }
44598
+ return {
44599
+ inAmount: String(route.inAmount),
44600
+ outAmount: String(route.outAmount),
44601
+ otherAmountThreshold,
44602
+ slippageBps,
44603
+ platformFee: route.platformFee ? {
44604
+ amount: String(route.platformFee.amount),
44605
+ feeBps: route.platformFee.fee_bps
44606
+ } : void 0,
44607
+ contextSlot: route.contextSlot,
44608
+ timeTaken: route.timeTaken
44609
+ };
44610
+ }
44611
+ async function resolveLookupTables(connection, lutPubkeys) {
44612
+ if (lutPubkeys.length === 0) return [];
44613
+ const lutAccountsRaw = await connection.getMultipleAccountsInfo(lutPubkeys);
44614
+ return lutAccountsRaw.map((accountInfo, index) => {
44615
+ if (!accountInfo) return null;
44616
+ return new AddressLookupTableAccount({
44617
+ key: lutPubkeys[index],
44618
+ state: AddressLookupTableAccount.deserialize(accountInfo.data)
44619
+ });
44620
+ }).filter((account) => account !== null);
44621
+ }
44171
44622
 
44172
44623
  // src/vendor/klend/utils/klend/interest-rate.utils.ts
44173
44624
  function getKaminoTotalSupply(reserve) {
@@ -46689,18 +47140,18 @@ async function buildLoopFlashloanTx({
46689
47140
  overrideInferAccounts,
46690
47141
  blockhash
46691
47142
  }) {
46692
- const swapResult = [];
46693
47143
  const cuRequestIxs = [
46694
47144
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
46695
47145
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
46696
47146
  ];
47147
+ let amountToDeposit;
47148
+ let swapInstructions = [];
47149
+ let setupInstructions = [];
47150
+ let swapLookupTables = [];
47151
+ let swapQuote;
47152
+ let sizeConstraintUsed = 0;
46697
47153
  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
- });
47154
+ amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
46704
47155
  } else {
46705
47156
  const destinationTokenAccount = getAssociatedTokenAddressSync(
46706
47157
  new PublicKey(depositOpts.depositBank.mint),
@@ -46708,36 +47159,46 @@ async function buildLoopFlashloanTx({
46708
47159
  true,
46709
47160
  depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
46710
47161
  );
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
47162
+ const swapConstraints = await computeFlashloanSwapConstraints({
47163
+ program,
47164
+ marginfiAccount,
47165
+ bankMap,
47166
+ bankMetadataMap,
47167
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
47168
+ primaryIx: {
47169
+ type: "borrow",
47170
+ bank: borrowOpts.borrowBank,
47171
+ tokenProgram: borrowOpts.tokenProgram
47172
+ },
47173
+ secondaryIx: {
47174
+ type: "deposit",
47175
+ bank: depositOpts.depositBank,
47176
+ tokenProgram: depositOpts.tokenProgram
46721
47177
  },
47178
+ overrideInferAccounts
47179
+ });
47180
+ const swapResponse = await getSwapIxsForFlashloan({
47181
+ inputMint: borrowOpts.borrowBank.mint.toBase58(),
47182
+ outputMint: depositOpts.depositBank.mint.toBase58(),
47183
+ amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
47184
+ swapMode: "ExactIn",
46722
47185
  authority: marginfiAccount.authority,
46723
47186
  connection,
46724
47187
  destinationTokenAccount,
46725
- configParams: swapOpts.jupiterOptions?.configParams
46726
- });
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
46739
- });
47188
+ swapOpts,
47189
+ sizeConstraint: swapConstraints.sizeConstraint,
47190
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
46740
47191
  });
47192
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
47193
+ const outAmountThreshold = nativeToUi(
47194
+ swapResponse.quoteResponse.otherAmountThreshold,
47195
+ depositOpts.depositBank.mintDecimals
47196
+ );
47197
+ amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47198
+ swapInstructions = swapResponse.swapInstructions;
47199
+ setupInstructions = swapResponse.setupInstructions;
47200
+ swapLookupTables = swapResponse.addressLookupTableAddresses;
47201
+ swapQuote = swapResponse.quoteResponse;
46741
47202
  }
46742
47203
  const borrowIxs = await makeBorrowIx3({
46743
47204
  program,
@@ -46754,140 +47215,136 @@ async function buildLoopFlashloanTx({
46754
47215
  overrideInferAccounts
46755
47216
  }
46756
47217
  });
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;
47218
+ let depositIxs;
47219
+ switch (depositOpts.depositBank.config.assetTag) {
47220
+ case 3 /* KAMINO */: {
47221
+ const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
47222
+ if (!reserve) {
47223
+ throw TransactionBuildingError.kaminoReserveNotFound(
47224
+ depositOpts.depositBank.address.toBase58(),
47225
+ depositOpts.depositBank.mint.toBase58(),
47226
+ depositOpts.depositBank.tokenSymbol
47227
+ );
46791
47228
  }
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
- );
47229
+ depositIxs = await makeKaminoDepositIx3({
47230
+ program,
47231
+ bank: depositOpts.depositBank,
47232
+ tokenProgram: depositOpts.tokenProgram,
47233
+ amount: amountToDeposit,
47234
+ accountAddress: marginfiAccount.address,
47235
+ authority: marginfiAccount.authority,
47236
+ group: marginfiAccount.group,
47237
+ reserve,
47238
+ opts: {
47239
+ wrapAndUnwrapSol: false,
47240
+ overrideInferAccounts
46800
47241
  }
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;
46835
- }
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;
46851
- }
47242
+ });
47243
+ break;
46852
47244
  }
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);
46876
- } else {
46877
- continue;
47245
+ case 4 /* DRIFT */: {
47246
+ const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
47247
+ if (!driftState) {
47248
+ throw TransactionBuildingError.driftStateNotFound(
47249
+ depositOpts.depositBank.address.toBase58(),
47250
+ depositOpts.depositBank.mint.toBase58(),
47251
+ depositOpts.depositBank.tokenSymbol
47252
+ );
46878
47253
  }
46879
- } else {
46880
- return {
46881
- flashloanTx,
46882
- setupInstructions,
46883
- swapQuote: quoteResponse,
46884
- borrowIxs,
46885
- depositIxs,
46886
- amountToDeposit
46887
- };
47254
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
47255
+ const driftOracle = driftState.spotMarketState.oracle;
47256
+ depositIxs = await makeDriftDepositIx3({
47257
+ program,
47258
+ bank: depositOpts.depositBank,
47259
+ tokenProgram: depositOpts.tokenProgram,
47260
+ amount: amountToDeposit,
47261
+ accountAddress: marginfiAccount.address,
47262
+ authority: marginfiAccount.authority,
47263
+ group: marginfiAccount.group,
47264
+ driftMarketIndex,
47265
+ driftOracle,
47266
+ opts: {
47267
+ wrapAndUnwrapSol: false,
47268
+ overrideInferAccounts
47269
+ }
47270
+ });
47271
+ break;
47272
+ }
47273
+ case 6 /* JUPLEND */: {
47274
+ depositIxs = await makeJuplendDepositIx2({
47275
+ program,
47276
+ bank: depositOpts.depositBank,
47277
+ tokenProgram: depositOpts.tokenProgram,
47278
+ amount: amountToDeposit,
47279
+ accountAddress: marginfiAccount.address,
47280
+ authority: marginfiAccount.authority,
47281
+ group: marginfiAccount.group,
47282
+ opts: {
47283
+ wrapAndUnwrapSol: false,
47284
+ overrideInferAccounts
47285
+ }
47286
+ });
47287
+ break;
47288
+ }
47289
+ default: {
47290
+ depositIxs = await makeDepositIx3({
47291
+ program,
47292
+ bank: depositOpts.depositBank,
47293
+ tokenProgram: depositOpts.tokenProgram,
47294
+ amount: amountToDeposit,
47295
+ accountAddress: marginfiAccount.address,
47296
+ authority: marginfiAccount.authority,
47297
+ group: marginfiAccount.group,
47298
+ opts: {
47299
+ wrapAndUnwrapSol: false,
47300
+ overrideInferAccounts
47301
+ }
47302
+ });
47303
+ break;
46888
47304
  }
46889
47305
  }
46890
- throw new Error("Failed to build repay with collateral flashloan tx");
47306
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47307
+ const allNonFlIxs = [
47308
+ ...cuRequestIxs,
47309
+ ...borrowIxs.instructions,
47310
+ ...swapInstructions,
47311
+ ...depositIxs.instructions
47312
+ ];
47313
+ if (swapInstructions.length > 0) {
47314
+ compileFlashloanPrecheck({
47315
+ allIxs: allNonFlIxs,
47316
+ payer: marginfiAccount.authority,
47317
+ luts,
47318
+ sizeConstraint: sizeConstraintUsed,
47319
+ swapIxCount: swapInstructions.length,
47320
+ swapLutCount: swapLookupTables.length
47321
+ });
47322
+ }
47323
+ const flashloanTx = await makeFlashLoanTx({
47324
+ program,
47325
+ marginfiAccount,
47326
+ bankMap,
47327
+ addressLookupTableAccounts: luts,
47328
+ blockhash,
47329
+ ixs: allNonFlIxs
47330
+ });
47331
+ const txSize = getTxSize(flashloanTx);
47332
+ const totalKeys = getTotalAccountKeys(flashloanTx);
47333
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
47334
+ throw TransactionBuildingError.swapSizeExceededLoop(
47335
+ txSize,
47336
+ totalKeys,
47337
+ swapOpts.swapConfig?.provider
47338
+ );
47339
+ }
47340
+ return {
47341
+ flashloanTx,
47342
+ setupInstructions,
47343
+ swapQuote,
47344
+ borrowIxs,
47345
+ depositIxs,
47346
+ amountToDeposit
47347
+ };
46891
47348
  }
46892
47349
  async function makeRepayIx3({
46893
47350
  program,
@@ -47077,18 +47534,18 @@ async function buildRepayWithCollatFlashloanTx({
47077
47534
  overrideInferAccounts,
47078
47535
  blockhash
47079
47536
  }) {
47080
- const swapResult = [];
47081
47537
  const cuRequestIxs = [
47082
47538
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47083
47539
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47084
47540
  ];
47541
+ let amountToRepay;
47542
+ let swapInstructions = [];
47543
+ let setupInstructions = [];
47544
+ let swapLookupTables = [];
47545
+ let swapQuote;
47546
+ let sizeConstraintUsed = 0;
47085
47547
  if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
47086
- swapResult.push({
47087
- amountToRepay: withdrawOpts.withdrawAmount,
47088
- swapInstructions: [],
47089
- setupInstructions: [],
47090
- swapLookupTables: []
47091
- });
47548
+ amountToRepay = withdrawOpts.withdrawAmount;
47092
47549
  } else {
47093
47550
  const destinationTokenAccount = getAssociatedTokenAddressSync(
47094
47551
  new PublicKey(repayOpts.repayBank.mint),
@@ -47096,41 +47553,50 @@ async function buildRepayWithCollatFlashloanTx({
47096
47553
  true,
47097
47554
  repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47098
47555
  );
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
47556
+ const swapConstraints = await computeFlashloanSwapConstraints({
47557
+ program,
47558
+ marginfiAccount,
47559
+ bankMap,
47560
+ bankMetadataMap,
47561
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
47562
+ primaryIx: {
47563
+ type: "withdraw",
47564
+ bank: withdrawOpts.withdrawBank,
47565
+ tokenProgram: withdrawOpts.tokenProgram
47566
+ },
47567
+ secondaryIx: {
47568
+ type: "repay",
47569
+ bank: repayOpts.repayBank,
47570
+ tokenProgram: repayOpts.tokenProgram
47112
47571
  },
47572
+ overrideInferAccounts
47573
+ });
47574
+ const swapResponse = await getSwapIxsForFlashloan({
47575
+ inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
47576
+ outputMint: repayOpts.repayBank.mint.toBase58(),
47577
+ amount: uiToNative(
47578
+ withdrawOpts.withdrawAmount,
47579
+ withdrawOpts.withdrawBank.mintDecimals
47580
+ ).toNumber(),
47581
+ swapMode: "ExactIn",
47113
47582
  authority: marginfiAccount.authority,
47114
47583
  connection,
47115
47584
  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
- });
47585
+ swapOpts,
47586
+ sizeConstraint: swapConstraints.sizeConstraint,
47587
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47133
47588
  });
47589
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
47590
+ const { quoteResponse } = swapResponse;
47591
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
47592
+ const outAmountThreshold = nativeToUi(
47593
+ quoteResponse.otherAmountThreshold,
47594
+ repayOpts.repayBank.mintDecimals
47595
+ );
47596
+ amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
47597
+ swapInstructions = swapResponse.swapInstructions;
47598
+ swapLookupTables = swapResponse.addressLookupTableAddresses;
47599
+ swapQuote = quoteResponse;
47134
47600
  }
47135
47601
  let withdrawIxs;
47136
47602
  switch (withdrawOpts.withdrawBank.config.assetTag) {
@@ -47268,68 +47734,70 @@ async function buildRepayWithCollatFlashloanTx({
47268
47734
  break;
47269
47735
  }
47270
47736
  }
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
47311
- });
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
- };
47737
+ const repayIxs = await makeRepayIx3({
47738
+ program,
47739
+ bank: repayOpts.repayBank,
47740
+ tokenProgram: repayOpts.tokenProgram,
47741
+ amount: amountToRepay,
47742
+ accountAddress: marginfiAccount.address,
47743
+ authority: marginfiAccount.authority,
47744
+ repayAll: isWholePosition(
47745
+ {
47746
+ amount: repayOpts.totalPositionAmount,
47747
+ isLending: true
47748
+ },
47749
+ amountToRepay,
47750
+ repayOpts.repayBank.mintDecimals
47751
+ ),
47752
+ isSync: false,
47753
+ opts: {
47754
+ wrapAndUnwrapSol: false,
47755
+ overrideInferAccounts
47330
47756
  }
47757
+ });
47758
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47759
+ const allNonFlIxs = [
47760
+ ...cuRequestIxs,
47761
+ ...withdrawIxs.instructions,
47762
+ ...swapInstructions,
47763
+ ...repayIxs.instructions
47764
+ ];
47765
+ if (swapInstructions.length > 0) {
47766
+ compileFlashloanPrecheck({
47767
+ allIxs: allNonFlIxs,
47768
+ payer: marginfiAccount.authority,
47769
+ luts,
47770
+ sizeConstraint: sizeConstraintUsed,
47771
+ swapIxCount: swapInstructions.length,
47772
+ swapLutCount: swapLookupTables.length
47773
+ });
47331
47774
  }
47332
- throw new Error("Failed to build repay with collateral flashloan tx");
47775
+ const flashloanTx = await makeFlashLoanTx({
47776
+ program,
47777
+ marginfiAccount,
47778
+ bankMap,
47779
+ addressLookupTableAccounts: luts,
47780
+ blockhash,
47781
+ ixs: allNonFlIxs,
47782
+ isSync: true
47783
+ });
47784
+ const txSize = getTxSize(flashloanTx);
47785
+ const totalKeys = getTotalAccountKeys(flashloanTx);
47786
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
47787
+ throw TransactionBuildingError.swapSizeExceededRepay(
47788
+ txSize,
47789
+ totalKeys,
47790
+ swapOpts.swapConfig?.provider
47791
+ );
47792
+ }
47793
+ return {
47794
+ flashloanTx,
47795
+ setupInstructions,
47796
+ swapQuote,
47797
+ withdrawIxs,
47798
+ repayIxs,
47799
+ amountToRepay
47800
+ };
47333
47801
  }
47334
47802
 
47335
47803
  // src/services/account/actions/emissions.ts
@@ -47483,11 +47951,16 @@ async function buildSwapCollateralFlashloanTx({
47483
47951
  actualWithdrawAmount,
47484
47952
  withdrawBank.mintDecimals
47485
47953
  );
47486
- const swapResult = [];
47487
47954
  const cuRequestIxs = [
47488
47955
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47489
47956
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47490
47957
  ];
47958
+ let amountToDeposit;
47959
+ let swapInstructions = [];
47960
+ let setupInstructions = [];
47961
+ let swapLookupTables = [];
47962
+ let swapQuote;
47963
+ let sizeConstraintUsed = 0;
47491
47964
  let withdrawIxs;
47492
47965
  switch (withdrawOpts.withdrawBank.config.assetTag) {
47493
47966
  case 3 /* KAMINO */: {
@@ -47597,12 +48070,7 @@ async function buildSwapCollateralFlashloanTx({
47597
48070
  }
47598
48071
  }
47599
48072
  if (depositBank.mint.equals(withdrawBank.mint)) {
47600
- swapResult.push({
47601
- amountToDeposit: actualWithdrawAmount,
47602
- swapInstructions: [],
47603
- setupInstructions: [],
47604
- swapLookupTables: []
47605
- });
48073
+ amountToDeposit = actualWithdrawAmount;
47606
48074
  } else {
47607
48075
  const destinationTokenAccount = getAssociatedTokenAddressSync(
47608
48076
  depositBank.mint,
@@ -47610,175 +48078,168 @@ async function buildSwapCollateralFlashloanTx({
47610
48078
  true,
47611
48079
  depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47612
48080
  );
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
- },
48081
+ const swapConstraints = await computeFlashloanSwapConstraints({
48082
+ program,
48083
+ marginfiAccount,
48084
+ bankMap,
48085
+ bankMetadataMap,
48086
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48087
+ primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
48088
+ secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
48089
+ overrideInferAccounts
48090
+ });
48091
+ const swapResponses = await getSwapIxsForFlashloan({
48092
+ inputMint: withdrawBank.mint.toBase58(),
48093
+ outputMint: depositBank.mint.toBase58(),
48094
+ amount: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
48095
+ swapMode: "ExactIn",
47624
48096
  authority: marginfiAccount.authority,
47625
48097
  connection,
47626
48098
  destinationTokenAccount,
47627
- configParams: swapOpts.jupiterOptions?.configParams
47628
- });
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
- });
48099
+ swapOpts,
48100
+ sizeConstraint: swapConstraints.sizeConstraint,
48101
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47641
48102
  });
47642
- }
47643
- if (swapResult.length === 0) {
47644
- throw new Error(
47645
- `No swap routes found for ${withdrawBank.mint.toBase58()} -> ${depositBank.mint.toBase58()}`
48103
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
48104
+ amountToDeposit = nativeToUi(
48105
+ swapResponses.quoteResponse.otherAmountThreshold,
48106
+ depositBank.mintDecimals
47646
48107
  );
48108
+ swapInstructions = swapResponses.swapInstructions;
48109
+ setupInstructions = swapResponses.setupInstructions;
48110
+ swapLookupTables = swapResponses.addressLookupTableAddresses;
48111
+ swapQuote = swapResponses.quoteResponse;
47647
48112
  }
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;
48113
+ let depositIxs;
48114
+ switch (depositBank.config.assetTag) {
48115
+ case 3 /* KAMINO */: {
48116
+ const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
48117
+ if (!reserve) {
48118
+ throw TransactionBuildingError.kaminoReserveNotFound(
48119
+ depositBank.address.toBase58(),
48120
+ depositBank.mint.toBase58(),
48121
+ depositBank.tokenSymbol
48122
+ );
47682
48123
  }
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
- );
48124
+ depositIxs = await makeKaminoDepositIx3({
48125
+ program,
48126
+ bank: depositBank,
48127
+ tokenProgram: depositTokenProgram,
48128
+ amount: amountToDeposit,
48129
+ accountAddress: marginfiAccount.address,
48130
+ authority: marginfiAccount.authority,
48131
+ group: marginfiAccount.group,
48132
+ reserve,
48133
+ opts: {
48134
+ wrapAndUnwrapSol: false,
48135
+ overrideInferAccounts
47691
48136
  }
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
- }
48137
+ });
48138
+ break;
47743
48139
  }
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;
48140
+ case 4 /* DRIFT */: {
48141
+ const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
48142
+ if (!driftState) {
48143
+ throw TransactionBuildingError.driftStateNotFound(
48144
+ depositBank.address.toBase58(),
48145
+ depositBank.mint.toBase58(),
48146
+ depositBank.tokenSymbol
48147
+ );
47770
48148
  }
47771
- } else {
47772
- return {
47773
- flashloanTx,
47774
- setupInstructions,
47775
- swapQuote: quoteResponse,
47776
- withdrawIxs,
47777
- depositIxs
47778
- };
48149
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
48150
+ const driftOracle = driftState.spotMarketState.oracle;
48151
+ depositIxs = await makeDriftDepositIx3({
48152
+ program,
48153
+ bank: depositBank,
48154
+ tokenProgram: depositTokenProgram,
48155
+ amount: amountToDeposit,
48156
+ accountAddress: marginfiAccount.address,
48157
+ authority: marginfiAccount.authority,
48158
+ group: marginfiAccount.group,
48159
+ driftMarketIndex,
48160
+ driftOracle,
48161
+ opts: {
48162
+ wrapAndUnwrapSol: false,
48163
+ overrideInferAccounts
48164
+ }
48165
+ });
48166
+ break;
48167
+ }
48168
+ case 6 /* JUPLEND */: {
48169
+ depositIxs = await makeJuplendDepositIx2({
48170
+ program,
48171
+ bank: depositBank,
48172
+ tokenProgram: depositTokenProgram,
48173
+ amount: amountToDeposit,
48174
+ accountAddress: marginfiAccount.address,
48175
+ authority: marginfiAccount.authority,
48176
+ group: marginfiAccount.group,
48177
+ opts: {
48178
+ wrapAndUnwrapSol: false,
48179
+ overrideInferAccounts
48180
+ }
48181
+ });
48182
+ break;
47779
48183
  }
48184
+ default: {
48185
+ depositIxs = await makeDepositIx3({
48186
+ program,
48187
+ bank: depositBank,
48188
+ tokenProgram: depositTokenProgram,
48189
+ amount: amountToDeposit,
48190
+ accountAddress: marginfiAccount.address,
48191
+ authority: marginfiAccount.authority,
48192
+ group: marginfiAccount.group,
48193
+ opts: {
48194
+ wrapAndUnwrapSol: false,
48195
+ overrideInferAccounts
48196
+ }
48197
+ });
48198
+ break;
48199
+ }
48200
+ }
48201
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48202
+ const allNonFlIxs = [
48203
+ ...cuRequestIxs,
48204
+ ...withdrawIxs.instructions,
48205
+ ...swapInstructions,
48206
+ ...depositIxs.instructions
48207
+ ];
48208
+ if (swapInstructions.length > 0) {
48209
+ compileFlashloanPrecheck({
48210
+ allIxs: allNonFlIxs,
48211
+ payer: marginfiAccount.authority,
48212
+ luts,
48213
+ sizeConstraint: sizeConstraintUsed,
48214
+ swapIxCount: swapInstructions.length,
48215
+ swapLutCount: swapLookupTables.length
48216
+ });
47780
48217
  }
47781
- throw new Error("Failed to build swap collateral flashloan tx");
48218
+ const flashloanTx = await makeFlashLoanTx({
48219
+ program,
48220
+ marginfiAccount,
48221
+ bankMap,
48222
+ addressLookupTableAccounts: luts,
48223
+ blockhash,
48224
+ ixs: allNonFlIxs,
48225
+ isSync: true
48226
+ });
48227
+ const txSize = getTxSize(flashloanTx);
48228
+ const totalKeys = getTotalAccountKeys(flashloanTx);
48229
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48230
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48231
+ txSize,
48232
+ totalKeys,
48233
+ swapOpts.swapConfig?.provider
48234
+ );
48235
+ }
48236
+ return {
48237
+ flashloanTx,
48238
+ setupInstructions,
48239
+ swapQuote,
48240
+ withdrawIxs,
48241
+ depositIxs
48242
+ };
47782
48243
  }
47783
48244
  async function makeSwapDebtTx(params) {
47784
48245
  const {
@@ -47916,7 +48377,6 @@ async function buildSwapDebtFlashloanTx({
47916
48377
  throw new Error("repayAmount must be greater than 0");
47917
48378
  }
47918
48379
  const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
47919
- const swapResult = [];
47920
48380
  const cuRequestIxs = [
47921
48381
  ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47922
48382
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
@@ -47927,313 +48387,120 @@ async function buildSwapDebtFlashloanTx({
47927
48387
  true,
47928
48388
  repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47929
48389
  );
47930
- const jupiterApiClient = swapOpts.jupiterOptions?.configParams?.basePath ? new SwapApi(new Configuration(swapOpts.jupiterOptions.configParams)) : createJupiterApiClient(swapOpts.jupiterOptions?.configParams);
47931
- const estimateQuote = await jupiterApiClient.quoteGet({
48390
+ const { otherAmountThreshold } = await getExactOutEstimate({
47932
48391
  inputMint: borrowBank.mint.toBase58(),
47933
48392
  outputMint: repayBank.mint.toBase58(),
47934
48393
  amount: uiToNative(actualRepayAmount, repayBank.mintDecimals).toNumber(),
47935
- swapMode: "ExactOut",
47936
- dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
47937
- slippageBps: swapOpts.jupiterOptions?.slippageBps
48394
+ swapOpts,
48395
+ connection
47938
48396
  });
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
- },
48397
+ const estimatedBorrowAmount = nativeToUi(otherAmountThreshold, borrowBank.mintDecimals);
48398
+ const swapConstraints = await computeFlashloanSwapConstraints({
48399
+ program,
48400
+ marginfiAccount,
48401
+ bankMap,
48402
+ bankMetadataMap,
48403
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48404
+ primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
48405
+ secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
48406
+ overrideInferAccounts
48407
+ });
48408
+ const swapResponses = await getSwapIxsForFlashloan({
48409
+ inputMint: borrowBank.mint.toBase58(),
48410
+ outputMint: repayBank.mint.toBase58(),
48411
+ amount: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
48412
+ swapMode: "ExactIn",
47954
48413
  authority: marginfiAccount.authority,
47955
48414
  connection,
47956
48415
  destinationTokenAccount,
47957
- configParams: swapOpts.jupiterOptions?.configParams
48416
+ swapOpts,
48417
+ sizeConstraint: swapConstraints.sizeConstraint,
48418
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47958
48419
  });
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
- });
48420
+ const { quoteResponse } = swapResponses;
48421
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
48422
+ const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
48423
+ const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
48424
+ const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
48425
+ const borrowIxs = await makeBorrowIx3({
48426
+ program,
48427
+ bank: borrowBank,
48428
+ bankMap,
48429
+ tokenProgram: borrowTokenProgram,
48430
+ amount: borrowAmount,
48431
+ marginfiAccount,
48432
+ authority: marginfiAccount.authority,
48433
+ isSync: true,
48434
+ opts: {
48435
+ createAtas: false,
48436
+ wrapAndUnwrapSol: false,
48437
+ overrideInferAccounts
48438
+ }
47975
48439
  });
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 {
48440
+ const repayIxs = await makeRepayIx3({
48441
+ program,
48442
+ bank: repayBank,
48443
+ tokenProgram: repayTokenProgram,
48444
+ amount: amountToRepay,
48445
+ accountAddress: marginfiAccount.address,
48446
+ authority: marginfiAccount.authority,
48447
+ repayAll: isWholePosition(
48448
+ {
48449
+ amount: totalPositionAmount,
48450
+ isLending: false
48451
+ },
47983
48452
  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
- };
48061
- }
48062
- }
48063
- throw new Error("Failed to build swap debt flashloan tx");
48064
- }
48065
- var SYSVAR_CLOCK_ID2 = new PublicKey("SysvarC1ock11111111111111111111111111111111");
48066
- async function makeMintStakedLstIx(params) {
48067
- const { amount, authority, stakeAccountPk, validator, connection } = params;
48068
- const pool = findPoolAddress(validator);
48069
- const lstMint = findPoolMintAddress(pool);
48070
- const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
48071
- const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
48072
- const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
48073
- connection.getAccountInfo(lstAta),
48074
- connection.getParsedAccountInfo(stakeAccountPk),
48075
- connection.getMinimumBalanceForRentExemption(StakeProgram.space)
48076
- ]);
48077
- const stakeAccParsed = stakeAccInfoParsed?.value?.data;
48078
- const amountLamports = Math.round(Number(amount) * LAMPORTS_PER_SOL);
48079
- const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
48080
- const isFullStake = amountLamports >= stakeAccLamports;
48081
- const instructions2 = [];
48082
- const signers = [];
48083
- if (!lstAccInfo) {
48084
- instructions2.push(
48085
- createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
48086
- );
48087
- }
48088
- let targetStakePubkey;
48089
- if (!isFullStake) {
48090
- const splitStakeAccount = Keypair.generate();
48091
- signers.push(splitStakeAccount);
48092
- targetStakePubkey = splitStakeAccount.publicKey;
48093
- instructions2.push(
48094
- ...StakeProgram.split(
48095
- {
48096
- stakePubkey: stakeAccountPk,
48097
- authorizedPubkey: authority,
48098
- splitStakePubkey: splitStakeAccount.publicKey,
48099
- lamports: amountLamports
48100
- },
48101
- rentExemptReserve
48102
- ).instructions
48103
- );
48104
- } else {
48105
- targetStakePubkey = stakeAccountPk;
48106
- }
48107
- const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
48108
- StakeProgram.authorize({
48109
- stakePubkey: targetStakePubkey,
48110
- authorizedPubkey: authority,
48111
- newAuthorizedPubkey: poolStakeAuth,
48112
- stakeAuthorizationType: StakeAuthorizationLayout.Staker
48113
- }).instructions,
48114
- StakeProgram.authorize({
48115
- stakePubkey: targetStakePubkey,
48116
- authorizedPubkey: authority,
48117
- newAuthorizedPubkey: poolStakeAuth,
48118
- stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer
48119
- }).instructions
48120
- ]);
48121
- [authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
48122
- if (ix) {
48123
- ix.keys = ix.keys.map((key) => ({
48124
- ...key,
48125
- isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
48126
- }));
48453
+ repayBank.mintDecimals
48454
+ ),
48455
+ isSync: true,
48456
+ opts: {
48457
+ wrapAndUnwrapSol: false,
48458
+ overrideInferAccounts
48127
48459
  }
48128
48460
  });
48129
- instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
48130
- const depositStakeIx = await SinglePoolInstruction.depositStake(
48131
- pool,
48132
- targetStakePubkey,
48133
- lstAta,
48134
- authority
48135
- );
48136
- instructions2.push(depositStakeIx);
48137
- return { instructions: instructions2, keys: signers };
48138
- }
48139
- async function makeMintStakedLstTx(params) {
48140
- const { connection, luts, blockhash: providedBlockhash } = params;
48141
- const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
48142
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
48143
- const message = new TransactionMessage({
48144
- payerKey: params.authority,
48145
- recentBlockhash: blockhash,
48146
- instructions: instructions2
48147
- }).compileToV0Message(luts);
48148
- const tx = new VersionedTransaction(message);
48149
- return addTransactionMetadata(tx, {
48150
- signers: keys,
48151
- addressLookupTables: luts,
48152
- type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
48153
- });
48154
- }
48155
- async function makeRedeemStakedLstIx(params) {
48156
- const { amount, authority, validator, connection } = params;
48157
- const pool = findPoolAddress(validator);
48158
- const lstMint = findPoolMintAddress(pool);
48159
- const mintAuthority = findPoolMintAuthorityAddress(pool);
48160
- const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
48161
- const rentExemption = await connection.getMinimumBalanceForRentExemption(
48162
- StakeProgram.space
48163
- );
48164
- const stakeAmount = new BigNumber3(new BigNumber3(amount).toString());
48165
- const instructions2 = [];
48166
- const signers = [];
48167
- const stakeAccount = Keypair.generate();
48168
- signers.push(stakeAccount);
48169
- instructions2.push(
48170
- SystemProgram.createAccount({
48171
- fromPubkey: authority,
48172
- newAccountPubkey: stakeAccount.publicKey,
48173
- lamports: rentExemption,
48174
- space: StakeProgram.space,
48175
- programId: StakeProgram.programId
48176
- })
48177
- );
48178
- instructions2.push(
48179
- createApproveInstruction(
48180
- lstAta,
48181
- mintAuthority,
48182
- authority,
48183
- BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
48184
- )
48185
- );
48186
- const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
48187
- pool,
48188
- stakeAccount.publicKey,
48189
- authority,
48190
- lstAta,
48191
- stakeAmount
48192
- );
48193
- instructions2.push(withdrawStakeIx);
48194
- return { instructions: instructions2, keys: signers };
48195
- }
48196
- async function makeRedeemStakedLstTx(params) {
48197
- const { connection, luts, blockhash: providedBlockhash } = params;
48198
- const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
48199
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
48200
- const message = new TransactionMessage({
48201
- payerKey: params.authority,
48202
- recentBlockhash: blockhash,
48203
- instructions: instructions2
48204
- }).compileToV0Message(luts);
48205
- const tx = new VersionedTransaction(message);
48206
- return addTransactionMetadata(tx, {
48207
- signers: keys,
48208
- addressLookupTables: luts,
48209
- type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
48210
- });
48211
- }
48212
- async function makeMergeStakeAccountsTx(params) {
48213
- const {
48214
- authority,
48215
- sourceStakeAccount,
48216
- destinationStakeAccount,
48217
- connection,
48461
+ const luts = [
48462
+ ...addressLookupTableAccounts ?? [],
48463
+ ...swapResponses.addressLookupTableAddresses
48464
+ ];
48465
+ const allNonFlIxs = [
48466
+ ...cuRequestIxs,
48467
+ ...borrowIxs.instructions,
48468
+ ...swapResponses.swapInstructions,
48469
+ ...repayIxs.instructions
48470
+ ];
48471
+ compileFlashloanPrecheck({
48472
+ allIxs: allNonFlIxs,
48473
+ payer: marginfiAccount.authority,
48218
48474
  luts,
48219
- blockhash: providedBlockhash
48220
- } = params;
48221
- const mergeIx = StakeProgram.merge({
48222
- stakePubkey: destinationStakeAccount,
48223
- sourceStakePubKey: sourceStakeAccount,
48224
- authorizedPubkey: authority
48225
- }).instructions;
48226
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
48227
- const message = new TransactionMessage({
48228
- payerKey: authority,
48229
- recentBlockhash: blockhash,
48230
- instructions: mergeIx
48231
- }).compileToV0Message(luts);
48232
- const tx = new VersionedTransaction(message);
48233
- return addTransactionMetadata(tx, {
48234
- addressLookupTables: luts,
48235
- type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
48475
+ sizeConstraint: swapConstraints.sizeConstraint,
48476
+ swapIxCount: swapResponses.swapInstructions.length,
48477
+ swapLutCount: swapResponses.addressLookupTableAddresses.length
48478
+ });
48479
+ const flashloanTx = await makeFlashLoanTx({
48480
+ program,
48481
+ marginfiAccount,
48482
+ bankMap,
48483
+ addressLookupTableAccounts: luts,
48484
+ blockhash,
48485
+ ixs: allNonFlIxs,
48486
+ isSync: true
48236
48487
  });
48488
+ const txSize = getTxSize(flashloanTx);
48489
+ const totalKeys = getTotalAccountKeys(flashloanTx);
48490
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48491
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48492
+ txSize,
48493
+ totalKeys,
48494
+ swapOpts.swapConfig?.provider
48495
+ );
48496
+ }
48497
+ return {
48498
+ flashloanTx,
48499
+ setupInstructions: swapResponses.setupInstructions,
48500
+ swapQuote: quoteResponse,
48501
+ borrowIxs,
48502
+ repayIxs
48503
+ };
48237
48504
  }
48238
48505
 
48239
48506
  // src/services/account/services/account-simulation.service.ts
@@ -48859,17 +49126,528 @@ function computeMaxWithdrawForBank(params) {
48859
49126
  const maxWithdraw = initUntiedCollateralForBank.div(initWeightedPrice);
48860
49127
  return maxWithdraw;
48861
49128
  }
49129
+ var TITAN_FEE_WALLET = new PublicKey("6ryqDDCwKFZfSiHQrYRkjTEarbsLjg9TmuFg1RJorBk3");
49130
+ var getTitanFeeAccount = (mint) => {
49131
+ return getAssociatedTokenAddressSync(mint, TITAN_FEE_WALLET, true);
49132
+ };
49133
+ var checkTitanFeeAccount = async (connection, mint) => {
49134
+ const feeAccount = getTitanFeeAccount(mint);
49135
+ const hasFeeAccount = !!await connection.getAccountInfo(feeAccount);
49136
+ return { feeAccount, hasFeeAccount, feeWallet: TITAN_FEE_WALLET };
49137
+ };
49138
+ function deserializeTitanInstruction(ix) {
49139
+ return new TransactionInstruction({
49140
+ programId: new PublicKey(ix.p),
49141
+ keys: ix.a.map((account) => ({
49142
+ pubkey: new PublicKey(account.p),
49143
+ isSigner: account.s,
49144
+ isWritable: account.w
49145
+ })),
49146
+ data: Buffer.from(ix.d)
49147
+ });
49148
+ }
49149
+ var getTitanSwapIxsForFlashloan = async ({
49150
+ quoteParams,
49151
+ authority,
49152
+ connection,
49153
+ destinationTokenAccount,
49154
+ apiConfig
49155
+ }) => {
49156
+ const basePath = apiConfig?.basePath ?? "";
49157
+ const feeMint = new PublicKey(
49158
+ quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint
49159
+ );
49160
+ const { feeAccount, hasFeeAccount } = await checkTitanFeeAccount(connection, feeMint);
49161
+ let finalQuoteParams = quoteParams;
49162
+ if (!hasFeeAccount) {
49163
+ console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
49164
+ finalQuoteParams = {
49165
+ ...quoteParams,
49166
+ platformFeeBps: void 0
49167
+ };
49168
+ }
49169
+ if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
49170
+ return getTitanSwapIxsViaWebSocket(
49171
+ { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49172
+ hasFeeAccount ? feeAccount : void 0
49173
+ );
49174
+ } else {
49175
+ return getTitanSwapIxsViaHttpProxy(
49176
+ { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49177
+ hasFeeAccount ? feeAccount : void 0
49178
+ );
49179
+ }
49180
+ };
49181
+ async function getTitanSwapIxsViaWebSocket(params, feeAccount) {
49182
+ const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
49183
+ const {
49184
+ inputMint,
49185
+ outputMint,
49186
+ amount,
49187
+ swapMode,
49188
+ slippageBps,
49189
+ platformFeeBps,
49190
+ directRoutesOnly,
49191
+ sizeConstraint,
49192
+ maxSwapAccounts,
49193
+ maxSwapTotalAccounts
49194
+ } = quoteParams;
49195
+ const wsUrl = apiConfig?.basePath;
49196
+ if (!wsUrl) {
49197
+ throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
49198
+ }
49199
+ const txParams = {
49200
+ userPublicKey: authority.toBytes(),
49201
+ outputAccount: destinationTokenAccount.toBytes()
49202
+ };
49203
+ if (feeAccount && platformFeeBps) {
49204
+ txParams.feeBps = platformFeeBps;
49205
+ txParams.feeAccount = feeAccount.toBytes();
49206
+ }
49207
+ const client = await V1Client.connect(wsUrl);
49208
+ try {
49209
+ const { stream } = await client.newSwapQuoteStream({
49210
+ swap: {
49211
+ inputMint: new PublicKey(inputMint).toBytes(),
49212
+ outputMint: new PublicKey(outputMint).toBytes(),
49213
+ amount,
49214
+ swapMode,
49215
+ slippageBps,
49216
+ onlyDirectRoutes: directRoutesOnly,
49217
+ addSizeConstraint: sizeConstraint !== void 0,
49218
+ sizeConstraint,
49219
+ accountsLimitWritable: maxSwapAccounts,
49220
+ accountsLimitTotal: maxSwapTotalAccounts
49221
+ },
49222
+ transaction: txParams,
49223
+ update: {
49224
+ num_quotes: 3
49225
+ }
49226
+ });
49227
+ const reader = stream.getReader();
49228
+ const { value: swapQuotes, done } = await reader.read();
49229
+ reader.releaseLock();
49230
+ if (done || !swapQuotes) {
49231
+ throw new Error("Titan swap quote stream ended without data");
49232
+ }
49233
+ const quotes = swapQuotes;
49234
+ const bestRoute = selectBestRoute(quotes.quotes, swapMode);
49235
+ if (!bestRoute) {
49236
+ throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
49237
+ }
49238
+ const swapInstructions = bestRoute.instructions.map(deserializeTitanInstruction);
49239
+ const lutPubkeys = bestRoute.addressLookupTables.map((lutBytes) => new PublicKey(lutBytes));
49240
+ const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
49241
+ const quoteResponse = {
49242
+ ...buildSwapQuoteResult(bestRoute, swapMode),
49243
+ provider: "TITAN" /* TITAN */
49244
+ };
49245
+ return {
49246
+ swapInstructions,
49247
+ setupInstructions: [],
49248
+ addressLookupTableAddresses,
49249
+ quoteResponse
49250
+ };
49251
+ } finally {
49252
+ if (!client.closed) {
49253
+ await client.close();
49254
+ }
49255
+ }
49256
+ }
49257
+ async function getTitanSwapIxsViaHttpProxy(params, feeAccount) {
49258
+ const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
49259
+ const {
49260
+ inputMint,
49261
+ outputMint,
49262
+ amount,
49263
+ swapMode,
49264
+ slippageBps,
49265
+ platformFeeBps,
49266
+ directRoutesOnly,
49267
+ sizeConstraint,
49268
+ maxSwapAccounts,
49269
+ maxSwapTotalAccounts
49270
+ } = quoteParams;
49271
+ const basePath = apiConfig?.basePath;
49272
+ if (!basePath) {
49273
+ throw new Error("Titan proxy URL is required (apiConfig.basePath)");
49274
+ }
49275
+ const txBody = {
49276
+ userPublicKey: authority.toBase58(),
49277
+ outputAccount: destinationTokenAccount.toBase58()
49278
+ };
49279
+ if (feeAccount && platformFeeBps) {
49280
+ txBody.feeBps = platformFeeBps;
49281
+ txBody.feeAccount = feeAccount.toBase58();
49282
+ }
49283
+ const response = await fetch(`${basePath}/swap-quote`, {
49284
+ method: "POST",
49285
+ headers: {
49286
+ "Content-Type": "application/json",
49287
+ ...apiConfig?.headers ?? {}
49288
+ },
49289
+ body: JSON.stringify({
49290
+ swap: {
49291
+ inputMint,
49292
+ outputMint,
49293
+ amount,
49294
+ swapMode,
49295
+ slippageBps,
49296
+ onlyDirectRoutes: directRoutesOnly,
49297
+ addSizeConstraint: sizeConstraint !== void 0,
49298
+ sizeConstraint,
49299
+ accountsLimitWritable: maxSwapAccounts,
49300
+ accountsLimitTotal: maxSwapTotalAccounts
49301
+ },
49302
+ transaction: txBody
49303
+ })
49304
+ });
49305
+ if (!response.ok) {
49306
+ const errorData = await response.json().catch(() => ({}));
49307
+ throw new Error(
49308
+ `Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
49309
+ );
49310
+ }
49311
+ const data = await response.json();
49312
+ const bestRoute = selectBestRoute(data.quotes, swapMode);
49313
+ if (!bestRoute) {
49314
+ throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
49315
+ }
49316
+ const swapInstructions = bestRoute.instructions.map(deserializeSerializedInstruction);
49317
+ const lutPubkeys = bestRoute.addressLookupTables.map(
49318
+ (b64) => new PublicKey(Buffer.from(b64, "base64"))
49319
+ );
49320
+ const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
49321
+ const quoteResponse = {
49322
+ ...buildSwapQuoteResult(bestRoute, swapMode),
49323
+ provider: "TITAN" /* TITAN */
49324
+ };
49325
+ return {
49326
+ swapInstructions,
49327
+ setupInstructions: [],
49328
+ addressLookupTableAddresses,
49329
+ quoteResponse
49330
+ };
49331
+ }
49332
+ var getTitanExactOutEstimate = async (params) => {
49333
+ const basePath = params.apiConfig?.basePath ?? "";
49334
+ if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
49335
+ return getTitanExactOutViaWebSocket(params);
49336
+ } else {
49337
+ return getTitanExactOutViaHttpProxy(params);
49338
+ }
49339
+ };
49340
+ async function getTitanExactOutViaWebSocket(params) {
49341
+ const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
49342
+ const wsUrl = apiConfig?.basePath;
49343
+ if (!wsUrl) {
49344
+ throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
49345
+ }
49346
+ const client = await V1Client.connect(wsUrl);
49347
+ try {
49348
+ const { stream } = await client.newSwapQuoteStream({
49349
+ swap: {
49350
+ inputMint: new PublicKey(inputMint).toBytes(),
49351
+ outputMint: new PublicKey(outputMint).toBytes(),
49352
+ amount,
49353
+ swapMode: "ExactOut" /* ExactOut */,
49354
+ slippageBps
49355
+ },
49356
+ transaction: {
49357
+ userPublicKey: new Uint8Array(32)
49358
+ // placeholder, not executing
49359
+ },
49360
+ update: {
49361
+ num_quotes: 1
49362
+ }
49363
+ });
49364
+ const reader = stream.getReader();
49365
+ const { value: swapQuotes, done } = await reader.read();
49366
+ reader.releaseLock();
49367
+ if (done || !swapQuotes) {
49368
+ throw new Error("Titan ExactOut estimate stream ended without data");
49369
+ }
49370
+ const quotes = swapQuotes;
49371
+ const bestRoute = selectBestRoute(quotes.quotes, "ExactOut");
49372
+ if (!bestRoute) {
49373
+ throw new Error(`No Titan ExactOut routes found for ${inputMint} -> ${outputMint}`);
49374
+ }
49375
+ const quoteResult = {
49376
+ ...buildSwapQuoteResult(bestRoute, "ExactOut"),
49377
+ provider: "TITAN" /* TITAN */
49378
+ };
49379
+ return {
49380
+ otherAmountThreshold: quoteResult.otherAmountThreshold,
49381
+ quoteResult
49382
+ };
49383
+ } finally {
49384
+ if (!client.closed) {
49385
+ await client.close();
49386
+ }
49387
+ }
49388
+ }
49389
+ async function getTitanExactOutViaHttpProxy(params) {
49390
+ const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
49391
+ const basePath = apiConfig?.basePath;
49392
+ if (!basePath) {
49393
+ throw new Error("Titan proxy URL is required (apiConfig.basePath)");
49394
+ }
49395
+ const response = await fetch(`${basePath}/exact-out-estimate`, {
49396
+ method: "POST",
49397
+ headers: {
49398
+ "Content-Type": "application/json",
49399
+ ...apiConfig?.headers ?? {}
49400
+ },
49401
+ body: JSON.stringify({
49402
+ inputMint,
49403
+ outputMint,
49404
+ amount,
49405
+ slippageBps
49406
+ })
49407
+ });
49408
+ if (!response.ok) {
49409
+ const errorData = await response.json().catch(() => ({}));
49410
+ throw new Error(
49411
+ `Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
49412
+ );
49413
+ }
49414
+ const data = await response.json();
49415
+ const quoteResult = {
49416
+ inAmount: String(data.inAmount),
49417
+ outAmount: String(data.outAmount),
49418
+ otherAmountThreshold: data.otherAmountThreshold,
49419
+ slippageBps: data.slippageBps,
49420
+ provider: "TITAN" /* TITAN */
49421
+ };
49422
+ return {
49423
+ otherAmountThreshold: data.otherAmountThreshold,
49424
+ quoteResult
49425
+ };
49426
+ }
49427
+
49428
+ // src/services/account/utils/swap.utils.ts
49429
+ function getSwapProviderFn({
49430
+ attemptProvider,
49431
+ maxSwapTotalAccounts,
49432
+ inputMint,
49433
+ outputMint,
49434
+ amount,
49435
+ swapMode,
49436
+ authority,
49437
+ connection,
49438
+ destinationTokenAccount,
49439
+ swapOpts,
49440
+ sizeConstraint
49441
+ }) {
49442
+ switch (attemptProvider) {
49443
+ case "TITAN" /* TITAN */:
49444
+ return (apiConfig) => getTitanSwapIxsForFlashloan({
49445
+ quoteParams: {
49446
+ inputMint,
49447
+ outputMint,
49448
+ amount,
49449
+ swapMode,
49450
+ slippageBps: swapOpts.swapConfig?.slippageBps,
49451
+ platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
49452
+ directRoutesOnly: swapOpts.swapConfig?.directRoutesOnly,
49453
+ sizeConstraint,
49454
+ maxSwapTotalAccounts
49455
+ },
49456
+ authority,
49457
+ connection,
49458
+ destinationTokenAccount,
49459
+ apiConfig
49460
+ });
49461
+ case "JUPITER" /* JUPITER */:
49462
+ return (apiConfig) => getJupiterSwapIxsForFlashloan({
49463
+ quoteParams: {
49464
+ inputMint,
49465
+ outputMint,
49466
+ amount,
49467
+ swapMode,
49468
+ dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
49469
+ slippageBps: swapOpts.swapConfig?.slippageBps,
49470
+ platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
49471
+ onlyDirectRoutes: swapOpts.swapConfig?.directRoutesOnly ?? false
49472
+ },
49473
+ authority,
49474
+ connection,
49475
+ destinationTokenAccount,
49476
+ apiConfig,
49477
+ maxSwapAccounts: maxSwapTotalAccounts
49478
+ });
49479
+ default:
49480
+ return void 0;
49481
+ }
49482
+ }
49483
+ function getExactOutProviderFn({
49484
+ attemptProvider,
49485
+ inputMint,
49486
+ outputMint,
49487
+ amount,
49488
+ swapOpts,
49489
+ apiConfig
49490
+ }) {
49491
+ switch (attemptProvider) {
49492
+ case "TITAN" /* TITAN */:
49493
+ return () => getTitanExactOutEstimate({
49494
+ inputMint,
49495
+ outputMint,
49496
+ amount,
49497
+ slippageBps: swapOpts.swapConfig?.slippageBps,
49498
+ apiConfig
49499
+ });
49500
+ case "JUPITER" /* JUPITER */:
49501
+ return async () => {
49502
+ const configParams = toJupiterConfig(apiConfig);
49503
+ const jupiterApiClient = configParams?.basePath ? new SwapApi(new Configuration(configParams)) : createJupiterApiClient(configParams);
49504
+ const estimateQuote = await jupiterApiClient.quoteGet({
49505
+ inputMint,
49506
+ outputMint,
49507
+ amount,
49508
+ swapMode: "ExactOut",
49509
+ dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
49510
+ slippageBps: swapOpts.swapConfig?.slippageBps
49511
+ });
49512
+ const quoteResult = mapJupiterQuoteToSwapQuoteResult(estimateQuote);
49513
+ return { otherAmountThreshold: quoteResult.otherAmountThreshold, quoteResult };
49514
+ };
49515
+ default:
49516
+ return void 0;
49517
+ }
49518
+ }
49519
+ var getSwapIxsForFlashloan = async (params) => {
49520
+ const {
49521
+ inputMint,
49522
+ outputMint,
49523
+ amount,
49524
+ swapMode,
49525
+ authority,
49526
+ connection,
49527
+ destinationTokenAccount,
49528
+ swapOpts,
49529
+ sizeConstraint,
49530
+ maxSwapTotalAccounts
49531
+ } = params;
49532
+ if (swapOpts.swapIxs) {
49533
+ return {
49534
+ swapInstructions: swapOpts.swapIxs.instructions,
49535
+ setupInstructions: [],
49536
+ addressLookupTableAddresses: swapOpts.swapIxs.lookupTables,
49537
+ quoteResponse: {
49538
+ inAmount: String(amount),
49539
+ outAmount: "0",
49540
+ otherAmountThreshold: "0",
49541
+ slippageBps: 0
49542
+ }
49543
+ };
49544
+ }
49545
+ const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
49546
+ const attempts = [
49547
+ { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
49548
+ ...swapOpts.swapConfig?.fallbackProviders ?? []
49549
+ ];
49550
+ let lastError;
49551
+ for (const { provider: attemptProvider, apiConfig } of attempts) {
49552
+ const fn = getSwapProviderFn({
49553
+ attemptProvider,
49554
+ maxSwapTotalAccounts: params.maxSwapTotalAccounts,
49555
+ inputMint,
49556
+ outputMint,
49557
+ amount,
49558
+ swapMode,
49559
+ authority,
49560
+ connection,
49561
+ destinationTokenAccount,
49562
+ swapOpts,
49563
+ sizeConstraint
49564
+ });
49565
+ if (!fn) continue;
49566
+ try {
49567
+ return await fn(apiConfig);
49568
+ } catch (err) {
49569
+ if (err instanceof TransactionBuildingError) throw err;
49570
+ lastError = err;
49571
+ console.warn(`[swap] ${attemptProvider} failed:`, err instanceof Error ? err.message : err);
49572
+ }
49573
+ }
49574
+ const firstProvider = attempts[0]?.provider ?? "Swap";
49575
+ throw TransactionBuildingError.swapQuoteFailed(
49576
+ firstProvider,
49577
+ inputMint,
49578
+ outputMint,
49579
+ lastError?.message ?? "No swap route available"
49580
+ );
49581
+ };
49582
+ var getExactOutEstimate = async (params) => {
49583
+ const { inputMint, outputMint, amount, swapOpts, connection } = params;
49584
+ const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
49585
+ const attempts = [
49586
+ { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
49587
+ ...swapOpts.swapConfig?.fallbackProviders ?? []
49588
+ ];
49589
+ let lastError;
49590
+ for (const { provider: attemptProvider, apiConfig } of attempts) {
49591
+ const fn = getExactOutProviderFn({
49592
+ attemptProvider,
49593
+ inputMint,
49594
+ outputMint,
49595
+ amount,
49596
+ swapOpts,
49597
+ apiConfig
49598
+ });
49599
+ if (!fn) continue;
49600
+ try {
49601
+ return await fn(apiConfig);
49602
+ } catch (err) {
49603
+ if (err instanceof TransactionBuildingError) throw err;
49604
+ lastError = err;
49605
+ console.warn(
49606
+ `[exactout] ${attemptProvider} failed:`,
49607
+ err instanceof Error ? err.message : err
49608
+ );
49609
+ }
49610
+ }
49611
+ const firstProvider = attempts[0]?.provider ?? "Swap";
49612
+ throw TransactionBuildingError.swapQuoteFailed(
49613
+ firstProvider,
49614
+ inputMint,
49615
+ outputMint,
49616
+ lastError?.message ?? "No swap route available"
49617
+ );
49618
+ };
49619
+ function mapJupiterQuoteToSwapQuoteResult(quote) {
49620
+ return {
49621
+ inAmount: quote.inAmount,
49622
+ outAmount: quote.outAmount,
49623
+ otherAmountThreshold: quote.otherAmountThreshold,
49624
+ slippageBps: quote.slippageBps,
49625
+ platformFee: quote.platformFee ? {
49626
+ amount: quote.platformFee.amount ?? "0",
49627
+ feeBps: quote.platformFee.feeBps ?? 0
49628
+ } : void 0,
49629
+ priceImpactPct: quote.priceImpactPct,
49630
+ contextSlot: quote.contextSlot,
49631
+ timeTaken: quote.timeTaken,
49632
+ provider: "JUPITER" /* JUPITER */
49633
+ };
49634
+ }
49635
+
49636
+ // src/services/account/utils/jupiter.utils.ts
48862
49637
  var REFERRAL_PROGRAM_ID = new PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
48863
49638
  var REFERRAL_ACCOUNT_PUBKEY = new PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
48864
49639
  var getFeeAccount = (mint) => {
48865
- const referralProgramPubkey = REFERRAL_PROGRAM_ID;
48866
- const referralAccountPubkey = REFERRAL_ACCOUNT_PUBKEY;
48867
49640
  const [feeAccount] = PublicKey.findProgramAddressSync(
48868
- [Buffer.from("referral_ata"), referralAccountPubkey.toBuffer(), mint.toBuffer()],
48869
- referralProgramPubkey
49641
+ [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
49642
+ REFERRAL_PROGRAM_ID
48870
49643
  );
48871
49644
  return feeAccount.toBase58();
48872
49645
  };
49646
+ var checkFeeAccount = async (connection, mint) => {
49647
+ const feeAccount = getFeeAccount(mint);
49648
+ const hasFeeAccount = !!await connection.getAccountInfo(new PublicKey(feeAccount));
49649
+ return { feeAccount, hasFeeAccount };
49650
+ };
48873
49651
  function deserializeJupiterInstruction(instruction) {
48874
49652
  return new TransactionInstruction({
48875
49653
  programId: new PublicKey(instruction.programId),
@@ -48881,17 +49659,26 @@ function deserializeJupiterInstruction(instruction) {
48881
49659
  data: Buffer.from(instruction.data, "base64")
48882
49660
  });
48883
49661
  }
49662
+ function toJupiterConfig(apiConfig) {
49663
+ if (!apiConfig) return void 0;
49664
+ return {
49665
+ basePath: apiConfig.basePath,
49666
+ apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
49667
+ headers: apiConfig.headers
49668
+ };
49669
+ }
48884
49670
  var getJupiterSwapIxsForFlashloan = async ({
48885
49671
  quoteParams,
48886
49672
  authority,
48887
49673
  connection,
48888
49674
  destinationTokenAccount,
48889
- configParams
49675
+ apiConfig,
49676
+ maxSwapAccounts
48890
49677
  }) => {
49678
+ const configParams = toJupiterConfig(apiConfig);
48891
49679
  const jupiterApiClient = configParams?.basePath ? new SwapApi(new Configuration(configParams)) : createJupiterApiClient(configParams);
48892
49680
  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));
49681
+ const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new PublicKey(feeMint));
48895
49682
  const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
48896
49683
  let finalQuoteParams = quoteParams;
48897
49684
  if (!hasFeeAccount) {
@@ -48901,67 +49688,45 @@ var getJupiterSwapIxsForFlashloan = async ({
48901
49688
  platformFeeBps: void 0
48902
49689
  };
48903
49690
  }
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
- );
49691
+ const JUPITER_MAX_ACCOUNTS_MARGIN = 4;
49692
+ const maxAccounts = maxSwapAccounts !== void 0 ? maxSwapAccounts - JUPITER_MAX_ACCOUNTS_MARGIN : 40;
49693
+ const swapQuote = await jupiterApiClient.quoteGet({
49694
+ ...finalQuoteParams,
49695
+ maxAccounts
49696
+ });
49697
+ const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
49698
+ swapRequest: {
49699
+ quoteResponse: swapQuote,
49700
+ userPublicKey: authority.toBase58(),
49701
+ feeAccount: hasFeeAccount ? feeAccount : void 0,
49702
+ wrapAndUnwrapSol: false,
49703
+ destinationTokenAccount: destinationTokenAccount.toBase58()
49704
+ }
49705
+ });
49706
+ const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
48930
49707
  const lutAccountsRaw = await connection.getMultipleAccountsInfo(
48931
- lutAddresses.flat().map((address) => new PublicKey(address))
49708
+ lutAddresses.map((address) => new PublicKey(address))
48932
49709
  );
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
49710
+ const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
49711
+ const addressLookupTableAddress = lutAddresses[index];
49712
+ if (!accountInfo || !addressLookupTableAddress) {
49713
+ return null;
49714
+ }
49715
+ return new AddressLookupTableAccount({
49716
+ key: new PublicKey(addressLookupTableAddress),
49717
+ state: AddressLookupTableAccount.deserialize(accountInfo.data)
48962
49718
  });
48963
- }
48964
- return jupiterSwapIxs;
49719
+ }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
49720
+ const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
49721
+ const setupInstructions = swapInstructionResponse.setupInstructions.map(
49722
+ deserializeJupiterInstruction
49723
+ );
49724
+ return {
49725
+ swapInstructions: [instruction],
49726
+ setupInstructions,
49727
+ addressLookupTableAddresses: addressLookupTableAccounts,
49728
+ quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
49729
+ };
48965
49730
  };
48966
49731
 
48967
49732
  // src/services/account/utils/misc.utils.ts
@@ -48979,6 +49744,440 @@ function isWholePosition(position, amount, mintDecimals) {
48979
49744
  const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
48980
49745
  return amount >= closePositionTokenAmount;
48981
49746
  }
49747
+ var SWAP_MERGE_OVERHEAD = 150;
49748
+ var FL_IX_OVERHEAD = 52;
49749
+ function compactU16Size(n) {
49750
+ return n < 128 ? 1 : n < 16384 ? 2 : 3;
49751
+ }
49752
+ function computeV0TxSize(ixs, payerKey, luts) {
49753
+ const keyMap = /* @__PURE__ */ new Map();
49754
+ const payerStr = payerKey.toBase58();
49755
+ keyMap.set(payerStr, { isSigner: true, isWritable: true });
49756
+ const programIds = /* @__PURE__ */ new Set();
49757
+ for (const ix of ixs) {
49758
+ const progStr = ix.programId.toBase58();
49759
+ programIds.add(progStr);
49760
+ if (!keyMap.has(progStr)) {
49761
+ keyMap.set(progStr, { isSigner: false, isWritable: false });
49762
+ }
49763
+ for (const meta of ix.keys) {
49764
+ const keyStr = meta.pubkey.toBase58();
49765
+ const existing = keyMap.get(keyStr);
49766
+ if (existing) {
49767
+ existing.isSigner = existing.isSigner || meta.isSigner;
49768
+ existing.isWritable = existing.isWritable || meta.isWritable;
49769
+ } else {
49770
+ keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
49771
+ }
49772
+ }
49773
+ }
49774
+ const lutLookup = /* @__PURE__ */ new Map();
49775
+ for (let li = 0; li < luts.length; li++) {
49776
+ const addresses = luts[li].state.addresses;
49777
+ for (let ai = 0; ai < addresses.length; ai++) {
49778
+ const addrStr = addresses[ai].toBase58();
49779
+ if (!lutLookup.has(addrStr)) {
49780
+ lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
49781
+ }
49782
+ }
49783
+ }
49784
+ let numStaticKeys = 0;
49785
+ let numWritableStaticKeys = 0;
49786
+ const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
49787
+ const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
49788
+ for (const [keyStr, props] of keyMap) {
49789
+ if (props.isSigner || programIds.has(keyStr)) {
49790
+ numStaticKeys++;
49791
+ if (props.isWritable) numWritableStaticKeys++;
49792
+ continue;
49793
+ }
49794
+ const lutEntry = lutLookup.get(keyStr);
49795
+ if (lutEntry) {
49796
+ if (props.isWritable) {
49797
+ lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49798
+ } else {
49799
+ lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49800
+ }
49801
+ } else {
49802
+ numStaticKeys++;
49803
+ if (props.isWritable) numWritableStaticKeys++;
49804
+ }
49805
+ }
49806
+ const fixedOverhead = 101;
49807
+ const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
49808
+ let ixSection = compactU16Size(ixs.length);
49809
+ for (const ix of ixs) {
49810
+ const numAccounts = ix.keys.length;
49811
+ ixSection += 1 + // programId index
49812
+ compactU16Size(numAccounts) + numAccounts + // account key indexes
49813
+ compactU16Size(ix.data.length) + ix.data.length;
49814
+ }
49815
+ let numUsedLuts = 0;
49816
+ let lutSection = 0;
49817
+ for (let li = 0; li < luts.length; li++) {
49818
+ const wCount = lutWritableIdxs[li].size;
49819
+ const rCount = lutReadonlyIdxs[li].size;
49820
+ if (wCount === 0 && rCount === 0) continue;
49821
+ numUsedLuts++;
49822
+ lutSection += 32 + // LUT address
49823
+ compactU16Size(wCount) + wCount + // writable indexes
49824
+ compactU16Size(rCount) + rCount;
49825
+ }
49826
+ lutSection += compactU16Size(numUsedLuts);
49827
+ let totalLutKeys = 0;
49828
+ for (let li = 0; li < luts.length; li++) {
49829
+ totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
49830
+ }
49831
+ const accountCount = numStaticKeys + totalLutKeys;
49832
+ let totalLutWritableKeys = 0;
49833
+ for (let li = 0; li < luts.length; li++) {
49834
+ totalLutWritableKeys += lutWritableIdxs[li].size;
49835
+ }
49836
+ const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
49837
+ const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
49838
+ return { size, accountCount, writableAccountCount };
49839
+ }
49840
+ function computeFlashLoanNonSwapBudget({
49841
+ program,
49842
+ marginfiAccount,
49843
+ ixs,
49844
+ bankMap,
49845
+ addressLookupTableAccounts
49846
+ }) {
49847
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
49848
+ marginfiAccount.balances,
49849
+ ixs,
49850
+ program
49851
+ );
49852
+ const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
49853
+ const b = bankMap.get(key.toBase58());
49854
+ if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
49855
+ return b;
49856
+ });
49857
+ const endIndex = ixs.length + 1;
49858
+ const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
49859
+ program.programId,
49860
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49861
+ { endIndex: new BN11(endIndex) }
49862
+ );
49863
+ const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
49864
+ const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
49865
+ program.programId,
49866
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49867
+ endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
49868
+ );
49869
+ const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
49870
+ const nonSwapMsg = new TransactionMessage({
49871
+ payerKey: marginfiAccount.authority,
49872
+ recentBlockhash: PublicKey.default.toBase58(),
49873
+ instructions: allNonSwapIxs
49874
+ }).compileToV0Message(addressLookupTableAccounts);
49875
+ const nonSwapSize = new VersionedTransaction(nonSwapMsg).serialize().length;
49876
+ const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
49877
+ const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
49878
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49879
+ 0
49880
+ );
49881
+ const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
49882
+ const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
49883
+ console.log("[flashloan-budget]", {
49884
+ method: "compiled",
49885
+ nonSwapSize,
49886
+ nonSwapTotal,
49887
+ sizeConstraint,
49888
+ maxSwapTotalAccounts
49889
+ });
49890
+ return { sizeConstraint, maxSwapTotalAccounts };
49891
+ }
49892
+ function compileFlashloanPrecheck({
49893
+ allIxs,
49894
+ payer,
49895
+ luts,
49896
+ sizeConstraint,
49897
+ swapIxCount,
49898
+ swapLutCount
49899
+ }) {
49900
+ const msg = new TransactionMessage({
49901
+ payerKey: payer,
49902
+ recentBlockhash: PublicKey.default.toBase58(),
49903
+ instructions: allIxs
49904
+ }).compileToV0Message(luts);
49905
+ const rawSize = new VersionedTransaction(msg).serialize().length;
49906
+ const fullTxSize = rawSize + FL_IX_OVERHEAD;
49907
+ const overshoot = fullTxSize - MAX_TX_SIZE;
49908
+ const { header, staticAccountKeys, addressTableLookups } = msg;
49909
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
49910
+ const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
49911
+ const writableAccounts = writableStatic + writableLut;
49912
+ const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
49913
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49914
+ 0
49915
+ );
49916
+ console.log("[flashloan-precheck]", {
49917
+ fullTxSize,
49918
+ overshoot,
49919
+ sizeConstraint,
49920
+ writableAccounts,
49921
+ totalAccounts,
49922
+ staticKeys: staticAccountKeys.length,
49923
+ numLuts: addressTableLookups.length,
49924
+ swapIxCount,
49925
+ swapLutCount
49926
+ });
49927
+ return { fullTxSize, overshoot, writableAccounts, totalAccounts };
49928
+ }
49929
+ async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
49930
+ const { bank, tokenProgram } = config;
49931
+ switch (config.type) {
49932
+ case "borrow":
49933
+ return makeBorrowIx3({
49934
+ program,
49935
+ bank,
49936
+ bankMap,
49937
+ tokenProgram,
49938
+ amount: 1,
49939
+ marginfiAccount,
49940
+ authority: marginfiAccount.authority,
49941
+ isSync: true,
49942
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
49943
+ });
49944
+ case "repay":
49945
+ return makeRepayIx3({
49946
+ program,
49947
+ bank,
49948
+ tokenProgram,
49949
+ amount: 1,
49950
+ accountAddress: marginfiAccount.address,
49951
+ authority: marginfiAccount.authority,
49952
+ repayAll: false,
49953
+ isSync: true,
49954
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
49955
+ });
49956
+ case "deposit":
49957
+ return buildDepositBudgetIx(
49958
+ config,
49959
+ program,
49960
+ marginfiAccount,
49961
+ bankMetadataMap,
49962
+ overrideInferAccounts
49963
+ );
49964
+ case "withdraw":
49965
+ return buildWithdrawBudgetIx(
49966
+ config,
49967
+ program,
49968
+ marginfiAccount,
49969
+ bankMap,
49970
+ bankMetadataMap,
49971
+ overrideInferAccounts
49972
+ );
49973
+ }
49974
+ }
49975
+ async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
49976
+ const { bank, tokenProgram } = config;
49977
+ const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
49978
+ switch (bank.config.assetTag) {
49979
+ case 3 /* KAMINO */: {
49980
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
49981
+ if (!reserve) {
49982
+ throw TransactionBuildingError.kaminoReserveNotFound(
49983
+ bank.address.toBase58(),
49984
+ bank.mint.toBase58(),
49985
+ bank.tokenSymbol
49986
+ );
49987
+ }
49988
+ return makeKaminoDepositIx3({
49989
+ program,
49990
+ bank,
49991
+ tokenProgram,
49992
+ amount: 1,
49993
+ accountAddress: marginfiAccount.address,
49994
+ authority: marginfiAccount.authority,
49995
+ group: marginfiAccount.group,
49996
+ reserve,
49997
+ isSync: true,
49998
+ opts
49999
+ });
50000
+ }
50001
+ case 4 /* DRIFT */: {
50002
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50003
+ if (!driftState) {
50004
+ throw TransactionBuildingError.driftStateNotFound(
50005
+ bank.address.toBase58(),
50006
+ bank.mint.toBase58(),
50007
+ bank.tokenSymbol
50008
+ );
50009
+ }
50010
+ return makeDriftDepositIx3({
50011
+ program,
50012
+ bank,
50013
+ tokenProgram,
50014
+ amount: 1,
50015
+ accountAddress: marginfiAccount.address,
50016
+ authority: marginfiAccount.authority,
50017
+ group: marginfiAccount.group,
50018
+ driftMarketIndex: driftState.spotMarketState.marketIndex,
50019
+ driftOracle: driftState.spotMarketState.oracle,
50020
+ isSync: true,
50021
+ opts
50022
+ });
50023
+ }
50024
+ case 6 /* JUPLEND */: {
50025
+ return makeJuplendDepositIx2({
50026
+ program,
50027
+ bank,
50028
+ tokenProgram,
50029
+ amount: 1,
50030
+ accountAddress: marginfiAccount.address,
50031
+ authority: marginfiAccount.authority,
50032
+ group: marginfiAccount.group,
50033
+ isSync: true,
50034
+ opts
50035
+ });
50036
+ }
50037
+ default: {
50038
+ return makeDepositIx3({
50039
+ program,
50040
+ bank,
50041
+ tokenProgram,
50042
+ amount: 1,
50043
+ accountAddress: marginfiAccount.address,
50044
+ authority: marginfiAccount.authority,
50045
+ group: marginfiAccount.group,
50046
+ isSync: true,
50047
+ opts
50048
+ });
50049
+ }
50050
+ }
50051
+ }
50052
+ async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
50053
+ const { bank, tokenProgram } = config;
50054
+ const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
50055
+ switch (bank.config.assetTag) {
50056
+ case 3 /* KAMINO */: {
50057
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
50058
+ if (!reserve) {
50059
+ throw TransactionBuildingError.kaminoReserveNotFound(
50060
+ bank.address.toBase58(),
50061
+ bank.mint.toBase58(),
50062
+ bank.tokenSymbol
50063
+ );
50064
+ }
50065
+ return makeKaminoWithdrawIx3({
50066
+ program,
50067
+ bank,
50068
+ bankMap,
50069
+ tokenProgram,
50070
+ cTokenAmount: 1,
50071
+ marginfiAccount,
50072
+ authority: marginfiAccount.authority,
50073
+ reserve,
50074
+ withdrawAll: false,
50075
+ isSync: true,
50076
+ opts
50077
+ });
50078
+ }
50079
+ case 4 /* DRIFT */: {
50080
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50081
+ if (!driftState) {
50082
+ throw TransactionBuildingError.driftStateNotFound(
50083
+ bank.address.toBase58(),
50084
+ bank.mint.toBase58(),
50085
+ bank.tokenSymbol
50086
+ );
50087
+ }
50088
+ return makeDriftWithdrawIx3({
50089
+ program,
50090
+ bank,
50091
+ bankMap,
50092
+ tokenProgram,
50093
+ amount: 1,
50094
+ marginfiAccount,
50095
+ authority: marginfiAccount.authority,
50096
+ driftSpotMarket: driftState.spotMarketState,
50097
+ userRewards: driftState.userRewards,
50098
+ withdrawAll: false,
50099
+ isSync: true,
50100
+ opts
50101
+ });
50102
+ }
50103
+ case 6 /* JUPLEND */: {
50104
+ const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
50105
+ if (!jupLendState) {
50106
+ throw TransactionBuildingError.jupLendStateNotFound(
50107
+ bank.address.toBase58(),
50108
+ bank.mint.toBase58(),
50109
+ bank.tokenSymbol
50110
+ );
50111
+ }
50112
+ return makeJuplendWithdrawIx2({
50113
+ program,
50114
+ bank,
50115
+ bankMap,
50116
+ tokenProgram,
50117
+ amount: 1,
50118
+ marginfiAccount,
50119
+ authority: marginfiAccount.authority,
50120
+ jupLendingState: jupLendState.jupLendingState,
50121
+ withdrawAll: false,
50122
+ opts
50123
+ });
50124
+ }
50125
+ default: {
50126
+ return makeWithdrawIx3({
50127
+ program,
50128
+ bank,
50129
+ bankMap,
50130
+ tokenProgram,
50131
+ amount: 1,
50132
+ marginfiAccount,
50133
+ authority: marginfiAccount.authority,
50134
+ withdrawAll: false,
50135
+ isSync: true,
50136
+ opts
50137
+ });
50138
+ }
50139
+ }
50140
+ }
50141
+ async function computeFlashloanSwapConstraints({
50142
+ program,
50143
+ marginfiAccount,
50144
+ bankMap,
50145
+ addressLookupTableAccounts,
50146
+ bankMetadataMap,
50147
+ primaryIx,
50148
+ secondaryIx,
50149
+ overrideInferAccounts
50150
+ }) {
50151
+ const cuRequestIxs = [
50152
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
50153
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
50154
+ ];
50155
+ const [primaryResult, secondaryResult] = await Promise.all([
50156
+ buildBudgetIx(
50157
+ primaryIx,
50158
+ program,
50159
+ marginfiAccount,
50160
+ bankMap,
50161
+ bankMetadataMap,
50162
+ overrideInferAccounts
50163
+ ),
50164
+ buildBudgetIx(
50165
+ secondaryIx,
50166
+ program,
50167
+ marginfiAccount,
50168
+ bankMap,
50169
+ bankMetadataMap,
50170
+ overrideInferAccounts
50171
+ )
50172
+ ]);
50173
+ return computeFlashLoanNonSwapBudget({
50174
+ program,
50175
+ marginfiAccount,
50176
+ bankMap,
50177
+ addressLookupTableAccounts,
50178
+ ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
50179
+ });
50180
+ }
48982
50181
 
48983
50182
  // src/services/price/utils/smart-crank.utils.ts
48984
50183
  async function computeSmartCrank({
@@ -50182,7 +51381,7 @@ function computeMaxLeverage(depositBank, borrowBank, opts) {
50182
51381
  ltv
50183
51382
  };
50184
51383
  }
50185
- function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositOracleInfo, borrowOracleInfo, opts) {
51384
+ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositPriceUsd, borrowPriceUsd, opts) {
50186
51385
  const initialCollateral = toBigNumber(principal);
50187
51386
  const { maxLeverage } = computeMaxLeverage(depositBank, borrowBank, opts);
50188
51387
  let clampedLeverage = targetLeverage;
@@ -50197,7 +51396,7 @@ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank
50197
51396
  }
50198
51397
  const totalDepositAmount = initialCollateral.times(new BigNumber3(clampedLeverage));
50199
51398
  const additionalDepositAmount = totalDepositAmount.minus(initialCollateral);
50200
- const totalBorrowAmount = additionalDepositAmount.times(depositOracleInfo.priceWeighted.lowestPrice).div(borrowOracleInfo.priceWeighted.highestPrice);
51399
+ const totalBorrowAmount = additionalDepositAmount.times(new BigNumber3(depositPriceUsd)).div(new BigNumber3(borrowPriceUsd));
50201
51400
  return {
50202
51401
  totalBorrowAmount: totalBorrowAmount.decimalPlaces(
50203
51402
  borrowBank.mintDecimals,
@@ -51241,6 +52440,230 @@ function getValidatorVoteAccountByBank() {
51241
52440
  }
51242
52441
  return _voteAccountByBank;
51243
52442
  }
52443
+ async function computeStakedBankMultipliers(stakedBanks, connection) {
52444
+ const multiplierByBank = /* @__PURE__ */ new Map();
52445
+ if (stakedBanks.length === 0) {
52446
+ return multiplierByBank;
52447
+ }
52448
+ const metadataMap = getStakedBankMetadataMap();
52449
+ const stakedBankAddresses = [];
52450
+ const poolStakeAddresses = [];
52451
+ const lstMintAddresses = [];
52452
+ for (const bank of stakedBanks) {
52453
+ const metadata = metadataMap.get(bank.address.toBase58());
52454
+ if (!metadata) {
52455
+ multiplierByBank.set(bank.address.toBase58(), new BigNumber3(1));
52456
+ continue;
52457
+ }
52458
+ const pool = findPoolAddress(new PublicKey(metadata.validatorVoteAccount));
52459
+ stakedBankAddresses.push(bank.address.toBase58());
52460
+ poolStakeAddresses.push(findPoolStakeAddress(pool));
52461
+ lstMintAddresses.push(findPoolMintAddress(pool));
52462
+ }
52463
+ if (stakedBankAddresses.length === 0) {
52464
+ return multiplierByBank;
52465
+ }
52466
+ const allAddresses = [
52467
+ ...poolStakeAddresses.map((a) => a.toBase58()),
52468
+ ...lstMintAddresses.map((a) => a.toBase58())
52469
+ ];
52470
+ const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses);
52471
+ const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
52472
+ const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
52473
+ for (let i = 0; i < stakedBankAddresses.length; i++) {
52474
+ const bankAddr = stakedBankAddresses[i];
52475
+ const poolStakeInfo = poolStakeInfos[i];
52476
+ const lstMintInfo = lstMintInfos[i];
52477
+ if (!poolStakeInfo || !lstMintInfo) {
52478
+ multiplierByBank.set(bankAddr, new BigNumber3(1));
52479
+ continue;
52480
+ }
52481
+ const stakeLamports = poolStakeInfo.lamports;
52482
+ const supplyBuffer = lstMintInfo.data.slice(36, 44);
52483
+ const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
52484
+ if (lstMintSupply === 0) {
52485
+ multiplierByBank.set(bankAddr, new BigNumber3(1));
52486
+ continue;
52487
+ }
52488
+ const adjustedStake = Math.max(stakeLamports - LAMPORTS_PER_SOL, 0);
52489
+ const multiplier = new BigNumber3(adjustedStake).dividedBy(lstMintSupply);
52490
+ multiplierByBank.set(bankAddr, multiplier);
52491
+ }
52492
+ return multiplierByBank;
52493
+ }
52494
+ var SYSVAR_CLOCK_ID2 = new PublicKey("SysvarC1ock11111111111111111111111111111111");
52495
+ async function makeMintStakedLstIx(params) {
52496
+ const { amount, authority, stakeAccountPk, validator, connection } = params;
52497
+ const pool = findPoolAddress(validator);
52498
+ const lstMint = findPoolMintAddress(pool);
52499
+ const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
52500
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52501
+ const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
52502
+ connection.getAccountInfo(lstAta),
52503
+ connection.getParsedAccountInfo(stakeAccountPk),
52504
+ connection.getMinimumBalanceForRentExemption(StakeProgram.space)
52505
+ ]);
52506
+ const stakeAccParsed = stakeAccInfoParsed?.value?.data;
52507
+ const amountLamports = Math.round(Number(amount) * LAMPORTS_PER_SOL);
52508
+ const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
52509
+ const isFullStake = amountLamports >= stakeAccLamports;
52510
+ const instructions2 = [];
52511
+ const signers = [];
52512
+ if (!lstAccInfo) {
52513
+ instructions2.push(
52514
+ createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
52515
+ );
52516
+ }
52517
+ let targetStakePubkey;
52518
+ if (!isFullStake) {
52519
+ const splitStakeAccount = Keypair.generate();
52520
+ signers.push(splitStakeAccount);
52521
+ targetStakePubkey = splitStakeAccount.publicKey;
52522
+ instructions2.push(
52523
+ ...StakeProgram.split(
52524
+ {
52525
+ stakePubkey: stakeAccountPk,
52526
+ authorizedPubkey: authority,
52527
+ splitStakePubkey: splitStakeAccount.publicKey,
52528
+ lamports: amountLamports
52529
+ },
52530
+ rentExemptReserve
52531
+ ).instructions
52532
+ );
52533
+ } else {
52534
+ targetStakePubkey = stakeAccountPk;
52535
+ }
52536
+ const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
52537
+ StakeProgram.authorize({
52538
+ stakePubkey: targetStakePubkey,
52539
+ authorizedPubkey: authority,
52540
+ newAuthorizedPubkey: poolStakeAuth,
52541
+ stakeAuthorizationType: StakeAuthorizationLayout.Staker
52542
+ }).instructions,
52543
+ StakeProgram.authorize({
52544
+ stakePubkey: targetStakePubkey,
52545
+ authorizedPubkey: authority,
52546
+ newAuthorizedPubkey: poolStakeAuth,
52547
+ stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer
52548
+ }).instructions
52549
+ ]);
52550
+ [authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
52551
+ if (ix) {
52552
+ ix.keys = ix.keys.map((key) => ({
52553
+ ...key,
52554
+ isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
52555
+ }));
52556
+ }
52557
+ });
52558
+ instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
52559
+ const depositStakeIx = await SinglePoolInstruction.depositStake(
52560
+ pool,
52561
+ targetStakePubkey,
52562
+ lstAta,
52563
+ authority
52564
+ );
52565
+ instructions2.push(depositStakeIx);
52566
+ return { instructions: instructions2, keys: signers };
52567
+ }
52568
+ async function makeMintStakedLstTx(params) {
52569
+ const { connection, luts, blockhash: providedBlockhash } = params;
52570
+ const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
52571
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52572
+ const message = new TransactionMessage({
52573
+ payerKey: params.authority,
52574
+ recentBlockhash: blockhash,
52575
+ instructions: instructions2
52576
+ }).compileToV0Message(luts);
52577
+ const tx = new VersionedTransaction(message);
52578
+ return addTransactionMetadata(tx, {
52579
+ signers: keys,
52580
+ addressLookupTables: luts,
52581
+ type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
52582
+ });
52583
+ }
52584
+ async function makeRedeemStakedLstIx(params) {
52585
+ const { amount, authority, validator, connection } = params;
52586
+ const pool = findPoolAddress(validator);
52587
+ const lstMint = findPoolMintAddress(pool);
52588
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
52589
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52590
+ const rentExemption = await connection.getMinimumBalanceForRentExemption(
52591
+ StakeProgram.space
52592
+ );
52593
+ const stakeAmount = new BigNumber3(new BigNumber3(amount).toString());
52594
+ const instructions2 = [];
52595
+ const signers = [];
52596
+ const stakeAccount = Keypair.generate();
52597
+ signers.push(stakeAccount);
52598
+ instructions2.push(
52599
+ SystemProgram.createAccount({
52600
+ fromPubkey: authority,
52601
+ newAccountPubkey: stakeAccount.publicKey,
52602
+ lamports: rentExemption,
52603
+ space: StakeProgram.space,
52604
+ programId: StakeProgram.programId
52605
+ })
52606
+ );
52607
+ instructions2.push(
52608
+ createApproveInstruction(
52609
+ lstAta,
52610
+ mintAuthority,
52611
+ authority,
52612
+ BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
52613
+ )
52614
+ );
52615
+ const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
52616
+ pool,
52617
+ stakeAccount.publicKey,
52618
+ authority,
52619
+ lstAta,
52620
+ stakeAmount
52621
+ );
52622
+ instructions2.push(withdrawStakeIx);
52623
+ return { instructions: instructions2, keys: signers };
52624
+ }
52625
+ async function makeRedeemStakedLstTx(params) {
52626
+ const { connection, luts, blockhash: providedBlockhash } = params;
52627
+ const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
52628
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52629
+ const message = new TransactionMessage({
52630
+ payerKey: params.authority,
52631
+ recentBlockhash: blockhash,
52632
+ instructions: instructions2
52633
+ }).compileToV0Message(luts);
52634
+ const tx = new VersionedTransaction(message);
52635
+ return addTransactionMetadata(tx, {
52636
+ signers: keys,
52637
+ addressLookupTables: luts,
52638
+ type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
52639
+ });
52640
+ }
52641
+ async function makeMergeStakeAccountsTx(params) {
52642
+ const {
52643
+ authority,
52644
+ sourceStakeAccount,
52645
+ destinationStakeAccount,
52646
+ connection,
52647
+ luts,
52648
+ blockhash: providedBlockhash
52649
+ } = params;
52650
+ const mergeIx = StakeProgram.merge({
52651
+ stakePubkey: destinationStakeAccount,
52652
+ sourceStakePubKey: sourceStakeAccount,
52653
+ authorizedPubkey: authority
52654
+ }).instructions;
52655
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52656
+ const message = new TransactionMessage({
52657
+ payerKey: authority,
52658
+ recentBlockhash: blockhash,
52659
+ instructions: mergeIx
52660
+ }).compileToV0Message(luts);
52661
+ const tx = new VersionedTransaction(message);
52662
+ return addTransactionMetadata(tx, {
52663
+ addressLookupTables: luts,
52664
+ type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
52665
+ });
52666
+ }
51244
52667
  async function getKaminoMetadata(options) {
51245
52668
  const kaminoBanks = options.banks.filter((b) => b.config.assetTag === 3 /* KAMINO */);
51246
52669
  const DEFAULT_PUBKEY = PublicKey.default;
@@ -52664,7 +54087,7 @@ var MarginfiAccount = class _MarginfiAccount {
52664
54087
  * @param params.oraclePrices - Map of current oracle prices
52665
54088
  * @param params.depositOpts - Deposit configuration (bank, amount, mode)
52666
54089
  * @param params.borrowOpts - Borrow configuration (bank, amount)
52667
- * @param params.swapOpts - Jupiter swap configuration (slippage, fees)
54090
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52668
54091
  * @param params.addressLookupTableAccounts - Address lookup tables
52669
54092
  * @param params.overrideInferAccounts - Optional account overrides
52670
54093
  * @param params.additionalIxs - Additional instructions to include
@@ -52702,7 +54125,7 @@ var MarginfiAccount = class _MarginfiAccount {
52702
54125
  * @param params.oraclePrices - Map of current oracle prices
52703
54126
  * @param params.withdrawOpts - Withdraw configuration (bank, amount)
52704
54127
  * @param params.repayOpts - Repay configuration (bank, optional amount)
52705
- * @param params.swapOpts - Jupiter swap configuration
54128
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52706
54129
  * @param params.addressLookupTableAccounts - Address lookup tables
52707
54130
  * @param params.overrideInferAccounts - Optional account overrides
52708
54131
  * @param params.additionalIxs - Additional instructions to include
@@ -52742,7 +54165,7 @@ var MarginfiAccount = class _MarginfiAccount {
52742
54165
  * @param params.oraclePrices - Map of current oracle prices
52743
54166
  * @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
52744
54167
  * @param params.depositOpts - Deposit configuration (bank, tokenProgram)
52745
- * @param params.swapOpts - Jupiter swap configuration
54168
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52746
54169
  * @param params.addressLookupTableAccounts - Address lookup tables
52747
54170
  * @param params.overrideInferAccounts - Optional account overrides
52748
54171
  * @param params.additionalIxs - Additional instructions to include
@@ -52782,7 +54205,7 @@ var MarginfiAccount = class _MarginfiAccount {
52782
54205
  * @param params.oraclePrices - Map of current oracle prices
52783
54206
  * @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
52784
54207
  * @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
52785
- * @param params.swapOpts - Jupiter swap configuration
54208
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
52786
54209
  * @param params.addressLookupTableAccounts - Address lookup tables
52787
54210
  * @param params.overrideInferAccounts - Optional account overrides
52788
54211
  * @param params.additionalIxs - Additional instructions to include
@@ -53677,66 +55100,6 @@ var MarginfiAccountWrapper = class {
53677
55100
  return this.account.getHealthCheckAccounts(this.client.bankMap, mandatoryBanks, excludedBanks);
53678
55101
  }
53679
55102
  // ----------------------------------------------------------------------------
53680
- // Native stake actions
53681
- // Note: These call standalone action functions directly rather than routing
53682
- // through this.account because they interact with the SPL stake pool program,
53683
- // not the marginfi program. No MarginfiAccount state is needed.
53684
- // ----------------------------------------------------------------------------
53685
- /**
53686
- * Creates a transaction to mint LST from a native stake account.
53687
- *
53688
- * Converts a native stake account (or a portion of it) into LST tokens
53689
- * by depositing the stake into the single-validator pool.
53690
- *
53691
- * @param amount - SOL amount to convert (in UI units)
53692
- * @param stakeAccountPk - The stake account to convert
53693
- * @param validator - The validator vote account
53694
- */
53695
- async makeMintStakedLstTx(amount, stakeAccountPk, validator) {
53696
- return makeMintStakedLstTx({
53697
- amount,
53698
- authority: this.authority,
53699
- stakeAccountPk,
53700
- validator,
53701
- connection: this.client.program.provider.connection,
53702
- luts: this.client.addressLookupTables
53703
- });
53704
- }
53705
- /**
53706
- * Creates a transaction to redeem LST tokens back to a native stake account.
53707
- *
53708
- * Burns LST tokens and withdraws the underlying stake into a new stake account.
53709
- *
53710
- * @param amount - LST amount to redeem (in UI units)
53711
- * @param validator - The validator vote account
53712
- */
53713
- async makeRedeemStakedLstTx(amount, validator) {
53714
- return makeRedeemStakedLstTx({
53715
- amount,
53716
- authority: this.authority,
53717
- validator,
53718
- connection: this.client.program.provider.connection,
53719
- luts: this.client.addressLookupTables
53720
- });
53721
- }
53722
- /**
53723
- * Creates a transaction to merge two stake accounts.
53724
- *
53725
- * Both accounts must share the same authorized staker/withdrawer and vote account.
53726
- *
53727
- * @param sourceStakeAccount - The stake account to merge from (will be consumed)
53728
- * @param destinationStakeAccount - The stake account to merge into
53729
- */
53730
- async makeMergeStakeAccountsTx(sourceStakeAccount, destinationStakeAccount) {
53731
- return makeMergeStakeAccountsTx({
53732
- authority: this.authority,
53733
- sourceStakeAccount,
53734
- destinationStakeAccount,
53735
- connection: this.client.program.provider.connection,
53736
- luts: this.client.addressLookupTables
53737
- });
53738
- }
53739
- // ----------------------------------------------------------------------------
53740
55103
  // Helper methods
53741
55104
  // ----------------------------------------------------------------------------
53742
55105
  /**
@@ -54006,56 +55369,11 @@ var Project0Client = class _Project0Client {
54006
55369
  break;
54007
55370
  }
54008
55371
  });
54009
- const stakedBanks = banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */);
54010
- if (stakedBanks.length > 0) {
54011
- const metadataMap = getStakedBankMetadataMap();
54012
- const stakedBankAddresses = [];
54013
- const poolStakeAddresses = [];
54014
- const lstMintAddresses = [];
54015
- for (const bank of stakedBanks) {
54016
- const metadata = metadataMap.get(bank.address.toBase58());
54017
- if (!metadata) {
54018
- assetShareMultiplierByBank.set(bank.address.toBase58(), new BigNumber3(1));
54019
- continue;
54020
- }
54021
- const pool = findPoolAddress(new PublicKey(metadata.validatorVoteAccount));
54022
- stakedBankAddresses.push(bank.address.toBase58());
54023
- poolStakeAddresses.push(findPoolStakeAddress(pool));
54024
- lstMintAddresses.push(findPoolMintAddress(pool));
54025
- }
54026
- if (stakedBankAddresses.length > 0) {
54027
- const allAddresses = [
54028
- ...poolStakeAddresses.map((a) => a.toBase58()),
54029
- ...lstMintAddresses.map((a) => a.toBase58())
54030
- ];
54031
- const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(
54032
- connection,
54033
- allAddresses
54034
- );
54035
- const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
54036
- const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
54037
- for (let i = 0; i < stakedBankAddresses.length; i++) {
54038
- const bankAddr = stakedBankAddresses[i];
54039
- const poolStakeInfo = poolStakeInfos[i];
54040
- const lstMintInfo = lstMintInfos[i];
54041
- if (!poolStakeInfo || !lstMintInfo) {
54042
- assetShareMultiplierByBank.set(bankAddr, new BigNumber3(1));
54043
- continue;
54044
- }
54045
- const stakeLamports = poolStakeInfo.lamports;
54046
- const supplyBuffer = lstMintInfo.data.slice(36, 44);
54047
- const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
54048
- if (lstMintSupply === 0) {
54049
- assetShareMultiplierByBank.set(bankAddr, new BigNumber3(1));
54050
- continue;
54051
- }
54052
- const LAMPORTS_PER_SOL5 = 1e9;
54053
- const adjustedStake = Math.max(stakeLamports - LAMPORTS_PER_SOL5, 0);
54054
- const multiplier = new BigNumber3(adjustedStake).dividedBy(lstMintSupply);
54055
- assetShareMultiplierByBank.set(bankAddr, multiplier);
54056
- }
54057
- }
54058
- }
55372
+ const stakedMultipliers = await computeStakedBankMultipliers(
55373
+ banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */),
55374
+ connection
55375
+ );
55376
+ stakedMultipliers.forEach((v, k) => assetShareMultiplierByBank.set(k, v));
54059
55377
  const emodePairs = getEmodePairs(banksArray);
54060
55378
  return new _Project0Client(
54061
55379
  program,
@@ -54097,6 +55415,6 @@ var EmodeSettings = class _EmodeSettings {
54097
55415
  }
54098
55416
  };
54099
55417
 
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 };
55418
+ 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, computeStakedBankMultipliers, 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
55419
  //# sourceMappingURL=index.js.map
54102
55420
  //# sourceMappingURL=index.js.map