@0dotxyz/p0-ts-sdk 2.2.0-alpha.4 → 2.2.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2302 -917
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +284 -72
- package/dist/index.d.ts +284 -72
- package/dist/index.js +2288 -918
- package/dist/index.js.map +1 -1
- package/dist/vendor.cjs +349 -0
- package/dist/vendor.cjs.map +1 -1
- package/dist/vendor.d.cts +288 -3
- package/dist/vendor.d.ts +288 -3
- package/dist/vendor.js +340 -2
- package/dist/vendor.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,8 @@ var bufferLayoutUtils = require('@solana/buffer-layout-utils');
|
|
|
11
11
|
var buffer = require('buffer');
|
|
12
12
|
var borsh$1 = require('borsh');
|
|
13
13
|
var borsh = require('@coral-xyz/borsh');
|
|
14
|
+
var WebSocket = require('ws');
|
|
15
|
+
var msgpack = require('@msgpack/msgpack');
|
|
14
16
|
var api = require('@jup-ag/api');
|
|
15
17
|
var onDemand = require('@switchboard-xyz/on-demand');
|
|
16
18
|
var common = require('@switchboard-xyz/common');
|
|
@@ -39,6 +41,7 @@ var BigNumber3__default = /*#__PURE__*/_interopDefault(BigNumber3);
|
|
|
39
41
|
var BN11__default = /*#__PURE__*/_interopDefault(BN11);
|
|
40
42
|
var Decimal3__default = /*#__PURE__*/_interopDefault(Decimal3);
|
|
41
43
|
var borsh__namespace = /*#__PURE__*/_interopNamespace(borsh);
|
|
44
|
+
var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
|
|
42
45
|
|
|
43
46
|
// src/config.ts
|
|
44
47
|
|
|
@@ -117,10 +120,14 @@ function getConfig(environment = "production", overrides) {
|
|
|
117
120
|
var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCode2) => {
|
|
118
121
|
TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_REPAY"] = "JUPITER_SWAP_SIZE_EXCEEDED_REPAY";
|
|
119
122
|
TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_LOOP"] = "JUPITER_SWAP_SIZE_EXCEEDED_LOOP";
|
|
123
|
+
TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_LOOP"] = "SWAP_SIZE_EXCEEDED_LOOP";
|
|
124
|
+
TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_REPAY"] = "SWAP_SIZE_EXCEEDED_REPAY";
|
|
120
125
|
TransactionBuildingErrorCode2["ORACLE_CRANK_FAILED"] = "ORACLE_CRANK_FAILED";
|
|
121
126
|
TransactionBuildingErrorCode2["KAMINO_RESERVE_NOT_FOUND"] = "KAMINO_RESERVE_NOT_FOUND";
|
|
122
127
|
TransactionBuildingErrorCode2["DRIFT_STATE_NOT_FOUND"] = "DRIFT_STATE_NOT_FOUND";
|
|
123
128
|
TransactionBuildingErrorCode2["JUPLEND_STATE_NOT_FOUND"] = "JUPLEND_STATE_NOT_FOUND";
|
|
129
|
+
TransactionBuildingErrorCode2["SWITCHBOARD_FEED_UPDATE_FAILED"] = "SWITCHBOARD_FEED_UPDATE_FAILED";
|
|
130
|
+
TransactionBuildingErrorCode2["SWAP_QUOTE_FAILED"] = "SWAP_QUOTE_FAILED";
|
|
124
131
|
return TransactionBuildingErrorCode2;
|
|
125
132
|
})(TransactionBuildingErrorCode || {});
|
|
126
133
|
var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
@@ -152,6 +159,20 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
152
159
|
{ bytes, accountKeys }
|
|
153
160
|
);
|
|
154
161
|
}
|
|
162
|
+
static swapSizeExceededLoop(bytes, accountKeys, provider) {
|
|
163
|
+
return new _TransactionBuildingError(
|
|
164
|
+
"SWAP_SIZE_EXCEEDED_LOOP" /* SWAP_SIZE_EXCEEDED_LOOP */,
|
|
165
|
+
`${provider ?? "Swap"} instruction size exceeds available transaction size`,
|
|
166
|
+
{ bytes, accountKeys, provider }
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
static swapSizeExceededRepay(bytes, accountKeys, provider) {
|
|
170
|
+
return new _TransactionBuildingError(
|
|
171
|
+
"SWAP_SIZE_EXCEEDED_REPAY" /* SWAP_SIZE_EXCEEDED_REPAY */,
|
|
172
|
+
`${provider ?? "Swap"} instruction size exceeds available transaction size`,
|
|
173
|
+
{ bytes, accountKeys, provider }
|
|
174
|
+
);
|
|
175
|
+
}
|
|
155
176
|
/**
|
|
156
177
|
* Failed to crank oracles for one or more banks
|
|
157
178
|
*/
|
|
@@ -193,6 +214,26 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
193
214
|
{ bankAddress, bankMint, bankSymbol }
|
|
194
215
|
);
|
|
195
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Failed to update Switchboard price feeds
|
|
219
|
+
*/
|
|
220
|
+
static switchboardFeedUpdateFailed(oracleKeys, reason) {
|
|
221
|
+
return new _TransactionBuildingError(
|
|
222
|
+
"SWITCHBOARD_FEED_UPDATE_FAILED" /* SWITCHBOARD_FEED_UPDATE_FAILED */,
|
|
223
|
+
`Switchboard feed update failed: ${reason}`,
|
|
224
|
+
{ oracleKeys, reason }
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Failed to get a swap quote from any provider
|
|
229
|
+
*/
|
|
230
|
+
static swapQuoteFailed(provider, inputMint, outputMint, reason) {
|
|
231
|
+
return new _TransactionBuildingError(
|
|
232
|
+
"SWAP_QUOTE_FAILED" /* SWAP_QUOTE_FAILED */,
|
|
233
|
+
`${provider} swap quote failed for ${inputMint} \u2192 ${outputMint}: ${reason}`,
|
|
234
|
+
{ provider, inputMint, outputMint, reason }
|
|
235
|
+
);
|
|
236
|
+
}
|
|
196
237
|
/**
|
|
197
238
|
* Generic escape hatch for custom errors
|
|
198
239
|
*/
|
|
@@ -345,6 +386,7 @@ var MAX_U64 = BigInt("18446744073709551615").toString();
|
|
|
345
386
|
|
|
346
387
|
// src/constants/transaction.consts.ts
|
|
347
388
|
var MAX_TX_SIZE = 1232;
|
|
389
|
+
var MAX_ACCOUNT_LOCKS = 64;
|
|
348
390
|
var BUNDLE_TX_SIZE = 81;
|
|
349
391
|
var PRIORITY_TX_SIZE = 44;
|
|
350
392
|
var WSOL_MINT = new web3_js.PublicKey("So11111111111111111111111111111111111111112");
|
|
@@ -14893,8 +14935,40 @@ function getTxSize(tx) {
|
|
|
14893
14935
|
const signaturesSize = (numRequiredSignatures - numSigners) * 64 + 1;
|
|
14894
14936
|
try {
|
|
14895
14937
|
const baseTxSize = isVersioned ? tx.serialize().length : tx.serialize({ requireAllSignatures: false, verifySignatures: false }).length;
|
|
14896
|
-
|
|
14897
|
-
|
|
14938
|
+
const totalSize = baseTxSize + feePayerSize + signaturesSize;
|
|
14939
|
+
if (isVersioned && totalSize > 1232) {
|
|
14940
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14941
|
+
const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
14942
|
+
const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
|
|
14943
|
+
console.warn("[getTxSize] oversized TX", {
|
|
14944
|
+
totalSize,
|
|
14945
|
+
overshoot: totalSize - 1232,
|
|
14946
|
+
staticKeys: staticAccountKeys.length,
|
|
14947
|
+
numSignatures: header.numRequiredSignatures,
|
|
14948
|
+
numLuts: addressTableLookups.length,
|
|
14949
|
+
lutWritable,
|
|
14950
|
+
lutReadonly,
|
|
14951
|
+
totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
|
|
14952
|
+
});
|
|
14953
|
+
}
|
|
14954
|
+
return totalSize;
|
|
14955
|
+
} catch (err) {
|
|
14956
|
+
if (isVersioned) {
|
|
14957
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14958
|
+
const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
14959
|
+
const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
|
|
14960
|
+
console.warn("[getTxSize] serialize failed", {
|
|
14961
|
+
error: err.message,
|
|
14962
|
+
staticKeys: staticAccountKeys.length,
|
|
14963
|
+
numSignatures: header.numRequiredSignatures,
|
|
14964
|
+
numLuts: addressTableLookups.length,
|
|
14965
|
+
lutWritable,
|
|
14966
|
+
lutReadonly,
|
|
14967
|
+
totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
|
|
14968
|
+
});
|
|
14969
|
+
} else {
|
|
14970
|
+
console.warn("[getTxSize] serialize failed", { error: err.message });
|
|
14971
|
+
}
|
|
14898
14972
|
return 9999;
|
|
14899
14973
|
}
|
|
14900
14974
|
}
|
|
@@ -14909,6 +14983,47 @@ function getAccountKeys(tx, lookupTableAccounts) {
|
|
|
14909
14983
|
} else {
|
|
14910
14984
|
return tx.compileMessage().getAccountKeys().length;
|
|
14911
14985
|
}
|
|
14986
|
+
} catch (err) {
|
|
14987
|
+
console.warn("[getAccountKeys] decompile failed", { error: err.message });
|
|
14988
|
+
return 9999;
|
|
14989
|
+
}
|
|
14990
|
+
}
|
|
14991
|
+
function getWritableAccountKeys(tx) {
|
|
14992
|
+
const isVersioned = isV0Tx(tx);
|
|
14993
|
+
try {
|
|
14994
|
+
if (isVersioned) {
|
|
14995
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14996
|
+
const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
|
|
14997
|
+
const writableLut = addressTableLookups.reduce(
|
|
14998
|
+
(sum, lookup) => sum + lookup.writableIndexes.length,
|
|
14999
|
+
0
|
|
15000
|
+
);
|
|
15001
|
+
return writableStatic + writableLut;
|
|
15002
|
+
} else {
|
|
15003
|
+
const message = tx.compileMessage();
|
|
15004
|
+
const { numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts } = message.header;
|
|
15005
|
+
const totalKeys = message.accountKeys.length;
|
|
15006
|
+
const writableSigned = numRequiredSignatures - numReadonlySignedAccounts;
|
|
15007
|
+
const writableUnsigned = totalKeys - numRequiredSignatures - numReadonlyUnsignedAccounts;
|
|
15008
|
+
return writableSigned + writableUnsigned;
|
|
15009
|
+
}
|
|
15010
|
+
} catch {
|
|
15011
|
+
return 9999;
|
|
15012
|
+
}
|
|
15013
|
+
}
|
|
15014
|
+
function getTotalAccountKeys(tx) {
|
|
15015
|
+
const isVersioned = isV0Tx(tx);
|
|
15016
|
+
try {
|
|
15017
|
+
if (isVersioned) {
|
|
15018
|
+
const { staticAccountKeys, addressTableLookups } = tx.message;
|
|
15019
|
+
const lutAccounts = addressTableLookups.reduce(
|
|
15020
|
+
(sum, lookup) => sum + lookup.writableIndexes.length + lookup.readonlyIndexes.length,
|
|
15021
|
+
0
|
|
15022
|
+
);
|
|
15023
|
+
return staticAccountKeys.length + lutAccounts;
|
|
15024
|
+
} else {
|
|
15025
|
+
return tx.compileMessage().accountKeys.length;
|
|
15026
|
+
}
|
|
14912
15027
|
} catch {
|
|
14913
15028
|
return 9999;
|
|
14914
15029
|
}
|
|
@@ -20146,6 +20261,14 @@ var HealthCacheSimulationError = class _HealthCacheSimulationError extends Error
|
|
|
20146
20261
|
}
|
|
20147
20262
|
};
|
|
20148
20263
|
|
|
20264
|
+
// src/services/account/types/action.types.ts
|
|
20265
|
+
var SwapProvider = /* @__PURE__ */ ((SwapProvider2) => {
|
|
20266
|
+
SwapProvider2["JUPITER"] = "JUPITER";
|
|
20267
|
+
SwapProvider2["TITAN"] = "TITAN";
|
|
20268
|
+
SwapProvider2["DFLOW"] = "DFLOW";
|
|
20269
|
+
return SwapProvider2;
|
|
20270
|
+
})(SwapProvider || {});
|
|
20271
|
+
|
|
20149
20272
|
// src/services/account/utils/deserialize.utils.ts
|
|
20150
20273
|
var EMPTY_HEALTH_CACHE = {
|
|
20151
20274
|
assetValue: {
|
|
@@ -44194,6 +44317,330 @@ function makeUpdateJupLendRate({ lendingState }) {
|
|
|
44194
44317
|
lendingState.rewardsRateModel
|
|
44195
44318
|
);
|
|
44196
44319
|
}
|
|
44320
|
+
var SUBPROTOCOL = "v1.api.titan.ag";
|
|
44321
|
+
var UINT64_MAX = (1n << 64n) - 1n;
|
|
44322
|
+
function toBigInt(value) {
|
|
44323
|
+
if (typeof value === "bigint") {
|
|
44324
|
+
if (value < 0n || value > UINT64_MAX) {
|
|
44325
|
+
throw new RangeError(`Amount out of uint64 range: ${value}`);
|
|
44326
|
+
}
|
|
44327
|
+
return value;
|
|
44328
|
+
}
|
|
44329
|
+
if (!Number.isInteger(value)) {
|
|
44330
|
+
throw new TypeError(`Amount must be a whole number, got ${value}`);
|
|
44331
|
+
}
|
|
44332
|
+
if (value < 0) {
|
|
44333
|
+
throw new RangeError(`Amount must be non-negative, got ${value}`);
|
|
44334
|
+
}
|
|
44335
|
+
return BigInt(value);
|
|
44336
|
+
}
|
|
44337
|
+
var ConnectionClosed = class _ConnectionClosed extends Error {
|
|
44338
|
+
code;
|
|
44339
|
+
reason;
|
|
44340
|
+
constructor(code, reason) {
|
|
44341
|
+
super(`Client WebSocket closed with code ${code}: ${reason}`);
|
|
44342
|
+
this.name = "ConnectionClosed";
|
|
44343
|
+
Object.setPrototypeOf(this, _ConnectionClosed.prototype);
|
|
44344
|
+
this.code = code;
|
|
44345
|
+
this.reason = reason;
|
|
44346
|
+
}
|
|
44347
|
+
};
|
|
44348
|
+
var ErrorResponse = class _ErrorResponse extends Error {
|
|
44349
|
+
response;
|
|
44350
|
+
constructor(response) {
|
|
44351
|
+
super(`Request ${response.requestId} failed with code ${response.code}: ${response.message}`);
|
|
44352
|
+
this.name = "ErrorResponse";
|
|
44353
|
+
Object.setPrototypeOf(this, _ErrorResponse.prototype);
|
|
44354
|
+
this.response = response;
|
|
44355
|
+
}
|
|
44356
|
+
};
|
|
44357
|
+
var StreamError = class _StreamError extends Error {
|
|
44358
|
+
streamId;
|
|
44359
|
+
errorCode;
|
|
44360
|
+
errorMessage;
|
|
44361
|
+
constructor(packet) {
|
|
44362
|
+
const code = packet.errorCode ?? 0;
|
|
44363
|
+
const message = packet.errorMessage ?? "";
|
|
44364
|
+
super(`Stream ${packet.id} ended with error code ${code}: ${message}`);
|
|
44365
|
+
this.name = "StreamError";
|
|
44366
|
+
Object.setPrototypeOf(this, _StreamError.prototype);
|
|
44367
|
+
this.streamId = packet.id;
|
|
44368
|
+
this.errorCode = code;
|
|
44369
|
+
this.errorMessage = message;
|
|
44370
|
+
}
|
|
44371
|
+
};
|
|
44372
|
+
var encoder = new msgpack.Encoder({ useBigInt64: true });
|
|
44373
|
+
var decoder = new msgpack.Decoder({ useBigInt64: true });
|
|
44374
|
+
var V1Client = class _V1Client {
|
|
44375
|
+
socket;
|
|
44376
|
+
nextId = 0;
|
|
44377
|
+
_closed = false;
|
|
44378
|
+
_closing = false;
|
|
44379
|
+
pending = /* @__PURE__ */ new Map();
|
|
44380
|
+
streams = /* @__PURE__ */ new Map();
|
|
44381
|
+
streamStopping = /* @__PURE__ */ new Map();
|
|
44382
|
+
closeListeners = [];
|
|
44383
|
+
// --- Static connect ---
|
|
44384
|
+
static connect(url) {
|
|
44385
|
+
return new Promise((resolve, reject) => {
|
|
44386
|
+
const ws = new WebSocket__default.default(url, [SUBPROTOCOL]);
|
|
44387
|
+
ws.binaryType = "arraybuffer";
|
|
44388
|
+
ws.on("open", () => {
|
|
44389
|
+
resolve(new _V1Client(ws));
|
|
44390
|
+
});
|
|
44391
|
+
ws.on("error", (err) => {
|
|
44392
|
+
reject(err);
|
|
44393
|
+
});
|
|
44394
|
+
});
|
|
44395
|
+
}
|
|
44396
|
+
// --- Constructor ---
|
|
44397
|
+
constructor(socket) {
|
|
44398
|
+
this.socket = socket;
|
|
44399
|
+
this.socket.on("message", (data) => {
|
|
44400
|
+
this.handleMessage(data);
|
|
44401
|
+
});
|
|
44402
|
+
this.socket.on("close", (code, reason) => {
|
|
44403
|
+
this.handleClose(code, reason.toString());
|
|
44404
|
+
});
|
|
44405
|
+
this.socket.on("error", (err) => {
|
|
44406
|
+
this.handleError(err);
|
|
44407
|
+
});
|
|
44408
|
+
}
|
|
44409
|
+
nextRequestId() {
|
|
44410
|
+
return this.nextId++;
|
|
44411
|
+
}
|
|
44412
|
+
// --- Public API ---
|
|
44413
|
+
get closed() {
|
|
44414
|
+
return this._closed;
|
|
44415
|
+
}
|
|
44416
|
+
close() {
|
|
44417
|
+
if (this._closed) return Promise.resolve();
|
|
44418
|
+
return new Promise((resolve, reject) => {
|
|
44419
|
+
this.closeListeners.push({ resolve, reject });
|
|
44420
|
+
if (!this._closing) {
|
|
44421
|
+
this._closing = true;
|
|
44422
|
+
this.socket.close();
|
|
44423
|
+
}
|
|
44424
|
+
});
|
|
44425
|
+
}
|
|
44426
|
+
newSwapQuoteStream(params) {
|
|
44427
|
+
const requestId = this.nextRequestId();
|
|
44428
|
+
const promise = new Promise(
|
|
44429
|
+
(resolve, reject) => {
|
|
44430
|
+
this.pending.set(requestId, {
|
|
44431
|
+
resolve,
|
|
44432
|
+
reject,
|
|
44433
|
+
kind: "NewSwapQuoteStream"
|
|
44434
|
+
});
|
|
44435
|
+
}
|
|
44436
|
+
);
|
|
44437
|
+
const normalized = {
|
|
44438
|
+
...params,
|
|
44439
|
+
swap: { ...params.swap, amount: toBigInt(params.swap.amount) }
|
|
44440
|
+
};
|
|
44441
|
+
const message = {
|
|
44442
|
+
id: requestId,
|
|
44443
|
+
data: { NewSwapQuoteStream: normalized }
|
|
44444
|
+
};
|
|
44445
|
+
this.send(message);
|
|
44446
|
+
return promise;
|
|
44447
|
+
}
|
|
44448
|
+
stopStream(streamId) {
|
|
44449
|
+
const requestId = this.nextRequestId();
|
|
44450
|
+
const promise = new Promise((resolve, reject) => {
|
|
44451
|
+
this.pending.set(requestId, {
|
|
44452
|
+
resolve,
|
|
44453
|
+
reject,
|
|
44454
|
+
kind: "StopStream"
|
|
44455
|
+
});
|
|
44456
|
+
});
|
|
44457
|
+
const message = {
|
|
44458
|
+
id: requestId,
|
|
44459
|
+
data: { StopStream: { id: streamId } }
|
|
44460
|
+
};
|
|
44461
|
+
this.send(message);
|
|
44462
|
+
return promise;
|
|
44463
|
+
}
|
|
44464
|
+
// --- Send ---
|
|
44465
|
+
send(message) {
|
|
44466
|
+
try {
|
|
44467
|
+
const encoded = encoder.encode(message);
|
|
44468
|
+
this.socket.send(encoded);
|
|
44469
|
+
} catch (err) {
|
|
44470
|
+
const req = this.pending.get(message.id);
|
|
44471
|
+
if (req) {
|
|
44472
|
+
this.pending.delete(message.id);
|
|
44473
|
+
req.reject(err);
|
|
44474
|
+
}
|
|
44475
|
+
}
|
|
44476
|
+
}
|
|
44477
|
+
// --- Message handling ---
|
|
44478
|
+
handleMessage(raw) {
|
|
44479
|
+
let buf;
|
|
44480
|
+
if (raw instanceof ArrayBuffer) {
|
|
44481
|
+
buf = new Uint8Array(raw);
|
|
44482
|
+
} else if (Buffer.isBuffer(raw)) {
|
|
44483
|
+
buf = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
44484
|
+
} else if (Array.isArray(raw)) {
|
|
44485
|
+
buf = new Uint8Array(Buffer.concat(raw));
|
|
44486
|
+
} else {
|
|
44487
|
+
return;
|
|
44488
|
+
}
|
|
44489
|
+
let message;
|
|
44490
|
+
try {
|
|
44491
|
+
message = decoder.decode(buf);
|
|
44492
|
+
} catch {
|
|
44493
|
+
this.socket.close(3002, "failed to decode message");
|
|
44494
|
+
return;
|
|
44495
|
+
}
|
|
44496
|
+
if ("Response" in message) {
|
|
44497
|
+
this.handleResponse(message.Response);
|
|
44498
|
+
} else if ("Error" in message) {
|
|
44499
|
+
this.handleResponseError(message.Error);
|
|
44500
|
+
} else if ("StreamData" in message) {
|
|
44501
|
+
this.handleStreamData(message.StreamData);
|
|
44502
|
+
} else if ("StreamEnd" in message) {
|
|
44503
|
+
this.handleStreamEnd(message.StreamEnd);
|
|
44504
|
+
}
|
|
44505
|
+
}
|
|
44506
|
+
handleResponse(msg) {
|
|
44507
|
+
const req = this.pending.get(msg.requestId);
|
|
44508
|
+
if (!req) return;
|
|
44509
|
+
this.pending.delete(msg.requestId);
|
|
44510
|
+
if ("NewSwapQuoteStream" in msg.data && req.kind === "NewSwapQuoteStream") {
|
|
44511
|
+
const streamInfo = msg.stream;
|
|
44512
|
+
if (!streamInfo) {
|
|
44513
|
+
req.reject(new Error("No stream associated with NewSwapQuoteStream response"));
|
|
44514
|
+
return;
|
|
44515
|
+
}
|
|
44516
|
+
const stream = new ReadableStream({
|
|
44517
|
+
start: (controller) => {
|
|
44518
|
+
this.streams.set(streamInfo.id, controller);
|
|
44519
|
+
},
|
|
44520
|
+
cancel: () => {
|
|
44521
|
+
return this.cancelStream(streamInfo.id);
|
|
44522
|
+
}
|
|
44523
|
+
});
|
|
44524
|
+
const result = {
|
|
44525
|
+
response: msg.data.NewSwapQuoteStream,
|
|
44526
|
+
stream,
|
|
44527
|
+
streamId: streamInfo.id
|
|
44528
|
+
};
|
|
44529
|
+
req.resolve(result);
|
|
44530
|
+
} else if ("StreamStopped" in msg.data && req.kind === "StopStream") {
|
|
44531
|
+
req.resolve(msg.data.StreamStopped);
|
|
44532
|
+
} else {
|
|
44533
|
+
req.reject(new Error(`Unexpected response type for ${req.kind}`));
|
|
44534
|
+
}
|
|
44535
|
+
}
|
|
44536
|
+
handleResponseError(error) {
|
|
44537
|
+
const req = this.pending.get(error.requestId);
|
|
44538
|
+
if (!req) return;
|
|
44539
|
+
this.pending.delete(error.requestId);
|
|
44540
|
+
req.reject(new ErrorResponse(error));
|
|
44541
|
+
}
|
|
44542
|
+
handleStreamData(packet) {
|
|
44543
|
+
const controller = this.streams.get(packet.id);
|
|
44544
|
+
if (!controller) return;
|
|
44545
|
+
if (packet.payload.SwapQuotes !== void 0) {
|
|
44546
|
+
controller.enqueue(packet.payload.SwapQuotes);
|
|
44547
|
+
}
|
|
44548
|
+
}
|
|
44549
|
+
handleStreamEnd(packet) {
|
|
44550
|
+
const controller = this.streams.get(packet.id);
|
|
44551
|
+
if (!controller) return;
|
|
44552
|
+
this.streams.delete(packet.id);
|
|
44553
|
+
this.streamStopping.delete(packet.id);
|
|
44554
|
+
if (packet.errorCode !== void 0) {
|
|
44555
|
+
controller.error(new StreamError(packet));
|
|
44556
|
+
} else {
|
|
44557
|
+
controller.close();
|
|
44558
|
+
}
|
|
44559
|
+
}
|
|
44560
|
+
async cancelStream(streamId) {
|
|
44561
|
+
if (this.streamStopping.get(streamId) || !this.streams.has(streamId)) return;
|
|
44562
|
+
this.streamStopping.set(streamId, true);
|
|
44563
|
+
await this.stopStream(streamId);
|
|
44564
|
+
}
|
|
44565
|
+
// --- Connection lifecycle ---
|
|
44566
|
+
rejectAll(error) {
|
|
44567
|
+
for (const req of this.pending.values()) {
|
|
44568
|
+
req.reject(error);
|
|
44569
|
+
}
|
|
44570
|
+
this.pending.clear();
|
|
44571
|
+
for (const controller of this.streams.values()) {
|
|
44572
|
+
controller.error(error);
|
|
44573
|
+
}
|
|
44574
|
+
this.streams.clear();
|
|
44575
|
+
this.streamStopping.clear();
|
|
44576
|
+
}
|
|
44577
|
+
handleClose(code, reason) {
|
|
44578
|
+
this._closed = true;
|
|
44579
|
+
this.rejectAll(new ConnectionClosed(code, reason));
|
|
44580
|
+
for (const listener of this.closeListeners) {
|
|
44581
|
+
listener.resolve();
|
|
44582
|
+
}
|
|
44583
|
+
this.closeListeners = [];
|
|
44584
|
+
}
|
|
44585
|
+
handleError(err) {
|
|
44586
|
+
this.rejectAll(err);
|
|
44587
|
+
this.socket.close(3002);
|
|
44588
|
+
}
|
|
44589
|
+
};
|
|
44590
|
+
function deserializeSerializedInstruction(ix) {
|
|
44591
|
+
return new web3_js.TransactionInstruction({
|
|
44592
|
+
programId: new web3_js.PublicKey(Buffer.from(ix.p, "base64")),
|
|
44593
|
+
keys: ix.a.map((account) => ({
|
|
44594
|
+
pubkey: new web3_js.PublicKey(Buffer.from(account.p, "base64")),
|
|
44595
|
+
isSigner: account.s,
|
|
44596
|
+
isWritable: account.w
|
|
44597
|
+
})),
|
|
44598
|
+
data: Buffer.from(ix.d, "base64")
|
|
44599
|
+
});
|
|
44600
|
+
}
|
|
44601
|
+
function selectBestRoute(quotes, swapMode) {
|
|
44602
|
+
const routes = Object.values(quotes);
|
|
44603
|
+
if (routes.length === 0) return null;
|
|
44604
|
+
return routes.reduce((best, route) => {
|
|
44605
|
+
if (swapMode === "ExactIn") {
|
|
44606
|
+
return route.outAmount > best.outAmount ? route : best;
|
|
44607
|
+
} else {
|
|
44608
|
+
return route.inAmount < best.inAmount ? route : best;
|
|
44609
|
+
}
|
|
44610
|
+
});
|
|
44611
|
+
}
|
|
44612
|
+
function buildSwapQuoteResult(route, swapMode) {
|
|
44613
|
+
const slippageBps = route.slippageBps;
|
|
44614
|
+
let otherAmountThreshold;
|
|
44615
|
+
if (swapMode === "ExactIn") {
|
|
44616
|
+
otherAmountThreshold = String(Math.floor(route.outAmount * (1 - slippageBps / 1e4)));
|
|
44617
|
+
} else {
|
|
44618
|
+
otherAmountThreshold = String(Math.ceil(route.inAmount * (1 + slippageBps / 1e4)));
|
|
44619
|
+
}
|
|
44620
|
+
return {
|
|
44621
|
+
inAmount: String(route.inAmount),
|
|
44622
|
+
outAmount: String(route.outAmount),
|
|
44623
|
+
otherAmountThreshold,
|
|
44624
|
+
slippageBps,
|
|
44625
|
+
platformFee: route.platformFee ? {
|
|
44626
|
+
amount: String(route.platformFee.amount),
|
|
44627
|
+
feeBps: route.platformFee.fee_bps
|
|
44628
|
+
} : void 0,
|
|
44629
|
+
contextSlot: route.contextSlot,
|
|
44630
|
+
timeTaken: route.timeTaken
|
|
44631
|
+
};
|
|
44632
|
+
}
|
|
44633
|
+
async function resolveLookupTables(connection, lutPubkeys) {
|
|
44634
|
+
if (lutPubkeys.length === 0) return [];
|
|
44635
|
+
const lutAccountsRaw = await connection.getMultipleAccountsInfo(lutPubkeys);
|
|
44636
|
+
return lutAccountsRaw.map((accountInfo, index) => {
|
|
44637
|
+
if (!accountInfo) return null;
|
|
44638
|
+
return new web3_js.AddressLookupTableAccount({
|
|
44639
|
+
key: lutPubkeys[index],
|
|
44640
|
+
state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
|
|
44641
|
+
});
|
|
44642
|
+
}).filter((account) => account !== null);
|
|
44643
|
+
}
|
|
44197
44644
|
|
|
44198
44645
|
// src/vendor/klend/utils/klend/interest-rate.utils.ts
|
|
44199
44646
|
function getKaminoTotalSupply(reserve) {
|
|
@@ -46483,116 +46930,81 @@ async function makeJuplendDepositTx(params) {
|
|
|
46483
46930
|
});
|
|
46484
46931
|
return solanaTx;
|
|
46485
46932
|
}
|
|
46486
|
-
async function
|
|
46487
|
-
|
|
46488
|
-
|
|
46489
|
-
|
|
46490
|
-
|
|
46491
|
-
|
|
46492
|
-
|
|
46493
|
-
|
|
46494
|
-
|
|
46933
|
+
async function makeRepayIx3({
|
|
46934
|
+
program,
|
|
46935
|
+
bank,
|
|
46936
|
+
tokenProgram,
|
|
46937
|
+
amount,
|
|
46938
|
+
authority,
|
|
46939
|
+
accountAddress,
|
|
46940
|
+
repayAll = false,
|
|
46941
|
+
isSync = false,
|
|
46942
|
+
opts = {}
|
|
46943
|
+
}) {
|
|
46944
|
+
const wrapAndUnwrapSol = opts.wrapAndUnwrapSol ?? true;
|
|
46945
|
+
const wSolBalanceUi = opts.wSolBalanceUi ?? 0;
|
|
46946
|
+
const repayIxs = [];
|
|
46947
|
+
const userAta = getAssociatedTokenAddressSync(bank.mint, authority, true, tokenProgram);
|
|
46948
|
+
const remainingAccounts = tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? [{ pubkey: bank.mint, isSigner: false, isWritable: false }] : [];
|
|
46949
|
+
if (bank.mint.equals(NATIVE_MINT) && wrapAndUnwrapSol) {
|
|
46950
|
+
repayIxs.push(...makeWrapSolIxs(authority, new BigNumber3.BigNumber(amount).minus(wSolBalanceUi)));
|
|
46951
|
+
}
|
|
46952
|
+
const repayIx = !isSync || !opts.overrideInferAccounts?.group ? await instructions_default.makeRepayIx(
|
|
46495
46953
|
program,
|
|
46496
46954
|
{
|
|
46497
|
-
marginfiAccount:
|
|
46498
|
-
|
|
46955
|
+
marginfiAccount: accountAddress,
|
|
46956
|
+
signerTokenAccount: userAta,
|
|
46957
|
+
bank: bank.address,
|
|
46958
|
+
tokenProgram,
|
|
46959
|
+
authority: opts.overrideInferAccounts?.authority ?? authority,
|
|
46960
|
+
group: opts.overrideInferAccounts?.group,
|
|
46961
|
+
liquidityVault: opts.overrideInferAccounts?.liquidityVault
|
|
46499
46962
|
},
|
|
46500
|
-
{
|
|
46501
|
-
|
|
46502
|
-
|
|
46503
|
-
}
|
|
46504
|
-
async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
|
|
46505
|
-
const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
|
|
46506
|
-
const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
|
|
46963
|
+
{ amount: uiToNative(amount, bank.mintDecimals), repayAll },
|
|
46964
|
+
remainingAccounts
|
|
46965
|
+
) : sync_instructions_default.makeRepayIx(
|
|
46507
46966
|
program.programId,
|
|
46508
46967
|
{
|
|
46509
|
-
marginfiAccount:
|
|
46510
|
-
|
|
46511
|
-
|
|
46512
|
-
|
|
46513
|
-
|
|
46514
|
-
|
|
46515
|
-
isWritable: false
|
|
46516
|
-
}))
|
|
46517
|
-
) : await instructions_default.makeEndFlashLoanIx(
|
|
46518
|
-
program,
|
|
46519
|
-
{
|
|
46520
|
-
marginfiAccount: marginfiAccountPk,
|
|
46521
|
-
authority
|
|
46968
|
+
marginfiAccount: accountAddress,
|
|
46969
|
+
signerTokenAccount: userAta,
|
|
46970
|
+
bank: bank.address,
|
|
46971
|
+
tokenProgram,
|
|
46972
|
+
authority: opts.overrideInferAccounts?.authority ?? authority,
|
|
46973
|
+
group: opts.overrideInferAccounts?.group
|
|
46522
46974
|
},
|
|
46523
|
-
|
|
46524
|
-
|
|
46525
|
-
isSigner: false,
|
|
46526
|
-
isWritable: false
|
|
46527
|
-
}))
|
|
46975
|
+
{ amount: uiToNative(amount, bank.mintDecimals), repayAll },
|
|
46976
|
+
remainingAccounts
|
|
46528
46977
|
);
|
|
46529
|
-
|
|
46978
|
+
repayIxs.push(repayIx);
|
|
46979
|
+
return {
|
|
46980
|
+
instructions: repayIxs,
|
|
46981
|
+
keys: []
|
|
46982
|
+
};
|
|
46530
46983
|
}
|
|
46531
|
-
async function
|
|
46532
|
-
|
|
46533
|
-
|
|
46534
|
-
ixs
|
|
46535
|
-
|
|
46536
|
-
|
|
46537
|
-
|
|
46538
|
-
|
|
46539
|
-
|
|
46540
|
-
}) {
|
|
46541
|
-
const endIndex = ixs.length + 1;
|
|
46542
|
-
const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
|
|
46543
|
-
marginfiAccount.balances,
|
|
46544
|
-
ixs,
|
|
46545
|
-
program
|
|
46546
|
-
);
|
|
46547
|
-
const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
|
|
46548
|
-
const b = bankMap.get(account.toBase58());
|
|
46549
|
-
if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
|
|
46550
|
-
return b;
|
|
46551
|
-
});
|
|
46552
|
-
const beginFlashLoanIx = await makeBeginFlashLoanIx3(
|
|
46553
|
-
program,
|
|
46554
|
-
marginfiAccount.address,
|
|
46555
|
-
endIndex,
|
|
46556
|
-
marginfiAccount.authority,
|
|
46557
|
-
isSync
|
|
46558
|
-
);
|
|
46559
|
-
const endFlashLoanIx = await makeEndFlashLoanIx3(
|
|
46560
|
-
program,
|
|
46561
|
-
marginfiAccount.address,
|
|
46562
|
-
projectedActiveBanks,
|
|
46563
|
-
marginfiAccount.authority,
|
|
46564
|
-
isSync
|
|
46565
|
-
);
|
|
46566
|
-
const message = new web3_js.TransactionMessage({
|
|
46567
|
-
payerKey: marginfiAccount.authority,
|
|
46568
|
-
recentBlockhash: blockhash,
|
|
46569
|
-
instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
|
|
46570
|
-
}).compileToV0Message(addressLookupTableAccounts);
|
|
46571
|
-
const tx = addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
46572
|
-
addressLookupTables: addressLookupTableAccounts,
|
|
46573
|
-
type: "FLASHLOAN" /* FLASHLOAN */,
|
|
46574
|
-
signers
|
|
46984
|
+
async function makeRepayTx(params) {
|
|
46985
|
+
const { luts, ...depositIxParams } = params;
|
|
46986
|
+
const ixs = await makeRepayIx3(depositIxParams);
|
|
46987
|
+
const tx = new web3_js.Transaction().add(...ixs.instructions);
|
|
46988
|
+
tx.feePayer = params.authority;
|
|
46989
|
+
const solanaTx = addTransactionMetadata(tx, {
|
|
46990
|
+
type: "REPAY" /* REPAY */,
|
|
46991
|
+
signers: ixs.keys,
|
|
46992
|
+
addressLookupTables: luts
|
|
46575
46993
|
});
|
|
46576
|
-
|
|
46577
|
-
tx.sign(signers);
|
|
46578
|
-
}
|
|
46579
|
-
return tx;
|
|
46994
|
+
return solanaTx;
|
|
46580
46995
|
}
|
|
46581
|
-
|
|
46582
|
-
// src/services/account/actions/loop.ts
|
|
46583
|
-
async function makeLoopTx(params) {
|
|
46996
|
+
async function makeRepayWithCollatTx(params) {
|
|
46584
46997
|
const {
|
|
46585
46998
|
program,
|
|
46586
46999
|
marginfiAccount,
|
|
46587
47000
|
bankMap,
|
|
46588
|
-
|
|
46589
|
-
|
|
47001
|
+
withdrawOpts,
|
|
47002
|
+
repayOpts,
|
|
46590
47003
|
bankMetadataMap,
|
|
46591
47004
|
addressLookupTableAccounts,
|
|
46592
47005
|
connection,
|
|
46593
47006
|
oraclePrices,
|
|
46594
|
-
crossbarUrl
|
|
46595
|
-
additionalIxs = []
|
|
47007
|
+
crossbarUrl
|
|
46596
47008
|
} = params;
|
|
46597
47009
|
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
46598
47010
|
const setupIxs = await makeSetupIx({
|
|
@@ -46600,34 +47012,34 @@ async function makeLoopTx(params) {
|
|
|
46600
47012
|
authority: marginfiAccount.authority,
|
|
46601
47013
|
tokens: [
|
|
46602
47014
|
{
|
|
46603
|
-
mint:
|
|
46604
|
-
tokenProgram:
|
|
47015
|
+
mint: repayOpts.repayBank.mint,
|
|
47016
|
+
tokenProgram: repayOpts.tokenProgram
|
|
46605
47017
|
},
|
|
46606
47018
|
{
|
|
46607
|
-
mint:
|
|
46608
|
-
tokenProgram:
|
|
47019
|
+
mint: withdrawOpts.withdrawBank.mint,
|
|
47020
|
+
tokenProgram: withdrawOpts.tokenProgram
|
|
46609
47021
|
}
|
|
46610
47022
|
]
|
|
46611
47023
|
});
|
|
46612
|
-
const
|
|
46613
|
-
|
|
46614
|
-
|
|
46615
|
-
[
|
|
46616
|
-
|
|
47024
|
+
const updateJuplendMarketIxs = makeUpdateJupLendRateIxs(
|
|
47025
|
+
marginfiAccount,
|
|
47026
|
+
bankMap,
|
|
47027
|
+
[withdrawOpts.withdrawBank.address],
|
|
47028
|
+
bankMetadataMap
|
|
46617
47029
|
);
|
|
46618
47030
|
const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
|
|
46619
|
-
|
|
46620
|
-
|
|
46621
|
-
[
|
|
46622
|
-
|
|
47031
|
+
marginfiAccount,
|
|
47032
|
+
bankMap,
|
|
47033
|
+
[withdrawOpts.withdrawBank.address],
|
|
47034
|
+
bankMetadataMap
|
|
46623
47035
|
);
|
|
46624
47036
|
const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
|
|
46625
47037
|
marginfiAccount,
|
|
46626
47038
|
bankMap,
|
|
46627
|
-
[
|
|
47039
|
+
[withdrawOpts.withdrawBank.address, repayOpts.repayBank.address],
|
|
46628
47040
|
bankMetadataMap
|
|
46629
47041
|
);
|
|
46630
|
-
const { flashloanTx, setupInstructions, swapQuote,
|
|
47042
|
+
const { flashloanTx, setupInstructions, swapQuote, amountToRepay, withdrawIxs, repayIxs } = await buildRepayWithCollatFlashloanTx({
|
|
46631
47043
|
...params,
|
|
46632
47044
|
blockhash
|
|
46633
47045
|
});
|
|
@@ -46637,7 +47049,7 @@ async function makeLoopTx(params) {
|
|
|
46637
47049
|
}
|
|
46638
47050
|
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
46639
47051
|
const mintKey = ix.keys[3]?.pubkey;
|
|
46640
|
-
if (mintKey?.equals(
|
|
47052
|
+
if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(repayOpts.repayBank.mint)) {
|
|
46641
47053
|
return false;
|
|
46642
47054
|
}
|
|
46643
47055
|
}
|
|
@@ -46649,24 +47061,18 @@ async function makeLoopTx(params) {
|
|
|
46649
47061
|
bankMap,
|
|
46650
47062
|
oraclePrices,
|
|
46651
47063
|
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
46652
|
-
instructions: [...
|
|
47064
|
+
instructions: [...withdrawIxs.instructions, ...repayIxs.instructions],
|
|
46653
47065
|
program,
|
|
46654
47066
|
connection,
|
|
46655
47067
|
crossbarUrl
|
|
46656
47068
|
});
|
|
46657
47069
|
let additionalTxs = [];
|
|
46658
|
-
if (
|
|
46659
|
-
setupIxs.push(
|
|
46660
|
-
...makeWrapSolIxs(marginfiAccount.authority, new BigNumber3.BigNumber(depositOpts.inputDepositAmount))
|
|
46661
|
-
);
|
|
46662
|
-
}
|
|
46663
|
-
if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
|
|
47070
|
+
if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJuplendMarketIxs.instructions.length > 0) {
|
|
46664
47071
|
const ixs = [
|
|
46665
|
-
...additionalIxs,
|
|
46666
47072
|
...setupIxs,
|
|
46667
47073
|
...kaminoRefreshIxs.instructions,
|
|
46668
47074
|
...updateDriftMarketIxs.instructions,
|
|
46669
|
-
...
|
|
47075
|
+
...updateJuplendMarketIxs.instructions
|
|
46670
47076
|
];
|
|
46671
47077
|
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
46672
47078
|
blockhash,
|
|
@@ -46696,300 +47102,835 @@ async function makeLoopTx(params) {
|
|
|
46696
47102
|
);
|
|
46697
47103
|
}
|
|
46698
47104
|
const transactions = [...additionalTxs, flashloanTx];
|
|
46699
|
-
return {
|
|
46700
|
-
transactions,
|
|
46701
|
-
actionTxIndex: transactions.length - 1,
|
|
46702
|
-
quoteResponse: swapQuote
|
|
46703
|
-
};
|
|
47105
|
+
return { transactions, swapQuote, amountToRepay };
|
|
46704
47106
|
}
|
|
46705
|
-
async function
|
|
47107
|
+
async function buildRepayWithCollatFlashloanTx({
|
|
46706
47108
|
program,
|
|
46707
47109
|
marginfiAccount,
|
|
46708
47110
|
bankMap,
|
|
46709
|
-
|
|
46710
|
-
|
|
47111
|
+
withdrawOpts,
|
|
47112
|
+
repayOpts,
|
|
46711
47113
|
bankMetadataMap,
|
|
47114
|
+
assetShareValueMultiplierByBank,
|
|
46712
47115
|
addressLookupTableAccounts,
|
|
46713
47116
|
connection,
|
|
46714
47117
|
swapOpts,
|
|
46715
47118
|
overrideInferAccounts,
|
|
46716
47119
|
blockhash
|
|
46717
47120
|
}) {
|
|
46718
|
-
const swapResult = [];
|
|
46719
47121
|
const cuRequestIxs = [
|
|
46720
47122
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
46721
47123
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
46722
47124
|
];
|
|
46723
|
-
|
|
46724
|
-
|
|
46725
|
-
|
|
46726
|
-
|
|
46727
|
-
|
|
46728
|
-
|
|
46729
|
-
|
|
47125
|
+
let amountToRepay;
|
|
47126
|
+
let swapInstructions = [];
|
|
47127
|
+
let setupInstructions = [];
|
|
47128
|
+
let swapLookupTables = [];
|
|
47129
|
+
let swapQuote;
|
|
47130
|
+
let sizeConstraintUsed = 0;
|
|
47131
|
+
if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
|
|
47132
|
+
amountToRepay = withdrawOpts.withdrawAmount;
|
|
46730
47133
|
} else {
|
|
46731
47134
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
46732
|
-
new web3_js.PublicKey(
|
|
47135
|
+
new web3_js.PublicKey(repayOpts.repayBank.mint),
|
|
46733
47136
|
marginfiAccount.authority,
|
|
46734
47137
|
true,
|
|
46735
|
-
|
|
47138
|
+
repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
46736
47139
|
);
|
|
46737
|
-
const
|
|
46738
|
-
|
|
46739
|
-
|
|
46740
|
-
|
|
46741
|
-
|
|
46742
|
-
|
|
46743
|
-
|
|
46744
|
-
|
|
46745
|
-
|
|
46746
|
-
|
|
47140
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
47141
|
+
program,
|
|
47142
|
+
marginfiAccount,
|
|
47143
|
+
bankMap,
|
|
47144
|
+
bankMetadataMap,
|
|
47145
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
47146
|
+
primaryIx: {
|
|
47147
|
+
type: "withdraw",
|
|
47148
|
+
bank: withdrawOpts.withdrawBank,
|
|
47149
|
+
tokenProgram: withdrawOpts.tokenProgram
|
|
47150
|
+
},
|
|
47151
|
+
secondaryIx: {
|
|
47152
|
+
type: "repay",
|
|
47153
|
+
bank: repayOpts.repayBank,
|
|
47154
|
+
tokenProgram: repayOpts.tokenProgram
|
|
46747
47155
|
},
|
|
47156
|
+
overrideInferAccounts
|
|
47157
|
+
});
|
|
47158
|
+
const swapResponse = await getSwapIxsForFlashloan({
|
|
47159
|
+
inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47160
|
+
outputMint: repayOpts.repayBank.mint.toBase58(),
|
|
47161
|
+
amount: uiToNative(
|
|
47162
|
+
withdrawOpts.withdrawAmount,
|
|
47163
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47164
|
+
).toNumber(),
|
|
47165
|
+
swapMode: "ExactIn",
|
|
46748
47166
|
authority: marginfiAccount.authority,
|
|
46749
47167
|
connection,
|
|
46750
47168
|
destinationTokenAccount,
|
|
46751
|
-
|
|
47169
|
+
swapOpts,
|
|
47170
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
47171
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
46752
47172
|
});
|
|
46753
|
-
|
|
46754
|
-
|
|
46755
|
-
|
|
46756
|
-
|
|
46757
|
-
|
|
46758
|
-
|
|
46759
|
-
|
|
46760
|
-
|
|
46761
|
-
|
|
46762
|
-
|
|
46763
|
-
|
|
46764
|
-
|
|
47173
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
47174
|
+
const { quoteResponse } = swapResponse;
|
|
47175
|
+
const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
|
|
47176
|
+
const outAmountThreshold = nativeToUi(
|
|
47177
|
+
quoteResponse.otherAmountThreshold,
|
|
47178
|
+
repayOpts.repayBank.mintDecimals
|
|
47179
|
+
);
|
|
47180
|
+
amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
|
|
47181
|
+
swapInstructions = swapResponse.swapInstructions;
|
|
47182
|
+
swapLookupTables = swapResponse.addressLookupTableAddresses;
|
|
47183
|
+
swapQuote = quoteResponse;
|
|
47184
|
+
}
|
|
47185
|
+
let withdrawIxs;
|
|
47186
|
+
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
47187
|
+
case 3 /* KAMINO */: {
|
|
47188
|
+
const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47189
|
+
if (!reserve) {
|
|
47190
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47191
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
47192
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47193
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
47194
|
+
);
|
|
47195
|
+
}
|
|
47196
|
+
const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber3.BigNumber(1);
|
|
47197
|
+
const adjustedAmount = new BigNumber3.BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
|
|
47198
|
+
withdrawIxs = await makeKaminoWithdrawIx3({
|
|
47199
|
+
program,
|
|
47200
|
+
bank: withdrawOpts.withdrawBank,
|
|
47201
|
+
bankMap,
|
|
47202
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
47203
|
+
cTokenAmount: adjustedAmount,
|
|
47204
|
+
marginfiAccount,
|
|
47205
|
+
authority: marginfiAccount.authority,
|
|
47206
|
+
reserve,
|
|
47207
|
+
withdrawAll: isWholePosition(
|
|
47208
|
+
{
|
|
47209
|
+
amount: withdrawOpts.totalPositionAmount,
|
|
47210
|
+
isLending: true
|
|
47211
|
+
},
|
|
47212
|
+
withdrawOpts.withdrawAmount,
|
|
47213
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47214
|
+
),
|
|
47215
|
+
isSync: false,
|
|
47216
|
+
opts: {
|
|
47217
|
+
createAtas: false,
|
|
47218
|
+
wrapAndUnwrapSol: false,
|
|
47219
|
+
overrideInferAccounts
|
|
47220
|
+
}
|
|
46765
47221
|
});
|
|
46766
|
-
|
|
47222
|
+
break;
|
|
47223
|
+
}
|
|
47224
|
+
case 4 /* DRIFT */: {
|
|
47225
|
+
const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
|
|
47226
|
+
if (!driftState) {
|
|
47227
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
47228
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
47229
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47230
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
47231
|
+
);
|
|
47232
|
+
}
|
|
47233
|
+
withdrawIxs = await makeDriftWithdrawIx3({
|
|
47234
|
+
program,
|
|
47235
|
+
bank: withdrawOpts.withdrawBank,
|
|
47236
|
+
bankMap,
|
|
47237
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
47238
|
+
amount: withdrawOpts.withdrawAmount,
|
|
47239
|
+
marginfiAccount,
|
|
47240
|
+
authority: marginfiAccount.authority,
|
|
47241
|
+
driftSpotMarket: driftState.spotMarketState,
|
|
47242
|
+
userRewards: driftState.userRewards,
|
|
47243
|
+
withdrawAll: isWholePosition(
|
|
47244
|
+
{
|
|
47245
|
+
amount: withdrawOpts.totalPositionAmount,
|
|
47246
|
+
isLending: true
|
|
47247
|
+
},
|
|
47248
|
+
withdrawOpts.withdrawAmount,
|
|
47249
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47250
|
+
),
|
|
47251
|
+
isSync: false,
|
|
47252
|
+
opts: {
|
|
47253
|
+
createAtas: false,
|
|
47254
|
+
wrapAndUnwrapSol: false,
|
|
47255
|
+
overrideInferAccounts
|
|
47256
|
+
}
|
|
47257
|
+
});
|
|
47258
|
+
break;
|
|
47259
|
+
}
|
|
47260
|
+
case 6 /* JUPLEND */: {
|
|
47261
|
+
const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
|
|
47262
|
+
if (!jupLendState) {
|
|
47263
|
+
throw TransactionBuildingError.jupLendStateNotFound(
|
|
47264
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
47265
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47266
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
47267
|
+
);
|
|
47268
|
+
}
|
|
47269
|
+
withdrawIxs = await makeJuplendWithdrawIx2({
|
|
47270
|
+
program,
|
|
47271
|
+
bank: withdrawOpts.withdrawBank,
|
|
47272
|
+
bankMap,
|
|
47273
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
47274
|
+
amount: withdrawOpts.withdrawAmount,
|
|
47275
|
+
marginfiAccount,
|
|
47276
|
+
authority: marginfiAccount.authority,
|
|
47277
|
+
jupLendingState: jupLendState.jupLendingState,
|
|
47278
|
+
withdrawAll: isWholePosition(
|
|
47279
|
+
{
|
|
47280
|
+
amount: withdrawOpts.totalPositionAmount,
|
|
47281
|
+
isLending: true
|
|
47282
|
+
},
|
|
47283
|
+
withdrawOpts.withdrawAmount,
|
|
47284
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47285
|
+
),
|
|
47286
|
+
opts: {
|
|
47287
|
+
createAtas: false,
|
|
47288
|
+
wrapAndUnwrapSol: false,
|
|
47289
|
+
overrideInferAccounts
|
|
47290
|
+
}
|
|
47291
|
+
});
|
|
47292
|
+
break;
|
|
47293
|
+
}
|
|
47294
|
+
default: {
|
|
47295
|
+
withdrawIxs = await makeWithdrawIx3({
|
|
47296
|
+
program,
|
|
47297
|
+
bank: withdrawOpts.withdrawBank,
|
|
47298
|
+
bankMap,
|
|
47299
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
47300
|
+
amount: withdrawOpts.withdrawAmount,
|
|
47301
|
+
marginfiAccount,
|
|
47302
|
+
authority: marginfiAccount.authority,
|
|
47303
|
+
withdrawAll: isWholePosition(
|
|
47304
|
+
{
|
|
47305
|
+
amount: withdrawOpts.totalPositionAmount,
|
|
47306
|
+
isLending: true
|
|
47307
|
+
},
|
|
47308
|
+
withdrawOpts.withdrawAmount,
|
|
47309
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47310
|
+
),
|
|
47311
|
+
isSync: false,
|
|
47312
|
+
opts: {
|
|
47313
|
+
createAtas: false,
|
|
47314
|
+
wrapAndUnwrapSol: false,
|
|
47315
|
+
overrideInferAccounts
|
|
47316
|
+
}
|
|
47317
|
+
});
|
|
47318
|
+
break;
|
|
47319
|
+
}
|
|
46767
47320
|
}
|
|
46768
|
-
const
|
|
47321
|
+
const repayIxs = await makeRepayIx3({
|
|
46769
47322
|
program,
|
|
46770
|
-
bank:
|
|
46771
|
-
|
|
46772
|
-
|
|
46773
|
-
|
|
46774
|
-
marginfiAccount,
|
|
47323
|
+
bank: repayOpts.repayBank,
|
|
47324
|
+
tokenProgram: repayOpts.tokenProgram,
|
|
47325
|
+
amount: amountToRepay,
|
|
47326
|
+
accountAddress: marginfiAccount.address,
|
|
46775
47327
|
authority: marginfiAccount.authority,
|
|
47328
|
+
repayAll: isWholePosition(
|
|
47329
|
+
{
|
|
47330
|
+
amount: repayOpts.totalPositionAmount,
|
|
47331
|
+
isLending: true
|
|
47332
|
+
},
|
|
47333
|
+
amountToRepay,
|
|
47334
|
+
repayOpts.repayBank.mintDecimals
|
|
47335
|
+
),
|
|
46776
47336
|
isSync: false,
|
|
46777
47337
|
opts: {
|
|
46778
|
-
createAtas: false,
|
|
46779
47338
|
wrapAndUnwrapSol: false,
|
|
46780
47339
|
overrideInferAccounts
|
|
46781
47340
|
}
|
|
46782
47341
|
});
|
|
46783
|
-
|
|
46784
|
-
|
|
46785
|
-
|
|
46786
|
-
|
|
46787
|
-
|
|
46788
|
-
|
|
46789
|
-
|
|
46790
|
-
|
|
46791
|
-
|
|
46792
|
-
|
|
46793
|
-
|
|
46794
|
-
|
|
46795
|
-
|
|
46796
|
-
|
|
46797
|
-
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
46804
|
-
|
|
46805
|
-
|
|
46806
|
-
|
|
46807
|
-
|
|
46808
|
-
|
|
46809
|
-
|
|
46810
|
-
|
|
46811
|
-
|
|
46812
|
-
|
|
46813
|
-
|
|
46814
|
-
|
|
46815
|
-
|
|
46816
|
-
|
|
46817
|
-
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
|
|
46822
|
-
|
|
46823
|
-
|
|
46824
|
-
|
|
46825
|
-
|
|
46826
|
-
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
|
|
46830
|
-
|
|
46831
|
-
|
|
46832
|
-
|
|
46833
|
-
|
|
46834
|
-
|
|
46835
|
-
|
|
46836
|
-
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46841
|
-
|
|
46842
|
-
|
|
46843
|
-
|
|
46844
|
-
|
|
46845
|
-
|
|
46846
|
-
|
|
46847
|
-
|
|
46848
|
-
|
|
46849
|
-
|
|
46850
|
-
|
|
46851
|
-
|
|
46852
|
-
|
|
46853
|
-
authority: marginfiAccount.authority,
|
|
46854
|
-
group: marginfiAccount.group,
|
|
46855
|
-
opts: {
|
|
46856
|
-
wrapAndUnwrapSol: false,
|
|
46857
|
-
overrideInferAccounts
|
|
46858
|
-
}
|
|
46859
|
-
});
|
|
46860
|
-
break;
|
|
47342
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
47343
|
+
const allNonFlIxs = [
|
|
47344
|
+
...cuRequestIxs,
|
|
47345
|
+
...withdrawIxs.instructions,
|
|
47346
|
+
...swapInstructions,
|
|
47347
|
+
...repayIxs.instructions
|
|
47348
|
+
];
|
|
47349
|
+
if (swapInstructions.length > 0) {
|
|
47350
|
+
compileFlashloanPrecheck({
|
|
47351
|
+
allIxs: allNonFlIxs,
|
|
47352
|
+
payer: marginfiAccount.authority,
|
|
47353
|
+
luts,
|
|
47354
|
+
sizeConstraint: sizeConstraintUsed,
|
|
47355
|
+
swapIxCount: swapInstructions.length,
|
|
47356
|
+
swapLutCount: swapLookupTables.length
|
|
47357
|
+
});
|
|
47358
|
+
}
|
|
47359
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
47360
|
+
program,
|
|
47361
|
+
marginfiAccount,
|
|
47362
|
+
bankMap,
|
|
47363
|
+
addressLookupTableAccounts: luts,
|
|
47364
|
+
blockhash,
|
|
47365
|
+
ixs: allNonFlIxs,
|
|
47366
|
+
isSync: true
|
|
47367
|
+
});
|
|
47368
|
+
const txSize = getTxSize(flashloanTx);
|
|
47369
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
47370
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
47371
|
+
throw TransactionBuildingError.swapSizeExceededRepay(
|
|
47372
|
+
txSize,
|
|
47373
|
+
totalKeys,
|
|
47374
|
+
swapOpts.swapConfig?.provider
|
|
47375
|
+
);
|
|
47376
|
+
}
|
|
47377
|
+
return {
|
|
47378
|
+
flashloanTx,
|
|
47379
|
+
setupInstructions,
|
|
47380
|
+
swapQuote,
|
|
47381
|
+
withdrawIxs,
|
|
47382
|
+
repayIxs,
|
|
47383
|
+
amountToRepay
|
|
47384
|
+
};
|
|
47385
|
+
}
|
|
47386
|
+
|
|
47387
|
+
// src/services/account/utils/flashloan-size.utils.ts
|
|
47388
|
+
var SWAP_MERGE_OVERHEAD = 150;
|
|
47389
|
+
var FL_IX_OVERHEAD = 52;
|
|
47390
|
+
function compactU16Size(n) {
|
|
47391
|
+
return n < 128 ? 1 : n < 16384 ? 2 : 3;
|
|
47392
|
+
}
|
|
47393
|
+
function computeV0TxSize(ixs, payerKey, luts) {
|
|
47394
|
+
const keyMap = /* @__PURE__ */ new Map();
|
|
47395
|
+
const payerStr = payerKey.toBase58();
|
|
47396
|
+
keyMap.set(payerStr, { isSigner: true, isWritable: true });
|
|
47397
|
+
const programIds = /* @__PURE__ */ new Set();
|
|
47398
|
+
for (const ix of ixs) {
|
|
47399
|
+
const progStr = ix.programId.toBase58();
|
|
47400
|
+
programIds.add(progStr);
|
|
47401
|
+
if (!keyMap.has(progStr)) {
|
|
47402
|
+
keyMap.set(progStr, { isSigner: false, isWritable: false });
|
|
47403
|
+
}
|
|
47404
|
+
for (const meta of ix.keys) {
|
|
47405
|
+
const keyStr = meta.pubkey.toBase58();
|
|
47406
|
+
const existing = keyMap.get(keyStr);
|
|
47407
|
+
if (existing) {
|
|
47408
|
+
existing.isSigner = existing.isSigner || meta.isSigner;
|
|
47409
|
+
existing.isWritable = existing.isWritable || meta.isWritable;
|
|
47410
|
+
} else {
|
|
47411
|
+
keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
|
|
46861
47412
|
}
|
|
46862
|
-
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
opts: {
|
|
46872
|
-
wrapAndUnwrapSol: false,
|
|
46873
|
-
overrideInferAccounts
|
|
46874
|
-
}
|
|
46875
|
-
});
|
|
46876
|
-
break;
|
|
47413
|
+
}
|
|
47414
|
+
}
|
|
47415
|
+
const lutLookup = /* @__PURE__ */ new Map();
|
|
47416
|
+
for (let li = 0; li < luts.length; li++) {
|
|
47417
|
+
const addresses = luts[li].state.addresses;
|
|
47418
|
+
for (let ai = 0; ai < addresses.length; ai++) {
|
|
47419
|
+
const addrStr = addresses[ai].toBase58();
|
|
47420
|
+
if (!lutLookup.has(addrStr)) {
|
|
47421
|
+
lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
|
|
46877
47422
|
}
|
|
46878
47423
|
}
|
|
46879
|
-
|
|
46880
|
-
|
|
46881
|
-
|
|
46882
|
-
|
|
46883
|
-
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
]
|
|
46895
|
-
});
|
|
46896
|
-
const txSize = getTxSize(flashloanTx);
|
|
46897
|
-
const keySize = getAccountKeys(flashloanTx, luts);
|
|
46898
|
-
const isLast = index === swapResult.length - 1;
|
|
46899
|
-
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
46900
|
-
if (isLast) {
|
|
46901
|
-
throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
|
|
47424
|
+
}
|
|
47425
|
+
let numStaticKeys = 0;
|
|
47426
|
+
let numWritableStaticKeys = 0;
|
|
47427
|
+
const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
|
|
47428
|
+
const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
|
|
47429
|
+
for (const [keyStr, props] of keyMap) {
|
|
47430
|
+
if (props.isSigner || programIds.has(keyStr)) {
|
|
47431
|
+
numStaticKeys++;
|
|
47432
|
+
if (props.isWritable) numWritableStaticKeys++;
|
|
47433
|
+
continue;
|
|
47434
|
+
}
|
|
47435
|
+
const lutEntry = lutLookup.get(keyStr);
|
|
47436
|
+
if (lutEntry) {
|
|
47437
|
+
if (props.isWritable) {
|
|
47438
|
+
lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
|
|
46902
47439
|
} else {
|
|
46903
|
-
|
|
47440
|
+
lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
|
|
46904
47441
|
}
|
|
46905
47442
|
} else {
|
|
46906
|
-
|
|
46907
|
-
|
|
46908
|
-
setupInstructions,
|
|
46909
|
-
swapQuote: quoteResponse,
|
|
46910
|
-
borrowIxs,
|
|
46911
|
-
depositIxs,
|
|
46912
|
-
amountToDeposit
|
|
46913
|
-
};
|
|
47443
|
+
numStaticKeys++;
|
|
47444
|
+
if (props.isWritable) numWritableStaticKeys++;
|
|
46914
47445
|
}
|
|
46915
47446
|
}
|
|
46916
|
-
|
|
46917
|
-
|
|
46918
|
-
|
|
47447
|
+
const fixedOverhead = 101;
|
|
47448
|
+
const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
|
|
47449
|
+
let ixSection = compactU16Size(ixs.length);
|
|
47450
|
+
for (const ix of ixs) {
|
|
47451
|
+
const numAccounts = ix.keys.length;
|
|
47452
|
+
ixSection += 1 + // programId index
|
|
47453
|
+
compactU16Size(numAccounts) + numAccounts + // account key indexes
|
|
47454
|
+
compactU16Size(ix.data.length) + ix.data.length;
|
|
47455
|
+
}
|
|
47456
|
+
let numUsedLuts = 0;
|
|
47457
|
+
let lutSection = 0;
|
|
47458
|
+
for (let li = 0; li < luts.length; li++) {
|
|
47459
|
+
const wCount = lutWritableIdxs[li].size;
|
|
47460
|
+
const rCount = lutReadonlyIdxs[li].size;
|
|
47461
|
+
if (wCount === 0 && rCount === 0) continue;
|
|
47462
|
+
numUsedLuts++;
|
|
47463
|
+
lutSection += 32 + // LUT address
|
|
47464
|
+
compactU16Size(wCount) + wCount + // writable indexes
|
|
47465
|
+
compactU16Size(rCount) + rCount;
|
|
47466
|
+
}
|
|
47467
|
+
lutSection += compactU16Size(numUsedLuts);
|
|
47468
|
+
let totalLutKeys = 0;
|
|
47469
|
+
for (let li = 0; li < luts.length; li++) {
|
|
47470
|
+
totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
|
|
47471
|
+
}
|
|
47472
|
+
const accountCount = numStaticKeys + totalLutKeys;
|
|
47473
|
+
let totalLutWritableKeys = 0;
|
|
47474
|
+
for (let li = 0; li < luts.length; li++) {
|
|
47475
|
+
totalLutWritableKeys += lutWritableIdxs[li].size;
|
|
47476
|
+
}
|
|
47477
|
+
const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
|
|
47478
|
+
const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
|
|
47479
|
+
return { size, accountCount, writableAccountCount };
|
|
47480
|
+
}
|
|
47481
|
+
function computeFlashLoanNonSwapBudget({
|
|
46919
47482
|
program,
|
|
46920
|
-
|
|
46921
|
-
|
|
46922
|
-
|
|
46923
|
-
|
|
46924
|
-
accountAddress,
|
|
46925
|
-
repayAll = false,
|
|
46926
|
-
isSync = false,
|
|
46927
|
-
opts = {}
|
|
47483
|
+
marginfiAccount,
|
|
47484
|
+
ixs,
|
|
47485
|
+
bankMap,
|
|
47486
|
+
addressLookupTableAccounts
|
|
46928
47487
|
}) {
|
|
46929
|
-
const
|
|
46930
|
-
|
|
46931
|
-
|
|
46932
|
-
|
|
46933
|
-
|
|
46934
|
-
|
|
46935
|
-
|
|
47488
|
+
const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
|
|
47489
|
+
marginfiAccount.balances,
|
|
47490
|
+
ixs,
|
|
47491
|
+
program
|
|
47492
|
+
);
|
|
47493
|
+
const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
|
|
47494
|
+
const b = bankMap.get(key.toBase58());
|
|
47495
|
+
if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
|
|
47496
|
+
return b;
|
|
47497
|
+
});
|
|
47498
|
+
const endIndex = ixs.length + 1;
|
|
47499
|
+
const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
|
|
47500
|
+
program.programId,
|
|
47501
|
+
{ marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
|
|
47502
|
+
{ endIndex: new BN11__default.default(endIndex) }
|
|
47503
|
+
);
|
|
47504
|
+
const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
|
|
47505
|
+
const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
|
|
47506
|
+
program.programId,
|
|
47507
|
+
{ marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
|
|
47508
|
+
endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
|
|
47509
|
+
);
|
|
47510
|
+
const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
|
|
47511
|
+
const nonSwapMsg = new web3_js.TransactionMessage({
|
|
47512
|
+
payerKey: marginfiAccount.authority,
|
|
47513
|
+
recentBlockhash: web3_js.PublicKey.default.toBase58(),
|
|
47514
|
+
instructions: allNonSwapIxs
|
|
47515
|
+
}).compileToV0Message(addressLookupTableAccounts);
|
|
47516
|
+
const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
|
|
47517
|
+
const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
|
|
47518
|
+
const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
|
|
47519
|
+
(s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
|
|
47520
|
+
0
|
|
47521
|
+
);
|
|
47522
|
+
const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
|
|
47523
|
+
const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
|
|
47524
|
+
console.log("[flashloan-budget]", {
|
|
47525
|
+
method: "compiled",
|
|
47526
|
+
nonSwapSize,
|
|
47527
|
+
nonSwapTotal,
|
|
47528
|
+
sizeConstraint,
|
|
47529
|
+
maxSwapTotalAccounts
|
|
47530
|
+
});
|
|
47531
|
+
return { sizeConstraint, maxSwapTotalAccounts };
|
|
47532
|
+
}
|
|
47533
|
+
function compileFlashloanPrecheck({
|
|
47534
|
+
allIxs,
|
|
47535
|
+
payer,
|
|
47536
|
+
luts,
|
|
47537
|
+
sizeConstraint,
|
|
47538
|
+
swapIxCount,
|
|
47539
|
+
swapLutCount
|
|
47540
|
+
}) {
|
|
47541
|
+
const msg = new web3_js.TransactionMessage({
|
|
47542
|
+
payerKey: payer,
|
|
47543
|
+
recentBlockhash: web3_js.PublicKey.default.toBase58(),
|
|
47544
|
+
instructions: allIxs
|
|
47545
|
+
}).compileToV0Message(luts);
|
|
47546
|
+
const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
|
|
47547
|
+
const fullTxSize = rawSize + FL_IX_OVERHEAD;
|
|
47548
|
+
const overshoot = fullTxSize - MAX_TX_SIZE;
|
|
47549
|
+
const { header, staticAccountKeys, addressTableLookups } = msg;
|
|
47550
|
+
const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
|
|
47551
|
+
const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
47552
|
+
const writableAccounts = writableStatic + writableLut;
|
|
47553
|
+
const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
|
|
47554
|
+
(s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
|
|
47555
|
+
0
|
|
47556
|
+
);
|
|
47557
|
+
console.log("[flashloan-precheck]", {
|
|
47558
|
+
fullTxSize,
|
|
47559
|
+
overshoot,
|
|
47560
|
+
sizeConstraint,
|
|
47561
|
+
writableAccounts,
|
|
47562
|
+
totalAccounts,
|
|
47563
|
+
staticKeys: staticAccountKeys.length,
|
|
47564
|
+
numLuts: addressTableLookups.length,
|
|
47565
|
+
swapIxCount,
|
|
47566
|
+
swapLutCount
|
|
47567
|
+
});
|
|
47568
|
+
return { fullTxSize, overshoot, writableAccounts, totalAccounts };
|
|
47569
|
+
}
|
|
47570
|
+
async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
|
|
47571
|
+
const { bank, tokenProgram } = config;
|
|
47572
|
+
switch (config.type) {
|
|
47573
|
+
case "borrow":
|
|
47574
|
+
return makeBorrowIx3({
|
|
47575
|
+
program,
|
|
47576
|
+
bank,
|
|
47577
|
+
bankMap,
|
|
47578
|
+
tokenProgram,
|
|
47579
|
+
amount: 1,
|
|
47580
|
+
marginfiAccount,
|
|
47581
|
+
authority: marginfiAccount.authority,
|
|
47582
|
+
isSync: true,
|
|
47583
|
+
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
47584
|
+
});
|
|
47585
|
+
case "repay":
|
|
47586
|
+
return makeRepayIx3({
|
|
47587
|
+
program,
|
|
47588
|
+
bank,
|
|
47589
|
+
tokenProgram,
|
|
47590
|
+
amount: 1,
|
|
47591
|
+
accountAddress: marginfiAccount.address,
|
|
47592
|
+
authority: marginfiAccount.authority,
|
|
47593
|
+
repayAll: false,
|
|
47594
|
+
isSync: true,
|
|
47595
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
47596
|
+
});
|
|
47597
|
+
case "deposit":
|
|
47598
|
+
return buildDepositBudgetIx(
|
|
47599
|
+
config,
|
|
47600
|
+
program,
|
|
47601
|
+
marginfiAccount,
|
|
47602
|
+
bankMetadataMap,
|
|
47603
|
+
overrideInferAccounts
|
|
47604
|
+
);
|
|
47605
|
+
case "withdraw":
|
|
47606
|
+
return buildWithdrawBudgetIx(
|
|
47607
|
+
config,
|
|
47608
|
+
program,
|
|
47609
|
+
marginfiAccount,
|
|
47610
|
+
bankMap,
|
|
47611
|
+
bankMetadataMap,
|
|
47612
|
+
overrideInferAccounts
|
|
47613
|
+
);
|
|
46936
47614
|
}
|
|
46937
|
-
|
|
47615
|
+
}
|
|
47616
|
+
async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
|
|
47617
|
+
const { bank, tokenProgram } = config;
|
|
47618
|
+
const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
|
|
47619
|
+
switch (bank.config.assetTag) {
|
|
47620
|
+
case 3 /* KAMINO */: {
|
|
47621
|
+
const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47622
|
+
if (!reserve) {
|
|
47623
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47624
|
+
bank.address.toBase58(),
|
|
47625
|
+
bank.mint.toBase58(),
|
|
47626
|
+
bank.tokenSymbol
|
|
47627
|
+
);
|
|
47628
|
+
}
|
|
47629
|
+
return makeKaminoDepositIx3({
|
|
47630
|
+
program,
|
|
47631
|
+
bank,
|
|
47632
|
+
tokenProgram,
|
|
47633
|
+
amount: 1,
|
|
47634
|
+
accountAddress: marginfiAccount.address,
|
|
47635
|
+
authority: marginfiAccount.authority,
|
|
47636
|
+
group: marginfiAccount.group,
|
|
47637
|
+
reserve,
|
|
47638
|
+
isSync: true,
|
|
47639
|
+
opts
|
|
47640
|
+
});
|
|
47641
|
+
}
|
|
47642
|
+
case 4 /* DRIFT */: {
|
|
47643
|
+
const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
|
|
47644
|
+
if (!driftState) {
|
|
47645
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
47646
|
+
bank.address.toBase58(),
|
|
47647
|
+
bank.mint.toBase58(),
|
|
47648
|
+
bank.tokenSymbol
|
|
47649
|
+
);
|
|
47650
|
+
}
|
|
47651
|
+
return makeDriftDepositIx3({
|
|
47652
|
+
program,
|
|
47653
|
+
bank,
|
|
47654
|
+
tokenProgram,
|
|
47655
|
+
amount: 1,
|
|
47656
|
+
accountAddress: marginfiAccount.address,
|
|
47657
|
+
authority: marginfiAccount.authority,
|
|
47658
|
+
group: marginfiAccount.group,
|
|
47659
|
+
driftMarketIndex: driftState.spotMarketState.marketIndex,
|
|
47660
|
+
driftOracle: driftState.spotMarketState.oracle,
|
|
47661
|
+
isSync: true,
|
|
47662
|
+
opts
|
|
47663
|
+
});
|
|
47664
|
+
}
|
|
47665
|
+
case 6 /* JUPLEND */: {
|
|
47666
|
+
return makeJuplendDepositIx2({
|
|
47667
|
+
program,
|
|
47668
|
+
bank,
|
|
47669
|
+
tokenProgram,
|
|
47670
|
+
amount: 1,
|
|
47671
|
+
accountAddress: marginfiAccount.address,
|
|
47672
|
+
authority: marginfiAccount.authority,
|
|
47673
|
+
group: marginfiAccount.group,
|
|
47674
|
+
isSync: true,
|
|
47675
|
+
opts
|
|
47676
|
+
});
|
|
47677
|
+
}
|
|
47678
|
+
default: {
|
|
47679
|
+
return makeDepositIx3({
|
|
47680
|
+
program,
|
|
47681
|
+
bank,
|
|
47682
|
+
tokenProgram,
|
|
47683
|
+
amount: 1,
|
|
47684
|
+
accountAddress: marginfiAccount.address,
|
|
47685
|
+
authority: marginfiAccount.authority,
|
|
47686
|
+
group: marginfiAccount.group,
|
|
47687
|
+
isSync: true,
|
|
47688
|
+
opts
|
|
47689
|
+
});
|
|
47690
|
+
}
|
|
47691
|
+
}
|
|
47692
|
+
}
|
|
47693
|
+
async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
|
|
47694
|
+
const { bank, tokenProgram } = config;
|
|
47695
|
+
const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
|
|
47696
|
+
switch (bank.config.assetTag) {
|
|
47697
|
+
case 3 /* KAMINO */: {
|
|
47698
|
+
const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47699
|
+
if (!reserve) {
|
|
47700
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47701
|
+
bank.address.toBase58(),
|
|
47702
|
+
bank.mint.toBase58(),
|
|
47703
|
+
bank.tokenSymbol
|
|
47704
|
+
);
|
|
47705
|
+
}
|
|
47706
|
+
return makeKaminoWithdrawIx3({
|
|
47707
|
+
program,
|
|
47708
|
+
bank,
|
|
47709
|
+
bankMap,
|
|
47710
|
+
tokenProgram,
|
|
47711
|
+
cTokenAmount: 1,
|
|
47712
|
+
marginfiAccount,
|
|
47713
|
+
authority: marginfiAccount.authority,
|
|
47714
|
+
reserve,
|
|
47715
|
+
withdrawAll: false,
|
|
47716
|
+
isSync: true,
|
|
47717
|
+
opts
|
|
47718
|
+
});
|
|
47719
|
+
}
|
|
47720
|
+
case 4 /* DRIFT */: {
|
|
47721
|
+
const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
|
|
47722
|
+
if (!driftState) {
|
|
47723
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
47724
|
+
bank.address.toBase58(),
|
|
47725
|
+
bank.mint.toBase58(),
|
|
47726
|
+
bank.tokenSymbol
|
|
47727
|
+
);
|
|
47728
|
+
}
|
|
47729
|
+
return makeDriftWithdrawIx3({
|
|
47730
|
+
program,
|
|
47731
|
+
bank,
|
|
47732
|
+
bankMap,
|
|
47733
|
+
tokenProgram,
|
|
47734
|
+
amount: 1,
|
|
47735
|
+
marginfiAccount,
|
|
47736
|
+
authority: marginfiAccount.authority,
|
|
47737
|
+
driftSpotMarket: driftState.spotMarketState,
|
|
47738
|
+
userRewards: driftState.userRewards,
|
|
47739
|
+
withdrawAll: false,
|
|
47740
|
+
isSync: true,
|
|
47741
|
+
opts
|
|
47742
|
+
});
|
|
47743
|
+
}
|
|
47744
|
+
case 6 /* JUPLEND */: {
|
|
47745
|
+
const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
|
|
47746
|
+
if (!jupLendState) {
|
|
47747
|
+
throw TransactionBuildingError.jupLendStateNotFound(
|
|
47748
|
+
bank.address.toBase58(),
|
|
47749
|
+
bank.mint.toBase58(),
|
|
47750
|
+
bank.tokenSymbol
|
|
47751
|
+
);
|
|
47752
|
+
}
|
|
47753
|
+
return makeJuplendWithdrawIx2({
|
|
47754
|
+
program,
|
|
47755
|
+
bank,
|
|
47756
|
+
bankMap,
|
|
47757
|
+
tokenProgram,
|
|
47758
|
+
amount: 1,
|
|
47759
|
+
marginfiAccount,
|
|
47760
|
+
authority: marginfiAccount.authority,
|
|
47761
|
+
jupLendingState: jupLendState.jupLendingState,
|
|
47762
|
+
withdrawAll: false,
|
|
47763
|
+
opts
|
|
47764
|
+
});
|
|
47765
|
+
}
|
|
47766
|
+
default: {
|
|
47767
|
+
return makeWithdrawIx3({
|
|
47768
|
+
program,
|
|
47769
|
+
bank,
|
|
47770
|
+
bankMap,
|
|
47771
|
+
tokenProgram,
|
|
47772
|
+
amount: 1,
|
|
47773
|
+
marginfiAccount,
|
|
47774
|
+
authority: marginfiAccount.authority,
|
|
47775
|
+
withdrawAll: false,
|
|
47776
|
+
isSync: true,
|
|
47777
|
+
opts
|
|
47778
|
+
});
|
|
47779
|
+
}
|
|
47780
|
+
}
|
|
47781
|
+
}
|
|
47782
|
+
async function computeFlashloanSwapConstraints({
|
|
47783
|
+
program,
|
|
47784
|
+
marginfiAccount,
|
|
47785
|
+
bankMap,
|
|
47786
|
+
addressLookupTableAccounts,
|
|
47787
|
+
bankMetadataMap,
|
|
47788
|
+
primaryIx,
|
|
47789
|
+
secondaryIx,
|
|
47790
|
+
overrideInferAccounts
|
|
47791
|
+
}) {
|
|
47792
|
+
const cuRequestIxs = [
|
|
47793
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47794
|
+
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
47795
|
+
];
|
|
47796
|
+
const [primaryResult, secondaryResult] = await Promise.all([
|
|
47797
|
+
buildBudgetIx(
|
|
47798
|
+
primaryIx,
|
|
47799
|
+
program,
|
|
47800
|
+
marginfiAccount,
|
|
47801
|
+
bankMap,
|
|
47802
|
+
bankMetadataMap,
|
|
47803
|
+
overrideInferAccounts
|
|
47804
|
+
),
|
|
47805
|
+
buildBudgetIx(
|
|
47806
|
+
secondaryIx,
|
|
47807
|
+
program,
|
|
47808
|
+
marginfiAccount,
|
|
47809
|
+
bankMap,
|
|
47810
|
+
bankMetadataMap,
|
|
47811
|
+
overrideInferAccounts
|
|
47812
|
+
)
|
|
47813
|
+
]);
|
|
47814
|
+
return computeFlashLoanNonSwapBudget({
|
|
46938
47815
|
program,
|
|
47816
|
+
marginfiAccount,
|
|
47817
|
+
bankMap,
|
|
47818
|
+
addressLookupTableAccounts,
|
|
47819
|
+
ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
|
|
47820
|
+
});
|
|
47821
|
+
}
|
|
47822
|
+
|
|
47823
|
+
// src/services/account/actions/flash-loan.ts
|
|
47824
|
+
async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
|
|
47825
|
+
const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
|
|
47826
|
+
program.programId,
|
|
46939
47827
|
{
|
|
46940
|
-
marginfiAccount:
|
|
46941
|
-
|
|
46942
|
-
bank: bank.address,
|
|
46943
|
-
tokenProgram,
|
|
46944
|
-
authority: opts.overrideInferAccounts?.authority ?? authority,
|
|
46945
|
-
group: opts.overrideInferAccounts?.group,
|
|
46946
|
-
liquidityVault: opts.overrideInferAccounts?.liquidityVault
|
|
47828
|
+
marginfiAccount: marginfiAccountPk,
|
|
47829
|
+
authority
|
|
46947
47830
|
},
|
|
46948
|
-
{
|
|
46949
|
-
|
|
46950
|
-
|
|
47831
|
+
{ endIndex: new BN11__default.default(endIndex) }
|
|
47832
|
+
) : await instructions_default.makeBeginFlashLoanIx(
|
|
47833
|
+
program,
|
|
47834
|
+
{
|
|
47835
|
+
marginfiAccount: marginfiAccountPk,
|
|
47836
|
+
authority
|
|
47837
|
+
},
|
|
47838
|
+
{ endIndex: new BN11__default.default(endIndex) }
|
|
47839
|
+
);
|
|
47840
|
+
return { instructions: [ix], keys: [] };
|
|
47841
|
+
}
|
|
47842
|
+
async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
|
|
47843
|
+
const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
|
|
47844
|
+
const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
|
|
46951
47845
|
program.programId,
|
|
46952
47846
|
{
|
|
46953
|
-
marginfiAccount:
|
|
46954
|
-
|
|
46955
|
-
bank: bank.address,
|
|
46956
|
-
tokenProgram,
|
|
46957
|
-
authority: opts.overrideInferAccounts?.authority ?? authority,
|
|
46958
|
-
group: opts.overrideInferAccounts?.group
|
|
47847
|
+
marginfiAccount: marginfiAccountPk,
|
|
47848
|
+
authority
|
|
46959
47849
|
},
|
|
46960
|
-
|
|
46961
|
-
|
|
47850
|
+
remainingAccounts.map((account) => ({
|
|
47851
|
+
pubkey: account,
|
|
47852
|
+
isSigner: false,
|
|
47853
|
+
isWritable: false
|
|
47854
|
+
}))
|
|
47855
|
+
) : await instructions_default.makeEndFlashLoanIx(
|
|
47856
|
+
program,
|
|
47857
|
+
{
|
|
47858
|
+
marginfiAccount: marginfiAccountPk,
|
|
47859
|
+
authority
|
|
47860
|
+
},
|
|
47861
|
+
remainingAccounts.map((account) => ({
|
|
47862
|
+
pubkey: account,
|
|
47863
|
+
isSigner: false,
|
|
47864
|
+
isWritable: false
|
|
47865
|
+
}))
|
|
46962
47866
|
);
|
|
46963
|
-
|
|
46964
|
-
return {
|
|
46965
|
-
instructions: repayIxs,
|
|
46966
|
-
keys: []
|
|
46967
|
-
};
|
|
47867
|
+
return { instructions: [ix], keys: [] };
|
|
46968
47868
|
}
|
|
46969
|
-
async function
|
|
46970
|
-
|
|
46971
|
-
|
|
46972
|
-
|
|
46973
|
-
|
|
46974
|
-
|
|
46975
|
-
|
|
46976
|
-
|
|
46977
|
-
|
|
47869
|
+
async function makeFlashLoanTx({
|
|
47870
|
+
program,
|
|
47871
|
+
marginfiAccount,
|
|
47872
|
+
ixs,
|
|
47873
|
+
bankMap,
|
|
47874
|
+
blockhash,
|
|
47875
|
+
addressLookupTableAccounts,
|
|
47876
|
+
signers,
|
|
47877
|
+
isSync
|
|
47878
|
+
}) {
|
|
47879
|
+
const endIndex = ixs.length + 1;
|
|
47880
|
+
const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
|
|
47881
|
+
marginfiAccount.balances,
|
|
47882
|
+
ixs,
|
|
47883
|
+
program
|
|
47884
|
+
);
|
|
47885
|
+
const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
|
|
47886
|
+
const b = bankMap.get(account.toBase58());
|
|
47887
|
+
if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
|
|
47888
|
+
return b;
|
|
46978
47889
|
});
|
|
46979
|
-
|
|
47890
|
+
const beginFlashLoanIx = await makeBeginFlashLoanIx3(
|
|
47891
|
+
program,
|
|
47892
|
+
marginfiAccount.address,
|
|
47893
|
+
endIndex,
|
|
47894
|
+
marginfiAccount.authority,
|
|
47895
|
+
isSync
|
|
47896
|
+
);
|
|
47897
|
+
const endFlashLoanIx = await makeEndFlashLoanIx3(
|
|
47898
|
+
program,
|
|
47899
|
+
marginfiAccount.address,
|
|
47900
|
+
projectedActiveBanks,
|
|
47901
|
+
marginfiAccount.authority,
|
|
47902
|
+
isSync
|
|
47903
|
+
);
|
|
47904
|
+
const message = new web3_js.TransactionMessage({
|
|
47905
|
+
payerKey: marginfiAccount.authority,
|
|
47906
|
+
recentBlockhash: blockhash,
|
|
47907
|
+
instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
|
|
47908
|
+
}).compileToV0Message(addressLookupTableAccounts);
|
|
47909
|
+
const tx = addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
47910
|
+
addressLookupTables: addressLookupTableAccounts,
|
|
47911
|
+
type: "FLASHLOAN" /* FLASHLOAN */,
|
|
47912
|
+
signers
|
|
47913
|
+
});
|
|
47914
|
+
if (signers) {
|
|
47915
|
+
tx.sign(signers);
|
|
47916
|
+
}
|
|
47917
|
+
return tx;
|
|
46980
47918
|
}
|
|
46981
|
-
|
|
47919
|
+
|
|
47920
|
+
// src/services/account/actions/loop.ts
|
|
47921
|
+
async function makeLoopTx(params) {
|
|
46982
47922
|
const {
|
|
46983
47923
|
program,
|
|
46984
47924
|
marginfiAccount,
|
|
46985
47925
|
bankMap,
|
|
46986
|
-
|
|
46987
|
-
|
|
47926
|
+
depositOpts,
|
|
47927
|
+
borrowOpts,
|
|
46988
47928
|
bankMetadataMap,
|
|
46989
47929
|
addressLookupTableAccounts,
|
|
46990
47930
|
connection,
|
|
46991
47931
|
oraclePrices,
|
|
46992
|
-
crossbarUrl
|
|
47932
|
+
crossbarUrl,
|
|
47933
|
+
additionalIxs = []
|
|
46993
47934
|
} = params;
|
|
46994
47935
|
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
46995
47936
|
const setupIxs = await makeSetupIx({
|
|
@@ -46997,34 +47938,34 @@ async function makeRepayWithCollatTx(params) {
|
|
|
46997
47938
|
authority: marginfiAccount.authority,
|
|
46998
47939
|
tokens: [
|
|
46999
47940
|
{
|
|
47000
|
-
mint:
|
|
47001
|
-
tokenProgram:
|
|
47941
|
+
mint: borrowOpts.borrowBank.mint,
|
|
47942
|
+
tokenProgram: borrowOpts.tokenProgram
|
|
47002
47943
|
},
|
|
47003
47944
|
{
|
|
47004
|
-
mint:
|
|
47005
|
-
tokenProgram:
|
|
47945
|
+
mint: depositOpts.depositBank.mint,
|
|
47946
|
+
tokenProgram: depositOpts.tokenProgram
|
|
47006
47947
|
}
|
|
47007
47948
|
]
|
|
47008
47949
|
});
|
|
47009
|
-
const
|
|
47010
|
-
marginfiAccount,
|
|
47011
|
-
bankMap,
|
|
47012
|
-
[
|
|
47013
|
-
bankMetadataMap
|
|
47950
|
+
const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
|
|
47951
|
+
params.marginfiAccount,
|
|
47952
|
+
params.bankMap,
|
|
47953
|
+
[depositOpts.depositBank.address],
|
|
47954
|
+
params.bankMetadataMap
|
|
47014
47955
|
);
|
|
47015
47956
|
const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
|
|
47016
|
-
marginfiAccount,
|
|
47017
|
-
bankMap,
|
|
47018
|
-
[
|
|
47019
|
-
bankMetadataMap
|
|
47957
|
+
params.marginfiAccount,
|
|
47958
|
+
params.bankMap,
|
|
47959
|
+
[depositOpts.depositBank.address],
|
|
47960
|
+
params.bankMetadataMap
|
|
47020
47961
|
);
|
|
47021
47962
|
const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
|
|
47022
47963
|
marginfiAccount,
|
|
47023
47964
|
bankMap,
|
|
47024
|
-
[
|
|
47965
|
+
[borrowOpts.borrowBank.address, depositOpts.depositBank.address],
|
|
47025
47966
|
bankMetadataMap
|
|
47026
47967
|
);
|
|
47027
|
-
const { flashloanTx, setupInstructions, swapQuote,
|
|
47968
|
+
const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
|
|
47028
47969
|
...params,
|
|
47029
47970
|
blockhash
|
|
47030
47971
|
});
|
|
@@ -47034,7 +47975,7 @@ async function makeRepayWithCollatTx(params) {
|
|
|
47034
47975
|
}
|
|
47035
47976
|
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
47036
47977
|
const mintKey = ix.keys[3]?.pubkey;
|
|
47037
|
-
if (mintKey?.equals(
|
|
47978
|
+
if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
47038
47979
|
return false;
|
|
47039
47980
|
}
|
|
47040
47981
|
}
|
|
@@ -47046,18 +47987,24 @@ async function makeRepayWithCollatTx(params) {
|
|
|
47046
47987
|
bankMap,
|
|
47047
47988
|
oraclePrices,
|
|
47048
47989
|
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
47049
|
-
instructions: [...
|
|
47990
|
+
instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
|
|
47050
47991
|
program,
|
|
47051
47992
|
connection,
|
|
47052
47993
|
crossbarUrl
|
|
47053
47994
|
});
|
|
47054
47995
|
let additionalTxs = [];
|
|
47055
|
-
if (
|
|
47996
|
+
if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
|
|
47997
|
+
setupIxs.push(
|
|
47998
|
+
...makeWrapSolIxs(marginfiAccount.authority, new BigNumber3.BigNumber(depositOpts.inputDepositAmount))
|
|
47999
|
+
);
|
|
48000
|
+
}
|
|
48001
|
+
if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
|
|
47056
48002
|
const ixs = [
|
|
48003
|
+
...additionalIxs,
|
|
47057
48004
|
...setupIxs,
|
|
47058
48005
|
...kaminoRefreshIxs.instructions,
|
|
47059
48006
|
...updateDriftMarketIxs.instructions,
|
|
47060
|
-
...
|
|
48007
|
+
...updateJupLendRateIxs.instructions
|
|
47061
48008
|
];
|
|
47062
48009
|
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
47063
48010
|
blockhash,
|
|
@@ -47087,110 +48034,121 @@ async function makeRepayWithCollatTx(params) {
|
|
|
47087
48034
|
);
|
|
47088
48035
|
}
|
|
47089
48036
|
const transactions = [...additionalTxs, flashloanTx];
|
|
47090
|
-
return {
|
|
48037
|
+
return {
|
|
48038
|
+
transactions,
|
|
48039
|
+
actionTxIndex: transactions.length - 1,
|
|
48040
|
+
quoteResponse: swapQuote
|
|
48041
|
+
};
|
|
47091
48042
|
}
|
|
47092
|
-
async function
|
|
48043
|
+
async function buildLoopFlashloanTx({
|
|
47093
48044
|
program,
|
|
47094
48045
|
marginfiAccount,
|
|
47095
48046
|
bankMap,
|
|
47096
|
-
|
|
47097
|
-
|
|
48047
|
+
borrowOpts,
|
|
48048
|
+
depositOpts,
|
|
47098
48049
|
bankMetadataMap,
|
|
47099
|
-
assetShareValueMultiplierByBank,
|
|
47100
48050
|
addressLookupTableAccounts,
|
|
47101
48051
|
connection,
|
|
47102
48052
|
swapOpts,
|
|
47103
48053
|
overrideInferAccounts,
|
|
47104
48054
|
blockhash
|
|
47105
48055
|
}) {
|
|
47106
|
-
const swapResult = [];
|
|
47107
48056
|
const cuRequestIxs = [
|
|
47108
48057
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47109
48058
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
47110
48059
|
];
|
|
47111
|
-
|
|
47112
|
-
|
|
47113
|
-
|
|
47114
|
-
|
|
47115
|
-
|
|
47116
|
-
|
|
47117
|
-
|
|
48060
|
+
let amountToDeposit;
|
|
48061
|
+
let swapInstructions = [];
|
|
48062
|
+
let setupInstructions = [];
|
|
48063
|
+
let swapLookupTables = [];
|
|
48064
|
+
let swapQuote;
|
|
48065
|
+
let sizeConstraintUsed = 0;
|
|
48066
|
+
if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
|
|
48067
|
+
amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
|
|
47118
48068
|
} else {
|
|
47119
48069
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
47120
|
-
new web3_js.PublicKey(
|
|
48070
|
+
new web3_js.PublicKey(depositOpts.depositBank.mint),
|
|
47121
48071
|
marginfiAccount.authority,
|
|
47122
48072
|
true,
|
|
47123
|
-
|
|
48073
|
+
depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47124
48074
|
);
|
|
47125
|
-
const
|
|
47126
|
-
|
|
47127
|
-
|
|
47128
|
-
|
|
47129
|
-
|
|
47130
|
-
|
|
47131
|
-
|
|
47132
|
-
|
|
47133
|
-
|
|
47134
|
-
|
|
47135
|
-
|
|
47136
|
-
|
|
47137
|
-
|
|
48075
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
48076
|
+
program,
|
|
48077
|
+
marginfiAccount,
|
|
48078
|
+
bankMap,
|
|
48079
|
+
bankMetadataMap,
|
|
48080
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
48081
|
+
primaryIx: {
|
|
48082
|
+
type: "borrow",
|
|
48083
|
+
bank: borrowOpts.borrowBank,
|
|
48084
|
+
tokenProgram: borrowOpts.tokenProgram
|
|
48085
|
+
},
|
|
48086
|
+
secondaryIx: {
|
|
48087
|
+
type: "deposit",
|
|
48088
|
+
bank: depositOpts.depositBank,
|
|
48089
|
+
tokenProgram: depositOpts.tokenProgram
|
|
47138
48090
|
},
|
|
48091
|
+
overrideInferAccounts
|
|
48092
|
+
});
|
|
48093
|
+
const swapResponse = await getSwapIxsForFlashloan({
|
|
48094
|
+
inputMint: borrowOpts.borrowBank.mint.toBase58(),
|
|
48095
|
+
outputMint: depositOpts.depositBank.mint.toBase58(),
|
|
48096
|
+
amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
|
|
48097
|
+
swapMode: "ExactIn",
|
|
47139
48098
|
authority: marginfiAccount.authority,
|
|
47140
48099
|
connection,
|
|
47141
48100
|
destinationTokenAccount,
|
|
47142
|
-
|
|
47143
|
-
|
|
47144
|
-
|
|
47145
|
-
const { swapInstruction, addressLookupTableAddresses, quoteResponse } = response;
|
|
47146
|
-
const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
|
|
47147
|
-
const outAmountThreshold = nativeToUi(
|
|
47148
|
-
quoteResponse.otherAmountThreshold,
|
|
47149
|
-
repayOpts.repayBank.mintDecimals
|
|
47150
|
-
);
|
|
47151
|
-
const amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
|
|
47152
|
-
swapResult.push({
|
|
47153
|
-
amountToRepay,
|
|
47154
|
-
swapInstructions: [swapInstruction],
|
|
47155
|
-
setupInstructions: [],
|
|
47156
|
-
swapLookupTables: addressLookupTableAddresses,
|
|
47157
|
-
quoteResponse
|
|
47158
|
-
});
|
|
48101
|
+
swapOpts,
|
|
48102
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48103
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47159
48104
|
});
|
|
48105
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
48106
|
+
const outAmountThreshold = nativeToUi(
|
|
48107
|
+
swapResponse.quoteResponse.otherAmountThreshold,
|
|
48108
|
+
depositOpts.depositBank.mintDecimals
|
|
48109
|
+
);
|
|
48110
|
+
amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
|
|
48111
|
+
swapInstructions = swapResponse.swapInstructions;
|
|
48112
|
+
setupInstructions = swapResponse.setupInstructions;
|
|
48113
|
+
swapLookupTables = swapResponse.addressLookupTableAddresses;
|
|
48114
|
+
swapQuote = swapResponse.quoteResponse;
|
|
47160
48115
|
}
|
|
47161
|
-
|
|
47162
|
-
|
|
48116
|
+
const borrowIxs = await makeBorrowIx3({
|
|
48117
|
+
program,
|
|
48118
|
+
bank: borrowOpts.borrowBank,
|
|
48119
|
+
bankMap,
|
|
48120
|
+
tokenProgram: borrowOpts.tokenProgram,
|
|
48121
|
+
amount: borrowOpts.borrowAmount,
|
|
48122
|
+
marginfiAccount,
|
|
48123
|
+
authority: marginfiAccount.authority,
|
|
48124
|
+
isSync: false,
|
|
48125
|
+
opts: {
|
|
48126
|
+
createAtas: false,
|
|
48127
|
+
wrapAndUnwrapSol: false,
|
|
48128
|
+
overrideInferAccounts
|
|
48129
|
+
}
|
|
48130
|
+
});
|
|
48131
|
+
let depositIxs;
|
|
48132
|
+
switch (depositOpts.depositBank.config.assetTag) {
|
|
47163
48133
|
case 3 /* KAMINO */: {
|
|
47164
|
-
const reserve = bankMetadataMap[
|
|
48134
|
+
const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47165
48135
|
if (!reserve) {
|
|
47166
48136
|
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
48137
|
+
depositOpts.depositBank.address.toBase58(),
|
|
48138
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
48139
|
+
depositOpts.depositBank.tokenSymbol
|
|
47170
48140
|
);
|
|
47171
48141
|
}
|
|
47172
|
-
|
|
47173
|
-
const adjustedAmount = new BigNumber3.BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
|
|
47174
|
-
withdrawIxs = await makeKaminoWithdrawIx3({
|
|
48142
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
47175
48143
|
program,
|
|
47176
|
-
bank:
|
|
47177
|
-
|
|
47178
|
-
|
|
47179
|
-
|
|
47180
|
-
marginfiAccount,
|
|
48144
|
+
bank: depositOpts.depositBank,
|
|
48145
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
48146
|
+
amount: amountToDeposit,
|
|
48147
|
+
accountAddress: marginfiAccount.address,
|
|
47181
48148
|
authority: marginfiAccount.authority,
|
|
48149
|
+
group: marginfiAccount.group,
|
|
47182
48150
|
reserve,
|
|
47183
|
-
withdrawAll: isWholePosition(
|
|
47184
|
-
{
|
|
47185
|
-
amount: withdrawOpts.totalPositionAmount,
|
|
47186
|
-
isLending: true
|
|
47187
|
-
},
|
|
47188
|
-
withdrawOpts.withdrawAmount,
|
|
47189
|
-
withdrawOpts.withdrawBank.mintDecimals
|
|
47190
|
-
),
|
|
47191
|
-
isSync: false,
|
|
47192
48151
|
opts: {
|
|
47193
|
-
createAtas: false,
|
|
47194
48152
|
wrapAndUnwrapSol: false,
|
|
47195
48153
|
overrideInferAccounts
|
|
47196
48154
|
}
|
|
@@ -47198,35 +48156,27 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47198
48156
|
break;
|
|
47199
48157
|
}
|
|
47200
48158
|
case 4 /* DRIFT */: {
|
|
47201
|
-
const driftState = bankMetadataMap[
|
|
48159
|
+
const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
|
|
47202
48160
|
if (!driftState) {
|
|
47203
48161
|
throw TransactionBuildingError.driftStateNotFound(
|
|
47204
|
-
|
|
47205
|
-
|
|
47206
|
-
|
|
48162
|
+
depositOpts.depositBank.address.toBase58(),
|
|
48163
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
48164
|
+
depositOpts.depositBank.tokenSymbol
|
|
47207
48165
|
);
|
|
47208
48166
|
}
|
|
47209
|
-
|
|
48167
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
48168
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
48169
|
+
depositIxs = await makeDriftDepositIx3({
|
|
47210
48170
|
program,
|
|
47211
|
-
bank:
|
|
47212
|
-
|
|
47213
|
-
|
|
47214
|
-
|
|
47215
|
-
marginfiAccount,
|
|
48171
|
+
bank: depositOpts.depositBank,
|
|
48172
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
48173
|
+
amount: amountToDeposit,
|
|
48174
|
+
accountAddress: marginfiAccount.address,
|
|
47216
48175
|
authority: marginfiAccount.authority,
|
|
47217
|
-
|
|
47218
|
-
|
|
47219
|
-
|
|
47220
|
-
{
|
|
47221
|
-
amount: withdrawOpts.totalPositionAmount,
|
|
47222
|
-
isLending: true
|
|
47223
|
-
},
|
|
47224
|
-
withdrawOpts.withdrawAmount,
|
|
47225
|
-
withdrawOpts.withdrawBank.mintDecimals
|
|
47226
|
-
),
|
|
47227
|
-
isSync: false,
|
|
48176
|
+
group: marginfiAccount.group,
|
|
48177
|
+
driftMarketIndex,
|
|
48178
|
+
driftOracle,
|
|
47228
48179
|
opts: {
|
|
47229
|
-
createAtas: false,
|
|
47230
48180
|
wrapAndUnwrapSol: false,
|
|
47231
48181
|
overrideInferAccounts
|
|
47232
48182
|
}
|
|
@@ -47234,33 +48184,15 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47234
48184
|
break;
|
|
47235
48185
|
}
|
|
47236
48186
|
case 6 /* JUPLEND */: {
|
|
47237
|
-
|
|
47238
|
-
if (!jupLendState) {
|
|
47239
|
-
throw TransactionBuildingError.jupLendStateNotFound(
|
|
47240
|
-
withdrawOpts.withdrawBank.address.toBase58(),
|
|
47241
|
-
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47242
|
-
withdrawOpts.withdrawBank.tokenSymbol
|
|
47243
|
-
);
|
|
47244
|
-
}
|
|
47245
|
-
withdrawIxs = await makeJuplendWithdrawIx2({
|
|
48187
|
+
depositIxs = await makeJuplendDepositIx2({
|
|
47246
48188
|
program,
|
|
47247
|
-
bank:
|
|
47248
|
-
|
|
47249
|
-
|
|
47250
|
-
|
|
47251
|
-
marginfiAccount,
|
|
48189
|
+
bank: depositOpts.depositBank,
|
|
48190
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
48191
|
+
amount: amountToDeposit,
|
|
48192
|
+
accountAddress: marginfiAccount.address,
|
|
47252
48193
|
authority: marginfiAccount.authority,
|
|
47253
|
-
|
|
47254
|
-
withdrawAll: isWholePosition(
|
|
47255
|
-
{
|
|
47256
|
-
amount: withdrawOpts.totalPositionAmount,
|
|
47257
|
-
isLending: true
|
|
47258
|
-
},
|
|
47259
|
-
withdrawOpts.withdrawAmount,
|
|
47260
|
-
withdrawOpts.withdrawBank.mintDecimals
|
|
47261
|
-
),
|
|
48194
|
+
group: marginfiAccount.group,
|
|
47262
48195
|
opts: {
|
|
47263
|
-
createAtas: false,
|
|
47264
48196
|
wrapAndUnwrapSol: false,
|
|
47265
48197
|
overrideInferAccounts
|
|
47266
48198
|
}
|
|
@@ -47268,25 +48200,15 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47268
48200
|
break;
|
|
47269
48201
|
}
|
|
47270
48202
|
default: {
|
|
47271
|
-
|
|
48203
|
+
depositIxs = await makeDepositIx3({
|
|
47272
48204
|
program,
|
|
47273
|
-
bank:
|
|
47274
|
-
|
|
47275
|
-
|
|
47276
|
-
|
|
47277
|
-
marginfiAccount,
|
|
48205
|
+
bank: depositOpts.depositBank,
|
|
48206
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
48207
|
+
amount: amountToDeposit,
|
|
48208
|
+
accountAddress: marginfiAccount.address,
|
|
47278
48209
|
authority: marginfiAccount.authority,
|
|
47279
|
-
|
|
47280
|
-
{
|
|
47281
|
-
amount: withdrawOpts.totalPositionAmount,
|
|
47282
|
-
isLending: true
|
|
47283
|
-
},
|
|
47284
|
-
withdrawOpts.withdrawAmount,
|
|
47285
|
-
withdrawOpts.withdrawBank.mintDecimals
|
|
47286
|
-
),
|
|
47287
|
-
isSync: false,
|
|
48210
|
+
group: marginfiAccount.group,
|
|
47288
48211
|
opts: {
|
|
47289
|
-
createAtas: false,
|
|
47290
48212
|
wrapAndUnwrapSol: false,
|
|
47291
48213
|
overrideInferAccounts
|
|
47292
48214
|
}
|
|
@@ -47294,68 +48216,48 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47294
48216
|
break;
|
|
47295
48217
|
}
|
|
47296
48218
|
}
|
|
47297
|
-
|
|
47298
|
-
|
|
47299
|
-
|
|
47300
|
-
|
|
47301
|
-
|
|
47302
|
-
|
|
47303
|
-
|
|
47304
|
-
|
|
47305
|
-
|
|
47306
|
-
|
|
47307
|
-
|
|
47308
|
-
|
|
47309
|
-
|
|
47310
|
-
|
|
47311
|
-
|
|
47312
|
-
repayOpts.repayBank.mintDecimals
|
|
47313
|
-
),
|
|
47314
|
-
isSync: false,
|
|
47315
|
-
opts: {
|
|
47316
|
-
wrapAndUnwrapSol: false,
|
|
47317
|
-
overrideInferAccounts
|
|
47318
|
-
}
|
|
47319
|
-
});
|
|
47320
|
-
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
47321
|
-
const flashloanParams = {
|
|
47322
|
-
program,
|
|
47323
|
-
marginfiAccount,
|
|
47324
|
-
bankMap,
|
|
47325
|
-
addressLookupTableAccounts: luts,
|
|
47326
|
-
blockhash
|
|
47327
|
-
};
|
|
47328
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
47329
|
-
...flashloanParams,
|
|
47330
|
-
ixs: [
|
|
47331
|
-
...cuRequestIxs,
|
|
47332
|
-
...withdrawIxs.instructions,
|
|
47333
|
-
...swapInstructions,
|
|
47334
|
-
...repayIxs.instructions
|
|
47335
|
-
],
|
|
47336
|
-
isSync: true
|
|
48219
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
48220
|
+
const allNonFlIxs = [
|
|
48221
|
+
...cuRequestIxs,
|
|
48222
|
+
...borrowIxs.instructions,
|
|
48223
|
+
...swapInstructions,
|
|
48224
|
+
...depositIxs.instructions
|
|
48225
|
+
];
|
|
48226
|
+
if (swapInstructions.length > 0) {
|
|
48227
|
+
compileFlashloanPrecheck({
|
|
48228
|
+
allIxs: allNonFlIxs,
|
|
48229
|
+
payer: marginfiAccount.authority,
|
|
48230
|
+
luts,
|
|
48231
|
+
sizeConstraint: sizeConstraintUsed,
|
|
48232
|
+
swapIxCount: swapInstructions.length,
|
|
48233
|
+
swapLutCount: swapLookupTables.length
|
|
47337
48234
|
});
|
|
47338
|
-
const txSize = getTxSize(flashloanTx);
|
|
47339
|
-
const keySize = getAccountKeys(flashloanTx, luts);
|
|
47340
|
-
const isLast = index === swapResult.length - 1;
|
|
47341
|
-
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
47342
|
-
if (isLast) {
|
|
47343
|
-
throw TransactionBuildingError.jupiterSwapSizeExceededRepay(txSize, keySize);
|
|
47344
|
-
} else {
|
|
47345
|
-
continue;
|
|
47346
|
-
}
|
|
47347
|
-
} else {
|
|
47348
|
-
return {
|
|
47349
|
-
flashloanTx,
|
|
47350
|
-
setupInstructions,
|
|
47351
|
-
swapQuote: quoteResponse,
|
|
47352
|
-
withdrawIxs,
|
|
47353
|
-
repayIxs,
|
|
47354
|
-
amountToRepay
|
|
47355
|
-
};
|
|
47356
|
-
}
|
|
47357
48235
|
}
|
|
47358
|
-
|
|
48236
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
48237
|
+
program,
|
|
48238
|
+
marginfiAccount,
|
|
48239
|
+
bankMap,
|
|
48240
|
+
addressLookupTableAccounts: luts,
|
|
48241
|
+
blockhash,
|
|
48242
|
+
ixs: allNonFlIxs
|
|
48243
|
+
});
|
|
48244
|
+
const txSize = getTxSize(flashloanTx);
|
|
48245
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
48246
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
48247
|
+
throw TransactionBuildingError.swapSizeExceededLoop(
|
|
48248
|
+
txSize,
|
|
48249
|
+
totalKeys,
|
|
48250
|
+
swapOpts.swapConfig?.provider
|
|
48251
|
+
);
|
|
48252
|
+
}
|
|
48253
|
+
return {
|
|
48254
|
+
flashloanTx,
|
|
48255
|
+
setupInstructions,
|
|
48256
|
+
swapQuote,
|
|
48257
|
+
borrowIxs,
|
|
48258
|
+
depositIxs,
|
|
48259
|
+
amountToDeposit
|
|
48260
|
+
};
|
|
47359
48261
|
}
|
|
47360
48262
|
|
|
47361
48263
|
// src/services/account/actions/emissions.ts
|
|
@@ -47509,11 +48411,16 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47509
48411
|
actualWithdrawAmount,
|
|
47510
48412
|
withdrawBank.mintDecimals
|
|
47511
48413
|
);
|
|
47512
|
-
const swapResult = [];
|
|
47513
48414
|
const cuRequestIxs = [
|
|
47514
48415
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47515
48416
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
47516
48417
|
];
|
|
48418
|
+
let amountToDeposit;
|
|
48419
|
+
let swapInstructions = [];
|
|
48420
|
+
let setupInstructions = [];
|
|
48421
|
+
let swapLookupTables = [];
|
|
48422
|
+
let swapQuote;
|
|
48423
|
+
let sizeConstraintUsed = 0;
|
|
47517
48424
|
let withdrawIxs;
|
|
47518
48425
|
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
47519
48426
|
case 3 /* KAMINO */: {
|
|
@@ -47623,12 +48530,7 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47623
48530
|
}
|
|
47624
48531
|
}
|
|
47625
48532
|
if (depositBank.mint.equals(withdrawBank.mint)) {
|
|
47626
|
-
|
|
47627
|
-
amountToDeposit: actualWithdrawAmount,
|
|
47628
|
-
swapInstructions: [],
|
|
47629
|
-
setupInstructions: [],
|
|
47630
|
-
swapLookupTables: []
|
|
47631
|
-
});
|
|
48533
|
+
amountToDeposit = actualWithdrawAmount;
|
|
47632
48534
|
} else {
|
|
47633
48535
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
47634
48536
|
depositBank.mint,
|
|
@@ -47636,175 +48538,168 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47636
48538
|
true,
|
|
47637
48539
|
depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47638
48540
|
);
|
|
47639
|
-
const
|
|
47640
|
-
|
|
47641
|
-
|
|
47642
|
-
|
|
47643
|
-
|
|
47644
|
-
|
|
47645
|
-
|
|
47646
|
-
|
|
47647
|
-
|
|
47648
|
-
|
|
47649
|
-
|
|
48541
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
48542
|
+
program,
|
|
48543
|
+
marginfiAccount,
|
|
48544
|
+
bankMap,
|
|
48545
|
+
bankMetadataMap,
|
|
48546
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
48547
|
+
primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
|
|
48548
|
+
secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
|
|
48549
|
+
overrideInferAccounts
|
|
48550
|
+
});
|
|
48551
|
+
const swapResponses = await getSwapIxsForFlashloan({
|
|
48552
|
+
inputMint: withdrawBank.mint.toBase58(),
|
|
48553
|
+
outputMint: depositBank.mint.toBase58(),
|
|
48554
|
+
amount: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
|
|
48555
|
+
swapMode: "ExactIn",
|
|
47650
48556
|
authority: marginfiAccount.authority,
|
|
47651
48557
|
connection,
|
|
47652
48558
|
destinationTokenAccount,
|
|
47653
|
-
|
|
48559
|
+
swapOpts,
|
|
48560
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48561
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47654
48562
|
});
|
|
47655
|
-
|
|
47656
|
-
|
|
47657
|
-
|
|
47658
|
-
|
|
47659
|
-
);
|
|
47660
|
-
swapResult.push({
|
|
47661
|
-
amountToDeposit: outAmountThreshold,
|
|
47662
|
-
swapInstructions: [response.swapInstruction],
|
|
47663
|
-
setupInstructions: response.setupInstructions,
|
|
47664
|
-
swapLookupTables: response.addressLookupTableAddresses,
|
|
47665
|
-
quoteResponse: response.quoteResponse
|
|
47666
|
-
});
|
|
47667
|
-
});
|
|
47668
|
-
}
|
|
47669
|
-
if (swapResult.length === 0) {
|
|
47670
|
-
throw new Error(
|
|
47671
|
-
`No swap routes found for ${withdrawBank.mint.toBase58()} -> ${depositBank.mint.toBase58()}`
|
|
48563
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
48564
|
+
amountToDeposit = nativeToUi(
|
|
48565
|
+
swapResponses.quoteResponse.otherAmountThreshold,
|
|
48566
|
+
depositBank.mintDecimals
|
|
47672
48567
|
);
|
|
48568
|
+
swapInstructions = swapResponses.swapInstructions;
|
|
48569
|
+
setupInstructions = swapResponses.setupInstructions;
|
|
48570
|
+
swapLookupTables = swapResponses.addressLookupTableAddresses;
|
|
48571
|
+
swapQuote = swapResponses.quoteResponse;
|
|
47673
48572
|
}
|
|
47674
|
-
|
|
47675
|
-
|
|
47676
|
-
|
|
47677
|
-
|
|
47678
|
-
|
|
47679
|
-
|
|
47680
|
-
|
|
47681
|
-
|
|
47682
|
-
|
|
47683
|
-
|
|
47684
|
-
case 3 /* KAMINO */: {
|
|
47685
|
-
const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47686
|
-
if (!reserve) {
|
|
47687
|
-
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47688
|
-
depositBank.address.toBase58(),
|
|
47689
|
-
depositBank.mint.toBase58(),
|
|
47690
|
-
depositBank.tokenSymbol
|
|
47691
|
-
);
|
|
47692
|
-
}
|
|
47693
|
-
depositIxs = await makeKaminoDepositIx3({
|
|
47694
|
-
program,
|
|
47695
|
-
bank: depositBank,
|
|
47696
|
-
tokenProgram: depositTokenProgram,
|
|
47697
|
-
amount: amountToDeposit,
|
|
47698
|
-
accountAddress: marginfiAccount.address,
|
|
47699
|
-
authority: marginfiAccount.authority,
|
|
47700
|
-
group: marginfiAccount.group,
|
|
47701
|
-
reserve,
|
|
47702
|
-
opts: {
|
|
47703
|
-
wrapAndUnwrapSol: false,
|
|
47704
|
-
overrideInferAccounts
|
|
47705
|
-
}
|
|
47706
|
-
});
|
|
47707
|
-
break;
|
|
48573
|
+
let depositIxs;
|
|
48574
|
+
switch (depositBank.config.assetTag) {
|
|
48575
|
+
case 3 /* KAMINO */: {
|
|
48576
|
+
const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
48577
|
+
if (!reserve) {
|
|
48578
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
48579
|
+
depositBank.address.toBase58(),
|
|
48580
|
+
depositBank.mint.toBase58(),
|
|
48581
|
+
depositBank.tokenSymbol
|
|
48582
|
+
);
|
|
47708
48583
|
}
|
|
47709
|
-
|
|
47710
|
-
|
|
47711
|
-
|
|
47712
|
-
|
|
47713
|
-
|
|
47714
|
-
|
|
47715
|
-
|
|
47716
|
-
|
|
48584
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
48585
|
+
program,
|
|
48586
|
+
bank: depositBank,
|
|
48587
|
+
tokenProgram: depositTokenProgram,
|
|
48588
|
+
amount: amountToDeposit,
|
|
48589
|
+
accountAddress: marginfiAccount.address,
|
|
48590
|
+
authority: marginfiAccount.authority,
|
|
48591
|
+
group: marginfiAccount.group,
|
|
48592
|
+
reserve,
|
|
48593
|
+
opts: {
|
|
48594
|
+
wrapAndUnwrapSol: false,
|
|
48595
|
+
overrideInferAccounts
|
|
47717
48596
|
}
|
|
47718
|
-
|
|
47719
|
-
|
|
47720
|
-
depositIxs = await makeDriftDepositIx3({
|
|
47721
|
-
program,
|
|
47722
|
-
bank: depositBank,
|
|
47723
|
-
tokenProgram: depositTokenProgram,
|
|
47724
|
-
amount: amountToDeposit,
|
|
47725
|
-
accountAddress: marginfiAccount.address,
|
|
47726
|
-
authority: marginfiAccount.authority,
|
|
47727
|
-
group: marginfiAccount.group,
|
|
47728
|
-
driftMarketIndex,
|
|
47729
|
-
driftOracle,
|
|
47730
|
-
opts: {
|
|
47731
|
-
wrapAndUnwrapSol: false,
|
|
47732
|
-
overrideInferAccounts
|
|
47733
|
-
}
|
|
47734
|
-
});
|
|
47735
|
-
break;
|
|
47736
|
-
}
|
|
47737
|
-
case 6 /* JUPLEND */: {
|
|
47738
|
-
depositIxs = await makeJuplendDepositIx2({
|
|
47739
|
-
program,
|
|
47740
|
-
bank: depositBank,
|
|
47741
|
-
tokenProgram: depositTokenProgram,
|
|
47742
|
-
amount: amountToDeposit,
|
|
47743
|
-
accountAddress: marginfiAccount.address,
|
|
47744
|
-
authority: marginfiAccount.authority,
|
|
47745
|
-
group: marginfiAccount.group,
|
|
47746
|
-
opts: {
|
|
47747
|
-
wrapAndUnwrapSol: false,
|
|
47748
|
-
overrideInferAccounts
|
|
47749
|
-
}
|
|
47750
|
-
});
|
|
47751
|
-
break;
|
|
47752
|
-
}
|
|
47753
|
-
default: {
|
|
47754
|
-
depositIxs = await makeDepositIx3({
|
|
47755
|
-
program,
|
|
47756
|
-
bank: depositBank,
|
|
47757
|
-
tokenProgram: depositTokenProgram,
|
|
47758
|
-
amount: amountToDeposit,
|
|
47759
|
-
accountAddress: marginfiAccount.address,
|
|
47760
|
-
authority: marginfiAccount.authority,
|
|
47761
|
-
group: marginfiAccount.group,
|
|
47762
|
-
opts: {
|
|
47763
|
-
wrapAndUnwrapSol: false,
|
|
47764
|
-
overrideInferAccounts
|
|
47765
|
-
}
|
|
47766
|
-
});
|
|
47767
|
-
break;
|
|
47768
|
-
}
|
|
48597
|
+
});
|
|
48598
|
+
break;
|
|
47769
48599
|
}
|
|
47770
|
-
|
|
47771
|
-
|
|
47772
|
-
|
|
47773
|
-
|
|
47774
|
-
|
|
47775
|
-
|
|
47776
|
-
|
|
47777
|
-
|
|
47778
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
47779
|
-
...flashloanParams,
|
|
47780
|
-
ixs: [
|
|
47781
|
-
...cuRequestIxs,
|
|
47782
|
-
...withdrawIxs.instructions,
|
|
47783
|
-
...swapInstructions,
|
|
47784
|
-
...depositIxs.instructions
|
|
47785
|
-
],
|
|
47786
|
-
isSync: true
|
|
47787
|
-
});
|
|
47788
|
-
const txSize = getTxSize(flashloanTx);
|
|
47789
|
-
const keySize = getAccountKeys(flashloanTx, luts);
|
|
47790
|
-
const isLast = index === swapResult.length - 1;
|
|
47791
|
-
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
47792
|
-
if (isLast) {
|
|
47793
|
-
throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
|
|
47794
|
-
} else {
|
|
47795
|
-
continue;
|
|
48600
|
+
case 4 /* DRIFT */: {
|
|
48601
|
+
const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
|
|
48602
|
+
if (!driftState) {
|
|
48603
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
48604
|
+
depositBank.address.toBase58(),
|
|
48605
|
+
depositBank.mint.toBase58(),
|
|
48606
|
+
depositBank.tokenSymbol
|
|
48607
|
+
);
|
|
47796
48608
|
}
|
|
47797
|
-
|
|
47798
|
-
|
|
47799
|
-
|
|
47800
|
-
|
|
47801
|
-
|
|
47802
|
-
|
|
47803
|
-
|
|
47804
|
-
|
|
48609
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
48610
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
48611
|
+
depositIxs = await makeDriftDepositIx3({
|
|
48612
|
+
program,
|
|
48613
|
+
bank: depositBank,
|
|
48614
|
+
tokenProgram: depositTokenProgram,
|
|
48615
|
+
amount: amountToDeposit,
|
|
48616
|
+
accountAddress: marginfiAccount.address,
|
|
48617
|
+
authority: marginfiAccount.authority,
|
|
48618
|
+
group: marginfiAccount.group,
|
|
48619
|
+
driftMarketIndex,
|
|
48620
|
+
driftOracle,
|
|
48621
|
+
opts: {
|
|
48622
|
+
wrapAndUnwrapSol: false,
|
|
48623
|
+
overrideInferAccounts
|
|
48624
|
+
}
|
|
48625
|
+
});
|
|
48626
|
+
break;
|
|
48627
|
+
}
|
|
48628
|
+
case 6 /* JUPLEND */: {
|
|
48629
|
+
depositIxs = await makeJuplendDepositIx2({
|
|
48630
|
+
program,
|
|
48631
|
+
bank: depositBank,
|
|
48632
|
+
tokenProgram: depositTokenProgram,
|
|
48633
|
+
amount: amountToDeposit,
|
|
48634
|
+
accountAddress: marginfiAccount.address,
|
|
48635
|
+
authority: marginfiAccount.authority,
|
|
48636
|
+
group: marginfiAccount.group,
|
|
48637
|
+
opts: {
|
|
48638
|
+
wrapAndUnwrapSol: false,
|
|
48639
|
+
overrideInferAccounts
|
|
48640
|
+
}
|
|
48641
|
+
});
|
|
48642
|
+
break;
|
|
48643
|
+
}
|
|
48644
|
+
default: {
|
|
48645
|
+
depositIxs = await makeDepositIx3({
|
|
48646
|
+
program,
|
|
48647
|
+
bank: depositBank,
|
|
48648
|
+
tokenProgram: depositTokenProgram,
|
|
48649
|
+
amount: amountToDeposit,
|
|
48650
|
+
accountAddress: marginfiAccount.address,
|
|
48651
|
+
authority: marginfiAccount.authority,
|
|
48652
|
+
group: marginfiAccount.group,
|
|
48653
|
+
opts: {
|
|
48654
|
+
wrapAndUnwrapSol: false,
|
|
48655
|
+
overrideInferAccounts
|
|
48656
|
+
}
|
|
48657
|
+
});
|
|
48658
|
+
break;
|
|
47805
48659
|
}
|
|
47806
48660
|
}
|
|
47807
|
-
|
|
48661
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
48662
|
+
const allNonFlIxs = [
|
|
48663
|
+
...cuRequestIxs,
|
|
48664
|
+
...withdrawIxs.instructions,
|
|
48665
|
+
...swapInstructions,
|
|
48666
|
+
...depositIxs.instructions
|
|
48667
|
+
];
|
|
48668
|
+
if (swapInstructions.length > 0) {
|
|
48669
|
+
compileFlashloanPrecheck({
|
|
48670
|
+
allIxs: allNonFlIxs,
|
|
48671
|
+
payer: marginfiAccount.authority,
|
|
48672
|
+
luts,
|
|
48673
|
+
sizeConstraint: sizeConstraintUsed,
|
|
48674
|
+
swapIxCount: swapInstructions.length,
|
|
48675
|
+
swapLutCount: swapLookupTables.length
|
|
48676
|
+
});
|
|
48677
|
+
}
|
|
48678
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
48679
|
+
program,
|
|
48680
|
+
marginfiAccount,
|
|
48681
|
+
bankMap,
|
|
48682
|
+
addressLookupTableAccounts: luts,
|
|
48683
|
+
blockhash,
|
|
48684
|
+
ixs: allNonFlIxs,
|
|
48685
|
+
isSync: true
|
|
48686
|
+
});
|
|
48687
|
+
const txSize = getTxSize(flashloanTx);
|
|
48688
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
48689
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
48690
|
+
throw TransactionBuildingError.swapSizeExceededLoop(
|
|
48691
|
+
txSize,
|
|
48692
|
+
totalKeys,
|
|
48693
|
+
swapOpts.swapConfig?.provider
|
|
48694
|
+
);
|
|
48695
|
+
}
|
|
48696
|
+
return {
|
|
48697
|
+
flashloanTx,
|
|
48698
|
+
setupInstructions,
|
|
48699
|
+
swapQuote,
|
|
48700
|
+
withdrawIxs,
|
|
48701
|
+
depositIxs
|
|
48702
|
+
};
|
|
47808
48703
|
}
|
|
47809
48704
|
async function makeSwapDebtTx(params) {
|
|
47810
48705
|
const {
|
|
@@ -47942,7 +48837,6 @@ async function buildSwapDebtFlashloanTx({
|
|
|
47942
48837
|
throw new Error("repayAmount must be greater than 0");
|
|
47943
48838
|
}
|
|
47944
48839
|
const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
|
|
47945
|
-
const swapResult = [];
|
|
47946
48840
|
const cuRequestIxs = [
|
|
47947
48841
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47948
48842
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
@@ -47953,140 +48847,120 @@ async function buildSwapDebtFlashloanTx({
|
|
|
47953
48847
|
true,
|
|
47954
48848
|
repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47955
48849
|
);
|
|
47956
|
-
const
|
|
47957
|
-
const estimateQuote = await jupiterApiClient.quoteGet({
|
|
48850
|
+
const { otherAmountThreshold } = await getExactOutEstimate({
|
|
47958
48851
|
inputMint: borrowBank.mint.toBase58(),
|
|
47959
48852
|
outputMint: repayBank.mint.toBase58(),
|
|
47960
48853
|
amount: uiToNative(actualRepayAmount, repayBank.mintDecimals).toNumber(),
|
|
47961
|
-
|
|
47962
|
-
|
|
47963
|
-
slippageBps: swapOpts.jupiterOptions?.slippageBps
|
|
48854
|
+
swapOpts,
|
|
48855
|
+
connection
|
|
47964
48856
|
});
|
|
47965
|
-
const estimatedBorrowAmount = nativeToUi(
|
|
47966
|
-
|
|
47967
|
-
|
|
47968
|
-
|
|
47969
|
-
|
|
47970
|
-
|
|
47971
|
-
|
|
47972
|
-
|
|
47973
|
-
|
|
47974
|
-
|
|
47975
|
-
|
|
47976
|
-
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
48857
|
+
const estimatedBorrowAmount = nativeToUi(otherAmountThreshold, borrowBank.mintDecimals);
|
|
48858
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
48859
|
+
program,
|
|
48860
|
+
marginfiAccount,
|
|
48861
|
+
bankMap,
|
|
48862
|
+
bankMetadataMap,
|
|
48863
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
48864
|
+
primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
|
|
48865
|
+
secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
|
|
48866
|
+
overrideInferAccounts
|
|
48867
|
+
});
|
|
48868
|
+
const swapResponses = await getSwapIxsForFlashloan({
|
|
48869
|
+
inputMint: borrowBank.mint.toBase58(),
|
|
48870
|
+
outputMint: repayBank.mint.toBase58(),
|
|
48871
|
+
amount: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
|
|
48872
|
+
swapMode: "ExactIn",
|
|
47980
48873
|
authority: marginfiAccount.authority,
|
|
47981
48874
|
connection,
|
|
47982
48875
|
destinationTokenAccount,
|
|
47983
|
-
|
|
48876
|
+
swapOpts,
|
|
48877
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48878
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47984
48879
|
});
|
|
47985
|
-
|
|
47986
|
-
|
|
47987
|
-
|
|
47988
|
-
|
|
47989
|
-
|
|
47990
|
-
|
|
47991
|
-
|
|
47992
|
-
|
|
47993
|
-
|
|
47994
|
-
|
|
47995
|
-
|
|
47996
|
-
|
|
47997
|
-
|
|
47998
|
-
|
|
47999
|
-
|
|
48000
|
-
|
|
48880
|
+
const { quoteResponse } = swapResponses;
|
|
48881
|
+
const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
|
|
48882
|
+
const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
|
|
48883
|
+
const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
|
|
48884
|
+
const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
|
|
48885
|
+
const borrowIxs = await makeBorrowIx3({
|
|
48886
|
+
program,
|
|
48887
|
+
bank: borrowBank,
|
|
48888
|
+
bankMap,
|
|
48889
|
+
tokenProgram: borrowTokenProgram,
|
|
48890
|
+
amount: borrowAmount,
|
|
48891
|
+
marginfiAccount,
|
|
48892
|
+
authority: marginfiAccount.authority,
|
|
48893
|
+
isSync: true,
|
|
48894
|
+
opts: {
|
|
48895
|
+
createAtas: false,
|
|
48896
|
+
wrapAndUnwrapSol: false,
|
|
48897
|
+
overrideInferAccounts
|
|
48898
|
+
}
|
|
48001
48899
|
});
|
|
48002
|
-
|
|
48003
|
-
|
|
48004
|
-
|
|
48005
|
-
|
|
48006
|
-
|
|
48007
|
-
|
|
48008
|
-
|
|
48900
|
+
const repayIxs = await makeRepayIx3({
|
|
48901
|
+
program,
|
|
48902
|
+
bank: repayBank,
|
|
48903
|
+
tokenProgram: repayTokenProgram,
|
|
48904
|
+
amount: amountToRepay,
|
|
48905
|
+
accountAddress: marginfiAccount.address,
|
|
48906
|
+
authority: marginfiAccount.authority,
|
|
48907
|
+
repayAll: isWholePosition(
|
|
48908
|
+
{
|
|
48909
|
+
amount: totalPositionAmount,
|
|
48910
|
+
isLending: false
|
|
48911
|
+
},
|
|
48009
48912
|
amountToRepay,
|
|
48010
|
-
|
|
48011
|
-
|
|
48012
|
-
|
|
48013
|
-
|
|
48014
|
-
|
|
48015
|
-
|
|
48016
|
-
const borrowIxs = await makeBorrowIx3({
|
|
48017
|
-
program,
|
|
48018
|
-
bank: borrowBank,
|
|
48019
|
-
bankMap,
|
|
48020
|
-
tokenProgram: borrowTokenProgram,
|
|
48021
|
-
amount: borrowAmount,
|
|
48022
|
-
marginfiAccount,
|
|
48023
|
-
authority: marginfiAccount.authority,
|
|
48024
|
-
isSync: true,
|
|
48025
|
-
opts: {
|
|
48026
|
-
createAtas: false,
|
|
48027
|
-
wrapAndUnwrapSol: false,
|
|
48028
|
-
overrideInferAccounts
|
|
48029
|
-
}
|
|
48030
|
-
});
|
|
48031
|
-
const repayIxs = await makeRepayIx3({
|
|
48032
|
-
program,
|
|
48033
|
-
bank: repayBank,
|
|
48034
|
-
tokenProgram: repayTokenProgram,
|
|
48035
|
-
amount: amountToRepay,
|
|
48036
|
-
accountAddress: marginfiAccount.address,
|
|
48037
|
-
authority: marginfiAccount.authority,
|
|
48038
|
-
repayAll: isWholePosition(
|
|
48039
|
-
{
|
|
48040
|
-
amount: totalPositionAmount,
|
|
48041
|
-
isLending: false
|
|
48042
|
-
},
|
|
48043
|
-
amountToRepay,
|
|
48044
|
-
repayBank.mintDecimals
|
|
48045
|
-
),
|
|
48046
|
-
isSync: true,
|
|
48047
|
-
opts: {
|
|
48048
|
-
wrapAndUnwrapSol: false,
|
|
48049
|
-
overrideInferAccounts
|
|
48050
|
-
}
|
|
48051
|
-
});
|
|
48052
|
-
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
48053
|
-
const flashloanParams = {
|
|
48054
|
-
program,
|
|
48055
|
-
marginfiAccount,
|
|
48056
|
-
bankMap,
|
|
48057
|
-
addressLookupTableAccounts: luts,
|
|
48058
|
-
blockhash
|
|
48059
|
-
};
|
|
48060
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
48061
|
-
...flashloanParams,
|
|
48062
|
-
ixs: [
|
|
48063
|
-
...cuRequestIxs,
|
|
48064
|
-
...borrowIxs.instructions,
|
|
48065
|
-
...swapInstructions,
|
|
48066
|
-
...repayIxs.instructions
|
|
48067
|
-
],
|
|
48068
|
-
isSync: true
|
|
48069
|
-
});
|
|
48070
|
-
const txSize = getTxSize(flashloanTx);
|
|
48071
|
-
const keySize = getAccountKeys(flashloanTx, luts);
|
|
48072
|
-
const isLast = index === swapResult.length - 1;
|
|
48073
|
-
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
48074
|
-
if (isLast) {
|
|
48075
|
-
throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
|
|
48076
|
-
} else {
|
|
48077
|
-
continue;
|
|
48078
|
-
}
|
|
48079
|
-
} else {
|
|
48080
|
-
return {
|
|
48081
|
-
flashloanTx,
|
|
48082
|
-
setupInstructions,
|
|
48083
|
-
swapQuote: quoteResponse,
|
|
48084
|
-
borrowIxs,
|
|
48085
|
-
repayIxs
|
|
48086
|
-
};
|
|
48913
|
+
repayBank.mintDecimals
|
|
48914
|
+
),
|
|
48915
|
+
isSync: true,
|
|
48916
|
+
opts: {
|
|
48917
|
+
wrapAndUnwrapSol: false,
|
|
48918
|
+
overrideInferAccounts
|
|
48087
48919
|
}
|
|
48920
|
+
});
|
|
48921
|
+
const luts = [
|
|
48922
|
+
...addressLookupTableAccounts ?? [],
|
|
48923
|
+
...swapResponses.addressLookupTableAddresses
|
|
48924
|
+
];
|
|
48925
|
+
const allNonFlIxs = [
|
|
48926
|
+
...cuRequestIxs,
|
|
48927
|
+
...borrowIxs.instructions,
|
|
48928
|
+
...swapResponses.swapInstructions,
|
|
48929
|
+
...repayIxs.instructions
|
|
48930
|
+
];
|
|
48931
|
+
compileFlashloanPrecheck({
|
|
48932
|
+
allIxs: allNonFlIxs,
|
|
48933
|
+
payer: marginfiAccount.authority,
|
|
48934
|
+
luts,
|
|
48935
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48936
|
+
swapIxCount: swapResponses.swapInstructions.length,
|
|
48937
|
+
swapLutCount: swapResponses.addressLookupTableAddresses.length
|
|
48938
|
+
});
|
|
48939
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
48940
|
+
program,
|
|
48941
|
+
marginfiAccount,
|
|
48942
|
+
bankMap,
|
|
48943
|
+
addressLookupTableAccounts: luts,
|
|
48944
|
+
blockhash,
|
|
48945
|
+
ixs: allNonFlIxs,
|
|
48946
|
+
isSync: true
|
|
48947
|
+
});
|
|
48948
|
+
const txSize = getTxSize(flashloanTx);
|
|
48949
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
48950
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
48951
|
+
throw TransactionBuildingError.swapSizeExceededLoop(
|
|
48952
|
+
txSize,
|
|
48953
|
+
totalKeys,
|
|
48954
|
+
swapOpts.swapConfig?.provider
|
|
48955
|
+
);
|
|
48088
48956
|
}
|
|
48089
|
-
|
|
48957
|
+
return {
|
|
48958
|
+
flashloanTx,
|
|
48959
|
+
setupInstructions: swapResponses.setupInstructions,
|
|
48960
|
+
swapQuote: quoteResponse,
|
|
48961
|
+
borrowIxs,
|
|
48962
|
+
repayIxs
|
|
48963
|
+
};
|
|
48090
48964
|
}
|
|
48091
48965
|
var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
|
|
48092
48966
|
async function makeMintStakedLstIx(params) {
|
|
@@ -48885,17 +49759,528 @@ function computeMaxWithdrawForBank(params) {
|
|
|
48885
49759
|
const maxWithdraw = initUntiedCollateralForBank.div(initWeightedPrice);
|
|
48886
49760
|
return maxWithdraw;
|
|
48887
49761
|
}
|
|
49762
|
+
var TITAN_FEE_WALLET = new web3_js.PublicKey("6ryqDDCwKFZfSiHQrYRkjTEarbsLjg9TmuFg1RJorBk3");
|
|
49763
|
+
var getTitanFeeAccount = (mint) => {
|
|
49764
|
+
return getAssociatedTokenAddressSync(mint, TITAN_FEE_WALLET, true);
|
|
49765
|
+
};
|
|
49766
|
+
var checkTitanFeeAccount = async (connection, mint) => {
|
|
49767
|
+
const feeAccount = getTitanFeeAccount(mint);
|
|
49768
|
+
const hasFeeAccount = !!await connection.getAccountInfo(feeAccount);
|
|
49769
|
+
return { feeAccount, hasFeeAccount, feeWallet: TITAN_FEE_WALLET };
|
|
49770
|
+
};
|
|
49771
|
+
function deserializeTitanInstruction(ix) {
|
|
49772
|
+
return new web3_js.TransactionInstruction({
|
|
49773
|
+
programId: new web3_js.PublicKey(ix.p),
|
|
49774
|
+
keys: ix.a.map((account) => ({
|
|
49775
|
+
pubkey: new web3_js.PublicKey(account.p),
|
|
49776
|
+
isSigner: account.s,
|
|
49777
|
+
isWritable: account.w
|
|
49778
|
+
})),
|
|
49779
|
+
data: Buffer.from(ix.d)
|
|
49780
|
+
});
|
|
49781
|
+
}
|
|
49782
|
+
var getTitanSwapIxsForFlashloan = async ({
|
|
49783
|
+
quoteParams,
|
|
49784
|
+
authority,
|
|
49785
|
+
connection,
|
|
49786
|
+
destinationTokenAccount,
|
|
49787
|
+
apiConfig
|
|
49788
|
+
}) => {
|
|
49789
|
+
const basePath = apiConfig?.basePath ?? "";
|
|
49790
|
+
const feeMint = new web3_js.PublicKey(
|
|
49791
|
+
quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint
|
|
49792
|
+
);
|
|
49793
|
+
const { feeAccount, hasFeeAccount } = await checkTitanFeeAccount(connection, feeMint);
|
|
49794
|
+
let finalQuoteParams = quoteParams;
|
|
49795
|
+
if (!hasFeeAccount) {
|
|
49796
|
+
console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
|
|
49797
|
+
finalQuoteParams = {
|
|
49798
|
+
...quoteParams,
|
|
49799
|
+
platformFeeBps: void 0
|
|
49800
|
+
};
|
|
49801
|
+
}
|
|
49802
|
+
if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
|
|
49803
|
+
return getTitanSwapIxsViaWebSocket(
|
|
49804
|
+
{ quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
|
|
49805
|
+
hasFeeAccount ? feeAccount : void 0
|
|
49806
|
+
);
|
|
49807
|
+
} else {
|
|
49808
|
+
return getTitanSwapIxsViaHttpProxy(
|
|
49809
|
+
{ quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
|
|
49810
|
+
hasFeeAccount ? feeAccount : void 0
|
|
49811
|
+
);
|
|
49812
|
+
}
|
|
49813
|
+
};
|
|
49814
|
+
async function getTitanSwapIxsViaWebSocket(params, feeAccount) {
|
|
49815
|
+
const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
|
|
49816
|
+
const {
|
|
49817
|
+
inputMint,
|
|
49818
|
+
outputMint,
|
|
49819
|
+
amount,
|
|
49820
|
+
swapMode,
|
|
49821
|
+
slippageBps,
|
|
49822
|
+
platformFeeBps,
|
|
49823
|
+
directRoutesOnly,
|
|
49824
|
+
sizeConstraint,
|
|
49825
|
+
maxSwapAccounts,
|
|
49826
|
+
maxSwapTotalAccounts
|
|
49827
|
+
} = quoteParams;
|
|
49828
|
+
const wsUrl = apiConfig?.basePath;
|
|
49829
|
+
if (!wsUrl) {
|
|
49830
|
+
throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
|
|
49831
|
+
}
|
|
49832
|
+
const txParams = {
|
|
49833
|
+
userPublicKey: authority.toBytes(),
|
|
49834
|
+
outputAccount: destinationTokenAccount.toBytes()
|
|
49835
|
+
};
|
|
49836
|
+
if (feeAccount && platformFeeBps) {
|
|
49837
|
+
txParams.feeBps = platformFeeBps;
|
|
49838
|
+
txParams.feeAccount = feeAccount.toBytes();
|
|
49839
|
+
}
|
|
49840
|
+
const client = await V1Client.connect(wsUrl);
|
|
49841
|
+
try {
|
|
49842
|
+
const { stream } = await client.newSwapQuoteStream({
|
|
49843
|
+
swap: {
|
|
49844
|
+
inputMint: new web3_js.PublicKey(inputMint).toBytes(),
|
|
49845
|
+
outputMint: new web3_js.PublicKey(outputMint).toBytes(),
|
|
49846
|
+
amount,
|
|
49847
|
+
swapMode,
|
|
49848
|
+
slippageBps,
|
|
49849
|
+
onlyDirectRoutes: directRoutesOnly,
|
|
49850
|
+
addSizeConstraint: sizeConstraint !== void 0,
|
|
49851
|
+
sizeConstraint,
|
|
49852
|
+
accountsLimitWritable: maxSwapAccounts,
|
|
49853
|
+
accountsLimitTotal: maxSwapTotalAccounts
|
|
49854
|
+
},
|
|
49855
|
+
transaction: txParams,
|
|
49856
|
+
update: {
|
|
49857
|
+
num_quotes: 3
|
|
49858
|
+
}
|
|
49859
|
+
});
|
|
49860
|
+
const reader = stream.getReader();
|
|
49861
|
+
const { value: swapQuotes, done } = await reader.read();
|
|
49862
|
+
reader.releaseLock();
|
|
49863
|
+
if (done || !swapQuotes) {
|
|
49864
|
+
throw new Error("Titan swap quote stream ended without data");
|
|
49865
|
+
}
|
|
49866
|
+
const quotes = swapQuotes;
|
|
49867
|
+
const bestRoute = selectBestRoute(quotes.quotes, swapMode);
|
|
49868
|
+
if (!bestRoute) {
|
|
49869
|
+
throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
|
|
49870
|
+
}
|
|
49871
|
+
const swapInstructions = bestRoute.instructions.map(deserializeTitanInstruction);
|
|
49872
|
+
const lutPubkeys = bestRoute.addressLookupTables.map((lutBytes) => new web3_js.PublicKey(lutBytes));
|
|
49873
|
+
const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
|
|
49874
|
+
const quoteResponse = {
|
|
49875
|
+
...buildSwapQuoteResult(bestRoute, swapMode),
|
|
49876
|
+
provider: "TITAN" /* TITAN */
|
|
49877
|
+
};
|
|
49878
|
+
return {
|
|
49879
|
+
swapInstructions,
|
|
49880
|
+
setupInstructions: [],
|
|
49881
|
+
addressLookupTableAddresses,
|
|
49882
|
+
quoteResponse
|
|
49883
|
+
};
|
|
49884
|
+
} finally {
|
|
49885
|
+
if (!client.closed) {
|
|
49886
|
+
await client.close();
|
|
49887
|
+
}
|
|
49888
|
+
}
|
|
49889
|
+
}
|
|
49890
|
+
async function getTitanSwapIxsViaHttpProxy(params, feeAccount) {
|
|
49891
|
+
const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
|
|
49892
|
+
const {
|
|
49893
|
+
inputMint,
|
|
49894
|
+
outputMint,
|
|
49895
|
+
amount,
|
|
49896
|
+
swapMode,
|
|
49897
|
+
slippageBps,
|
|
49898
|
+
platformFeeBps,
|
|
49899
|
+
directRoutesOnly,
|
|
49900
|
+
sizeConstraint,
|
|
49901
|
+
maxSwapAccounts,
|
|
49902
|
+
maxSwapTotalAccounts
|
|
49903
|
+
} = quoteParams;
|
|
49904
|
+
const basePath = apiConfig?.basePath;
|
|
49905
|
+
if (!basePath) {
|
|
49906
|
+
throw new Error("Titan proxy URL is required (apiConfig.basePath)");
|
|
49907
|
+
}
|
|
49908
|
+
const txBody = {
|
|
49909
|
+
userPublicKey: authority.toBase58(),
|
|
49910
|
+
outputAccount: destinationTokenAccount.toBase58()
|
|
49911
|
+
};
|
|
49912
|
+
if (feeAccount && platformFeeBps) {
|
|
49913
|
+
txBody.feeBps = platformFeeBps;
|
|
49914
|
+
txBody.feeAccount = feeAccount.toBase58();
|
|
49915
|
+
}
|
|
49916
|
+
const response = await fetch(`${basePath}/swap-quote`, {
|
|
49917
|
+
method: "POST",
|
|
49918
|
+
headers: {
|
|
49919
|
+
"Content-Type": "application/json",
|
|
49920
|
+
...apiConfig?.headers ?? {}
|
|
49921
|
+
},
|
|
49922
|
+
body: JSON.stringify({
|
|
49923
|
+
swap: {
|
|
49924
|
+
inputMint,
|
|
49925
|
+
outputMint,
|
|
49926
|
+
amount,
|
|
49927
|
+
swapMode,
|
|
49928
|
+
slippageBps,
|
|
49929
|
+
onlyDirectRoutes: directRoutesOnly,
|
|
49930
|
+
addSizeConstraint: sizeConstraint !== void 0,
|
|
49931
|
+
sizeConstraint,
|
|
49932
|
+
accountsLimitWritable: maxSwapAccounts,
|
|
49933
|
+
accountsLimitTotal: maxSwapTotalAccounts
|
|
49934
|
+
},
|
|
49935
|
+
transaction: txBody
|
|
49936
|
+
})
|
|
49937
|
+
});
|
|
49938
|
+
if (!response.ok) {
|
|
49939
|
+
const errorData = await response.json().catch(() => ({}));
|
|
49940
|
+
throw new Error(
|
|
49941
|
+
`Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
|
|
49942
|
+
);
|
|
49943
|
+
}
|
|
49944
|
+
const data = await response.json();
|
|
49945
|
+
const bestRoute = selectBestRoute(data.quotes, swapMode);
|
|
49946
|
+
if (!bestRoute) {
|
|
49947
|
+
throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
|
|
49948
|
+
}
|
|
49949
|
+
const swapInstructions = bestRoute.instructions.map(deserializeSerializedInstruction);
|
|
49950
|
+
const lutPubkeys = bestRoute.addressLookupTables.map(
|
|
49951
|
+
(b64) => new web3_js.PublicKey(Buffer.from(b64, "base64"))
|
|
49952
|
+
);
|
|
49953
|
+
const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
|
|
49954
|
+
const quoteResponse = {
|
|
49955
|
+
...buildSwapQuoteResult(bestRoute, swapMode),
|
|
49956
|
+
provider: "TITAN" /* TITAN */
|
|
49957
|
+
};
|
|
49958
|
+
return {
|
|
49959
|
+
swapInstructions,
|
|
49960
|
+
setupInstructions: [],
|
|
49961
|
+
addressLookupTableAddresses,
|
|
49962
|
+
quoteResponse
|
|
49963
|
+
};
|
|
49964
|
+
}
|
|
49965
|
+
var getTitanExactOutEstimate = async (params) => {
|
|
49966
|
+
const basePath = params.apiConfig?.basePath ?? "";
|
|
49967
|
+
if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
|
|
49968
|
+
return getTitanExactOutViaWebSocket(params);
|
|
49969
|
+
} else {
|
|
49970
|
+
return getTitanExactOutViaHttpProxy(params);
|
|
49971
|
+
}
|
|
49972
|
+
};
|
|
49973
|
+
async function getTitanExactOutViaWebSocket(params) {
|
|
49974
|
+
const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
|
|
49975
|
+
const wsUrl = apiConfig?.basePath;
|
|
49976
|
+
if (!wsUrl) {
|
|
49977
|
+
throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
|
|
49978
|
+
}
|
|
49979
|
+
const client = await V1Client.connect(wsUrl);
|
|
49980
|
+
try {
|
|
49981
|
+
const { stream } = await client.newSwapQuoteStream({
|
|
49982
|
+
swap: {
|
|
49983
|
+
inputMint: new web3_js.PublicKey(inputMint).toBytes(),
|
|
49984
|
+
outputMint: new web3_js.PublicKey(outputMint).toBytes(),
|
|
49985
|
+
amount,
|
|
49986
|
+
swapMode: "ExactOut",
|
|
49987
|
+
slippageBps
|
|
49988
|
+
},
|
|
49989
|
+
transaction: {
|
|
49990
|
+
userPublicKey: new Uint8Array(32)
|
|
49991
|
+
// placeholder, not executing
|
|
49992
|
+
},
|
|
49993
|
+
update: {
|
|
49994
|
+
num_quotes: 1
|
|
49995
|
+
}
|
|
49996
|
+
});
|
|
49997
|
+
const reader = stream.getReader();
|
|
49998
|
+
const { value: swapQuotes, done } = await reader.read();
|
|
49999
|
+
reader.releaseLock();
|
|
50000
|
+
if (done || !swapQuotes) {
|
|
50001
|
+
throw new Error("Titan ExactOut estimate stream ended without data");
|
|
50002
|
+
}
|
|
50003
|
+
const quotes = swapQuotes;
|
|
50004
|
+
const bestRoute = selectBestRoute(quotes.quotes, "ExactOut");
|
|
50005
|
+
if (!bestRoute) {
|
|
50006
|
+
throw new Error(`No Titan ExactOut routes found for ${inputMint} -> ${outputMint}`);
|
|
50007
|
+
}
|
|
50008
|
+
const quoteResult = {
|
|
50009
|
+
...buildSwapQuoteResult(bestRoute, "ExactOut"),
|
|
50010
|
+
provider: "TITAN" /* TITAN */
|
|
50011
|
+
};
|
|
50012
|
+
return {
|
|
50013
|
+
otherAmountThreshold: quoteResult.otherAmountThreshold,
|
|
50014
|
+
quoteResult
|
|
50015
|
+
};
|
|
50016
|
+
} finally {
|
|
50017
|
+
if (!client.closed) {
|
|
50018
|
+
await client.close();
|
|
50019
|
+
}
|
|
50020
|
+
}
|
|
50021
|
+
}
|
|
50022
|
+
async function getTitanExactOutViaHttpProxy(params) {
|
|
50023
|
+
const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
|
|
50024
|
+
const basePath = apiConfig?.basePath;
|
|
50025
|
+
if (!basePath) {
|
|
50026
|
+
throw new Error("Titan proxy URL is required (apiConfig.basePath)");
|
|
50027
|
+
}
|
|
50028
|
+
const response = await fetch(`${basePath}/exact-out-estimate`, {
|
|
50029
|
+
method: "POST",
|
|
50030
|
+
headers: {
|
|
50031
|
+
"Content-Type": "application/json",
|
|
50032
|
+
...apiConfig?.headers ?? {}
|
|
50033
|
+
},
|
|
50034
|
+
body: JSON.stringify({
|
|
50035
|
+
inputMint,
|
|
50036
|
+
outputMint,
|
|
50037
|
+
amount,
|
|
50038
|
+
slippageBps
|
|
50039
|
+
})
|
|
50040
|
+
});
|
|
50041
|
+
if (!response.ok) {
|
|
50042
|
+
const errorData = await response.json().catch(() => ({}));
|
|
50043
|
+
throw new Error(
|
|
50044
|
+
`Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
|
|
50045
|
+
);
|
|
50046
|
+
}
|
|
50047
|
+
const data = await response.json();
|
|
50048
|
+
const quoteResult = {
|
|
50049
|
+
inAmount: String(data.inAmount),
|
|
50050
|
+
outAmount: String(data.outAmount),
|
|
50051
|
+
otherAmountThreshold: data.otherAmountThreshold,
|
|
50052
|
+
slippageBps: data.slippageBps,
|
|
50053
|
+
provider: "TITAN" /* TITAN */
|
|
50054
|
+
};
|
|
50055
|
+
return {
|
|
50056
|
+
otherAmountThreshold: data.otherAmountThreshold,
|
|
50057
|
+
quoteResult
|
|
50058
|
+
};
|
|
50059
|
+
}
|
|
50060
|
+
|
|
50061
|
+
// src/services/account/utils/swap.utils.ts
|
|
50062
|
+
function getSwapProviderFn({
|
|
50063
|
+
attemptProvider,
|
|
50064
|
+
maxSwapTotalAccounts,
|
|
50065
|
+
inputMint,
|
|
50066
|
+
outputMint,
|
|
50067
|
+
amount,
|
|
50068
|
+
swapMode,
|
|
50069
|
+
authority,
|
|
50070
|
+
connection,
|
|
50071
|
+
destinationTokenAccount,
|
|
50072
|
+
swapOpts,
|
|
50073
|
+
sizeConstraint
|
|
50074
|
+
}) {
|
|
50075
|
+
switch (attemptProvider) {
|
|
50076
|
+
case "TITAN" /* TITAN */:
|
|
50077
|
+
return (apiConfig) => getTitanSwapIxsForFlashloan({
|
|
50078
|
+
quoteParams: {
|
|
50079
|
+
inputMint,
|
|
50080
|
+
outputMint,
|
|
50081
|
+
amount,
|
|
50082
|
+
swapMode,
|
|
50083
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
50084
|
+
platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
|
|
50085
|
+
directRoutesOnly: swapOpts.swapConfig?.directRoutesOnly,
|
|
50086
|
+
sizeConstraint,
|
|
50087
|
+
maxSwapTotalAccounts
|
|
50088
|
+
},
|
|
50089
|
+
authority,
|
|
50090
|
+
connection,
|
|
50091
|
+
destinationTokenAccount,
|
|
50092
|
+
apiConfig
|
|
50093
|
+
});
|
|
50094
|
+
case "JUPITER" /* JUPITER */:
|
|
50095
|
+
return (apiConfig) => getJupiterSwapIxsForFlashloan({
|
|
50096
|
+
quoteParams: {
|
|
50097
|
+
inputMint,
|
|
50098
|
+
outputMint,
|
|
50099
|
+
amount,
|
|
50100
|
+
swapMode,
|
|
50101
|
+
dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
|
|
50102
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
50103
|
+
platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
|
|
50104
|
+
onlyDirectRoutes: swapOpts.swapConfig?.directRoutesOnly ?? false
|
|
50105
|
+
},
|
|
50106
|
+
authority,
|
|
50107
|
+
connection,
|
|
50108
|
+
destinationTokenAccount,
|
|
50109
|
+
apiConfig,
|
|
50110
|
+
maxSwapAccounts: maxSwapTotalAccounts
|
|
50111
|
+
});
|
|
50112
|
+
default:
|
|
50113
|
+
return void 0;
|
|
50114
|
+
}
|
|
50115
|
+
}
|
|
50116
|
+
function getExactOutProviderFn({
|
|
50117
|
+
attemptProvider,
|
|
50118
|
+
inputMint,
|
|
50119
|
+
outputMint,
|
|
50120
|
+
amount,
|
|
50121
|
+
swapOpts,
|
|
50122
|
+
apiConfig
|
|
50123
|
+
}) {
|
|
50124
|
+
switch (attemptProvider) {
|
|
50125
|
+
case "TITAN" /* TITAN */:
|
|
50126
|
+
return () => getTitanExactOutEstimate({
|
|
50127
|
+
inputMint,
|
|
50128
|
+
outputMint,
|
|
50129
|
+
amount,
|
|
50130
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
50131
|
+
apiConfig
|
|
50132
|
+
});
|
|
50133
|
+
case "JUPITER" /* JUPITER */:
|
|
50134
|
+
return async () => {
|
|
50135
|
+
const configParams = toJupiterConfig(apiConfig);
|
|
50136
|
+
const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
|
|
50137
|
+
const estimateQuote = await jupiterApiClient.quoteGet({
|
|
50138
|
+
inputMint,
|
|
50139
|
+
outputMint,
|
|
50140
|
+
amount,
|
|
50141
|
+
swapMode: "ExactOut",
|
|
50142
|
+
dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
|
|
50143
|
+
slippageBps: swapOpts.swapConfig?.slippageBps
|
|
50144
|
+
});
|
|
50145
|
+
const quoteResult = mapJupiterQuoteToSwapQuoteResult(estimateQuote);
|
|
50146
|
+
return { otherAmountThreshold: quoteResult.otherAmountThreshold, quoteResult };
|
|
50147
|
+
};
|
|
50148
|
+
default:
|
|
50149
|
+
return void 0;
|
|
50150
|
+
}
|
|
50151
|
+
}
|
|
50152
|
+
var getSwapIxsForFlashloan = async (params) => {
|
|
50153
|
+
const {
|
|
50154
|
+
inputMint,
|
|
50155
|
+
outputMint,
|
|
50156
|
+
amount,
|
|
50157
|
+
swapMode,
|
|
50158
|
+
authority,
|
|
50159
|
+
connection,
|
|
50160
|
+
destinationTokenAccount,
|
|
50161
|
+
swapOpts,
|
|
50162
|
+
sizeConstraint,
|
|
50163
|
+
maxSwapTotalAccounts
|
|
50164
|
+
} = params;
|
|
50165
|
+
if (swapOpts.swapIxs) {
|
|
50166
|
+
return {
|
|
50167
|
+
swapInstructions: swapOpts.swapIxs.instructions,
|
|
50168
|
+
setupInstructions: [],
|
|
50169
|
+
addressLookupTableAddresses: swapOpts.swapIxs.lookupTables,
|
|
50170
|
+
quoteResponse: {
|
|
50171
|
+
inAmount: String(amount),
|
|
50172
|
+
outAmount: "0",
|
|
50173
|
+
otherAmountThreshold: "0",
|
|
50174
|
+
slippageBps: 0
|
|
50175
|
+
}
|
|
50176
|
+
};
|
|
50177
|
+
}
|
|
50178
|
+
const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
|
|
50179
|
+
const attempts = [
|
|
50180
|
+
{ provider, apiConfig: swapOpts.swapConfig?.apiConfig },
|
|
50181
|
+
...swapOpts.swapConfig?.fallbackProviders ?? []
|
|
50182
|
+
];
|
|
50183
|
+
let lastError;
|
|
50184
|
+
for (const { provider: attemptProvider, apiConfig } of attempts) {
|
|
50185
|
+
const fn = getSwapProviderFn({
|
|
50186
|
+
attemptProvider,
|
|
50187
|
+
maxSwapTotalAccounts: params.maxSwapTotalAccounts,
|
|
50188
|
+
inputMint,
|
|
50189
|
+
outputMint,
|
|
50190
|
+
amount,
|
|
50191
|
+
swapMode,
|
|
50192
|
+
authority,
|
|
50193
|
+
connection,
|
|
50194
|
+
destinationTokenAccount,
|
|
50195
|
+
swapOpts,
|
|
50196
|
+
sizeConstraint
|
|
50197
|
+
});
|
|
50198
|
+
if (!fn) continue;
|
|
50199
|
+
try {
|
|
50200
|
+
return await fn(apiConfig);
|
|
50201
|
+
} catch (err) {
|
|
50202
|
+
if (err instanceof TransactionBuildingError) throw err;
|
|
50203
|
+
lastError = err;
|
|
50204
|
+
console.warn(`[swap] ${attemptProvider} failed:`, err instanceof Error ? err.message : err);
|
|
50205
|
+
}
|
|
50206
|
+
}
|
|
50207
|
+
const firstProvider = attempts[0]?.provider ?? "Swap";
|
|
50208
|
+
throw TransactionBuildingError.swapQuoteFailed(
|
|
50209
|
+
firstProvider,
|
|
50210
|
+
inputMint,
|
|
50211
|
+
outputMint,
|
|
50212
|
+
lastError?.message ?? "No swap route available"
|
|
50213
|
+
);
|
|
50214
|
+
};
|
|
50215
|
+
var getExactOutEstimate = async (params) => {
|
|
50216
|
+
const { inputMint, outputMint, amount, swapOpts, connection } = params;
|
|
50217
|
+
const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
|
|
50218
|
+
const attempts = [
|
|
50219
|
+
{ provider, apiConfig: swapOpts.swapConfig?.apiConfig },
|
|
50220
|
+
...swapOpts.swapConfig?.fallbackProviders ?? []
|
|
50221
|
+
];
|
|
50222
|
+
let lastError;
|
|
50223
|
+
for (const { provider: attemptProvider, apiConfig } of attempts) {
|
|
50224
|
+
const fn = getExactOutProviderFn({
|
|
50225
|
+
attemptProvider,
|
|
50226
|
+
inputMint,
|
|
50227
|
+
outputMint,
|
|
50228
|
+
amount,
|
|
50229
|
+
swapOpts,
|
|
50230
|
+
apiConfig
|
|
50231
|
+
});
|
|
50232
|
+
if (!fn) continue;
|
|
50233
|
+
try {
|
|
50234
|
+
return await fn(apiConfig);
|
|
50235
|
+
} catch (err) {
|
|
50236
|
+
if (err instanceof TransactionBuildingError) throw err;
|
|
50237
|
+
lastError = err;
|
|
50238
|
+
console.warn(
|
|
50239
|
+
`[exactout] ${attemptProvider} failed:`,
|
|
50240
|
+
err instanceof Error ? err.message : err
|
|
50241
|
+
);
|
|
50242
|
+
}
|
|
50243
|
+
}
|
|
50244
|
+
const firstProvider = attempts[0]?.provider ?? "Swap";
|
|
50245
|
+
throw TransactionBuildingError.swapQuoteFailed(
|
|
50246
|
+
firstProvider,
|
|
50247
|
+
inputMint,
|
|
50248
|
+
outputMint,
|
|
50249
|
+
lastError?.message ?? "No swap route available"
|
|
50250
|
+
);
|
|
50251
|
+
};
|
|
50252
|
+
function mapJupiterQuoteToSwapQuoteResult(quote) {
|
|
50253
|
+
return {
|
|
50254
|
+
inAmount: quote.inAmount,
|
|
50255
|
+
outAmount: quote.outAmount,
|
|
50256
|
+
otherAmountThreshold: quote.otherAmountThreshold,
|
|
50257
|
+
slippageBps: quote.slippageBps,
|
|
50258
|
+
platformFee: quote.platformFee ? {
|
|
50259
|
+
amount: quote.platformFee.amount ?? "0",
|
|
50260
|
+
feeBps: quote.platformFee.feeBps ?? 0
|
|
50261
|
+
} : void 0,
|
|
50262
|
+
priceImpactPct: quote.priceImpactPct,
|
|
50263
|
+
contextSlot: quote.contextSlot,
|
|
50264
|
+
timeTaken: quote.timeTaken,
|
|
50265
|
+
provider: "JUPITER" /* JUPITER */
|
|
50266
|
+
};
|
|
50267
|
+
}
|
|
50268
|
+
|
|
50269
|
+
// src/services/account/utils/jupiter.utils.ts
|
|
48888
50270
|
var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
|
|
48889
50271
|
var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
|
|
48890
50272
|
var getFeeAccount = (mint) => {
|
|
48891
|
-
const referralProgramPubkey = REFERRAL_PROGRAM_ID;
|
|
48892
|
-
const referralAccountPubkey = REFERRAL_ACCOUNT_PUBKEY;
|
|
48893
50273
|
const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
|
|
48894
|
-
[Buffer.from("referral_ata"),
|
|
48895
|
-
|
|
50274
|
+
[Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
|
|
50275
|
+
REFERRAL_PROGRAM_ID
|
|
48896
50276
|
);
|
|
48897
50277
|
return feeAccount.toBase58();
|
|
48898
50278
|
};
|
|
50279
|
+
var checkFeeAccount = async (connection, mint) => {
|
|
50280
|
+
const feeAccount = getFeeAccount(mint);
|
|
50281
|
+
const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
|
|
50282
|
+
return { feeAccount, hasFeeAccount };
|
|
50283
|
+
};
|
|
48899
50284
|
function deserializeJupiterInstruction(instruction) {
|
|
48900
50285
|
return new web3_js.TransactionInstruction({
|
|
48901
50286
|
programId: new web3_js.PublicKey(instruction.programId),
|
|
@@ -48907,17 +50292,26 @@ function deserializeJupiterInstruction(instruction) {
|
|
|
48907
50292
|
data: Buffer.from(instruction.data, "base64")
|
|
48908
50293
|
});
|
|
48909
50294
|
}
|
|
50295
|
+
function toJupiterConfig(apiConfig) {
|
|
50296
|
+
if (!apiConfig) return void 0;
|
|
50297
|
+
return {
|
|
50298
|
+
basePath: apiConfig.basePath,
|
|
50299
|
+
apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
|
|
50300
|
+
headers: apiConfig.headers
|
|
50301
|
+
};
|
|
50302
|
+
}
|
|
48910
50303
|
var getJupiterSwapIxsForFlashloan = async ({
|
|
48911
50304
|
quoteParams,
|
|
48912
50305
|
authority,
|
|
48913
50306
|
connection,
|
|
48914
50307
|
destinationTokenAccount,
|
|
48915
|
-
|
|
50308
|
+
apiConfig,
|
|
50309
|
+
maxSwapAccounts
|
|
48916
50310
|
}) => {
|
|
50311
|
+
const configParams = toJupiterConfig(apiConfig);
|
|
48917
50312
|
const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
|
|
48918
50313
|
const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
|
|
48919
|
-
const feeAccount =
|
|
48920
|
-
const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
|
|
50314
|
+
const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
|
|
48921
50315
|
const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
|
|
48922
50316
|
let finalQuoteParams = quoteParams;
|
|
48923
50317
|
if (!hasFeeAccount) {
|
|
@@ -48927,67 +50321,44 @@ var getJupiterSwapIxsForFlashloan = async ({
|
|
|
48927
50321
|
platformFeeBps: void 0
|
|
48928
50322
|
};
|
|
48929
50323
|
}
|
|
48930
|
-
const
|
|
48931
|
-
const
|
|
48932
|
-
|
|
48933
|
-
|
|
48934
|
-
|
|
48935
|
-
|
|
48936
|
-
|
|
48937
|
-
|
|
48938
|
-
|
|
48939
|
-
|
|
48940
|
-
|
|
48941
|
-
|
|
48942
|
-
|
|
48943
|
-
|
|
48944
|
-
|
|
48945
|
-
userPublicKey: authority.toBase58(),
|
|
48946
|
-
feeAccount: hasFeeAccount ? feeAccount : void 0,
|
|
48947
|
-
wrapAndUnwrapSol: false,
|
|
48948
|
-
destinationTokenAccount: destinationTokenAccount.toBase58()
|
|
48949
|
-
}
|
|
48950
|
-
})
|
|
48951
|
-
)
|
|
48952
|
-
);
|
|
48953
|
-
const lutAddresses = swapInstructionResponses.map(
|
|
48954
|
-
(swapInstructionResponse) => swapInstructionResponse.addressLookupTableAddresses
|
|
48955
|
-
);
|
|
50324
|
+
const maxAccounts = maxSwapAccounts ?? 40;
|
|
50325
|
+
const swapQuote = await jupiterApiClient.quoteGet({
|
|
50326
|
+
...finalQuoteParams,
|
|
50327
|
+
maxAccounts
|
|
50328
|
+
});
|
|
50329
|
+
const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
|
|
50330
|
+
swapRequest: {
|
|
50331
|
+
quoteResponse: swapQuote,
|
|
50332
|
+
userPublicKey: authority.toBase58(),
|
|
50333
|
+
feeAccount: hasFeeAccount ? feeAccount : void 0,
|
|
50334
|
+
wrapAndUnwrapSol: false,
|
|
50335
|
+
destinationTokenAccount: destinationTokenAccount.toBase58()
|
|
50336
|
+
}
|
|
50337
|
+
});
|
|
50338
|
+
const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
|
|
48956
50339
|
const lutAccountsRaw = await connection.getMultipleAccountsInfo(
|
|
48957
|
-
lutAddresses.
|
|
50340
|
+
lutAddresses.map((address) => new web3_js.PublicKey(address))
|
|
48958
50341
|
);
|
|
48959
|
-
|
|
48960
|
-
|
|
48961
|
-
|
|
48962
|
-
|
|
48963
|
-
|
|
48964
|
-
|
|
48965
|
-
|
|
48966
|
-
|
|
48967
|
-
const addressesStartIndex = currentIndex;
|
|
48968
|
-
const addressesEndIndex = addressesStartIndex + addressesLength;
|
|
48969
|
-
currentIndex = addressesEndIndex;
|
|
48970
|
-
const lutAccounts = lutAccountsRaw.slice(addressesStartIndex, addressesEndIndex);
|
|
48971
|
-
const addressLookupTableAccounts = lutAccounts.map((accountInfo, index) => {
|
|
48972
|
-
const addressLookupTableAddress = address[index];
|
|
48973
|
-
if (!accountInfo || !addressLookupTableAddress) {
|
|
48974
|
-
return null;
|
|
48975
|
-
}
|
|
48976
|
-
return new web3_js.AddressLookupTableAccount({
|
|
48977
|
-
key: new web3_js.PublicKey(addressLookupTableAddress),
|
|
48978
|
-
state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
|
|
48979
|
-
});
|
|
48980
|
-
}).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
|
|
48981
|
-
const instruction = deserializeJupiterInstruction(response.swapInstruction);
|
|
48982
|
-
const setupInstructions = response.setupInstructions.map(deserializeJupiterInstruction);
|
|
48983
|
-
jupiterSwapIxs.push({
|
|
48984
|
-
swapInstruction: instruction,
|
|
48985
|
-
setupInstructions,
|
|
48986
|
-
addressLookupTableAddresses: addressLookupTableAccounts,
|
|
48987
|
-
quoteResponse: quote
|
|
50342
|
+
const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
|
|
50343
|
+
const addressLookupTableAddress = lutAddresses[index];
|
|
50344
|
+
if (!accountInfo || !addressLookupTableAddress) {
|
|
50345
|
+
return null;
|
|
50346
|
+
}
|
|
50347
|
+
return new web3_js.AddressLookupTableAccount({
|
|
50348
|
+
key: new web3_js.PublicKey(addressLookupTableAddress),
|
|
50349
|
+
state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
|
|
48988
50350
|
});
|
|
48989
|
-
}
|
|
48990
|
-
|
|
50351
|
+
}).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
|
|
50352
|
+
const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
|
|
50353
|
+
const setupInstructions = swapInstructionResponse.setupInstructions.map(
|
|
50354
|
+
deserializeJupiterInstruction
|
|
50355
|
+
);
|
|
50356
|
+
return {
|
|
50357
|
+
swapInstructions: [instruction],
|
|
50358
|
+
setupInstructions,
|
|
50359
|
+
addressLookupTableAddresses: addressLookupTableAccounts,
|
|
50360
|
+
quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
|
|
50361
|
+
};
|
|
48991
50362
|
};
|
|
48992
50363
|
|
|
48993
50364
|
// src/services/account/utils/misc.utils.ts
|
|
@@ -50208,7 +51579,7 @@ function computeMaxLeverage(depositBank, borrowBank, opts) {
|
|
|
50208
51579
|
ltv
|
|
50209
51580
|
};
|
|
50210
51581
|
}
|
|
50211
|
-
function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank,
|
|
51582
|
+
function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositPriceUsd, borrowPriceUsd, opts) {
|
|
50212
51583
|
const initialCollateral = toBigNumber(principal);
|
|
50213
51584
|
const { maxLeverage } = computeMaxLeverage(depositBank, borrowBank, opts);
|
|
50214
51585
|
let clampedLeverage = targetLeverage;
|
|
@@ -50223,7 +51594,7 @@ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank
|
|
|
50223
51594
|
}
|
|
50224
51595
|
const totalDepositAmount = initialCollateral.times(new BigNumber3__default.default(clampedLeverage));
|
|
50225
51596
|
const additionalDepositAmount = totalDepositAmount.minus(initialCollateral);
|
|
50226
|
-
const totalBorrowAmount = additionalDepositAmount.times(
|
|
51597
|
+
const totalBorrowAmount = additionalDepositAmount.times(new BigNumber3__default.default(depositPriceUsd)).div(new BigNumber3__default.default(borrowPriceUsd));
|
|
50227
51598
|
return {
|
|
50228
51599
|
totalBorrowAmount: totalBorrowAmount.decimalPlaces(
|
|
50229
51600
|
borrowBank.mintDecimals,
|
|
@@ -52690,7 +54061,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52690
54061
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52691
54062
|
* @param params.depositOpts - Deposit configuration (bank, amount, mode)
|
|
52692
54063
|
* @param params.borrowOpts - Borrow configuration (bank, amount)
|
|
52693
|
-
* @param params.swapOpts -
|
|
54064
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52694
54065
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52695
54066
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52696
54067
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52728,7 +54099,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52728
54099
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52729
54100
|
* @param params.withdrawOpts - Withdraw configuration (bank, amount)
|
|
52730
54101
|
* @param params.repayOpts - Repay configuration (bank, optional amount)
|
|
52731
|
-
* @param params.swapOpts -
|
|
54102
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52732
54103
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52733
54104
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52734
54105
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52768,7 +54139,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52768
54139
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52769
54140
|
* @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
|
|
52770
54141
|
* @param params.depositOpts - Deposit configuration (bank, tokenProgram)
|
|
52771
|
-
* @param params.swapOpts -
|
|
54142
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52772
54143
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52773
54144
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52774
54145
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52808,7 +54179,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52808
54179
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52809
54180
|
* @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
|
|
52810
54181
|
* @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
|
|
52811
|
-
* @param params.swapOpts -
|
|
54182
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52812
54183
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52813
54184
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52814
54185
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -54156,6 +55527,7 @@ exports.MARGINFI_PROGRAM = MARGINFI_PROGRAM;
|
|
|
54156
55527
|
exports.MARGINFI_PROGRAM_STAGING = MARGINFI_PROGRAM_STAGING;
|
|
54157
55528
|
exports.MARGINFI_PROGRAM_STAGING_ALT = MARGINFI_PROGRAM_STAGING_ALT;
|
|
54158
55529
|
exports.MARGINFI_SPONSORED_SHARD_ID = MARGINFI_SPONSORED_SHARD_ID;
|
|
55530
|
+
exports.MAX_ACCOUNT_LOCKS = MAX_ACCOUNT_LOCKS;
|
|
54159
55531
|
exports.MAX_CONFIDENCE_INTERVAL_RATIO = MAX_CONFIDENCE_INTERVAL_RATIO;
|
|
54160
55532
|
exports.MAX_TX_SIZE = MAX_TX_SIZE;
|
|
54161
55533
|
exports.MAX_U64 = MAX_U64;
|
|
@@ -54191,6 +55563,7 @@ exports.SYSTEM_PROGRAM_ID = SYSTEM_PROGRAM_ID;
|
|
|
54191
55563
|
exports.SYSVAR_CLOCK_ID = SYSVAR_CLOCK_ID;
|
|
54192
55564
|
exports.SYSVAR_RENT_ID = SYSVAR_RENT_ID;
|
|
54193
55565
|
exports.SYSVAR_STAKE_HISTORY_ID = SYSVAR_STAKE_HISTORY_ID;
|
|
55566
|
+
exports.SwapProvider = SwapProvider;
|
|
54194
55567
|
exports.TRANSFER_ACCOUNT_AUTHORITY_FLAG = TRANSFER_ACCOUNT_AUTHORITY_FLAG;
|
|
54195
55568
|
exports.TransactionArenaKeyMap = TransactionArenaKeyMap;
|
|
54196
55569
|
exports.TransactionBuildingError = TransactionBuildingError;
|
|
@@ -54224,6 +55597,7 @@ exports.checkMultipleOraclesCrankability = checkMultipleOraclesCrankability;
|
|
|
54224
55597
|
exports.chunkedGetRawMultipleAccountInfoOrdered = chunkedGetRawMultipleAccountInfoOrdered;
|
|
54225
55598
|
exports.chunkedGetRawMultipleAccountInfoOrderedWithNulls = chunkedGetRawMultipleAccountInfoOrderedWithNulls;
|
|
54226
55599
|
exports.chunkedGetRawMultipleAccountInfos = chunkedGetRawMultipleAccountInfos;
|
|
55600
|
+
exports.compileFlashloanPrecheck = compileFlashloanPrecheck;
|
|
54227
55601
|
exports.composeRemainingAccounts = composeRemainingAccounts;
|
|
54228
55602
|
exports.computeAccountValue = computeAccountValue;
|
|
54229
55603
|
exports.computeActiveEmodePairs = computeActiveEmodePairs;
|
|
@@ -54234,6 +55608,8 @@ exports.computeBaseInterestRate = computeBaseInterestRate;
|
|
|
54234
55608
|
exports.computeClaimedEmissions = computeClaimedEmissions;
|
|
54235
55609
|
exports.computeClosePositionTokenAmount = computeClosePositionTokenAmount;
|
|
54236
55610
|
exports.computeEmodeImpacts = computeEmodeImpacts;
|
|
55611
|
+
exports.computeFlashLoanNonSwapBudget = computeFlashLoanNonSwapBudget;
|
|
55612
|
+
exports.computeFlashloanSwapConstraints = computeFlashloanSwapConstraints;
|
|
54237
55613
|
exports.computeFreeCollateralFromBalances = computeFreeCollateralFromBalances;
|
|
54238
55614
|
exports.computeFreeCollateralFromCache = computeFreeCollateralFromCache;
|
|
54239
55615
|
exports.computeHealthAccountMetas = computeHealthAccountMetas;
|
|
@@ -54262,6 +55638,7 @@ exports.computeTotalOutstandingEmissions = computeTotalOutstandingEmissions;
|
|
|
54262
55638
|
exports.computeTvl = computeTvl;
|
|
54263
55639
|
exports.computeUsdValue = computeUsdValue;
|
|
54264
55640
|
exports.computeUtilizationRate = computeUtilizationRate;
|
|
55641
|
+
exports.computeV0TxSize = computeV0TxSize;
|
|
54265
55642
|
exports.convertVoteAccCoeffsToBankCoeffs = convertVoteAccCoeffsToBankCoeffs;
|
|
54266
55643
|
exports.createActiveEmodePairFromPairs = createActiveEmodePairFromPairs;
|
|
54267
55644
|
exports.createEmptyBalance = createEmptyBalance;
|
|
@@ -54337,6 +55714,7 @@ exports.getDriftCTokenMultiplier = getDriftCTokenMultiplier;
|
|
|
54337
55714
|
exports.getDriftMetadata = getDriftMetadata;
|
|
54338
55715
|
exports.getDriftStatesDto = getDriftStatesDto;
|
|
54339
55716
|
exports.getEmodePairs = getEmodePairs;
|
|
55717
|
+
exports.getExactOutEstimate = getExactOutEstimate;
|
|
54340
55718
|
exports.getHealthCacheStatusDescription = getHealthCacheStatusDescription;
|
|
54341
55719
|
exports.getHealthSimulationTransactions = getHealthSimulationTransactions;
|
|
54342
55720
|
exports.getJupLendFTokenMultiplier = getJupLendFTokenMultiplier;
|
|
@@ -54355,10 +55733,15 @@ exports.getOracleSourceNameFromKey = getOracleSourceNameFromKey;
|
|
|
54355
55733
|
exports.getPrice = getPrice;
|
|
54356
55734
|
exports.getPriceWithConfidence = getPriceWithConfidence;
|
|
54357
55735
|
exports.getStakedBankMetadataMap = getStakedBankMetadataMap;
|
|
55736
|
+
exports.getSwapIxsForFlashloan = getSwapIxsForFlashloan;
|
|
55737
|
+
exports.getTitanExactOutEstimate = getTitanExactOutEstimate;
|
|
55738
|
+
exports.getTitanSwapIxsForFlashloan = getTitanSwapIxsForFlashloan;
|
|
55739
|
+
exports.getTotalAccountKeys = getTotalAccountKeys;
|
|
54358
55740
|
exports.getTotalAssetQuantity = getTotalAssetQuantity;
|
|
54359
55741
|
exports.getTotalLiabilityQuantity = getTotalLiabilityQuantity;
|
|
54360
55742
|
exports.getTxSize = getTxSize;
|
|
54361
55743
|
exports.getValidatorVoteAccountByBank = getValidatorVoteAccountByBank;
|
|
55744
|
+
exports.getWritableAccountKeys = getWritableAccountKeys;
|
|
54362
55745
|
exports.groupToDto = groupToDto;
|
|
54363
55746
|
exports.hasAccountFlag = hasAccountFlag;
|
|
54364
55747
|
exports.hasEmodeEntryFlag = hasEmodeEntryFlag;
|
|
@@ -54427,6 +55810,7 @@ exports.makeWithdrawIx = makeWithdrawIx3;
|
|
|
54427
55810
|
exports.makeWithdrawTx = makeWithdrawTx;
|
|
54428
55811
|
exports.makeWrapSolIxs = makeWrapSolIxs;
|
|
54429
55812
|
exports.mapBrokenFeedsToOraclePrices = mapBrokenFeedsToOraclePrices;
|
|
55813
|
+
exports.mapJupiterQuoteToSwapQuoteResult = mapJupiterQuoteToSwapQuoteResult;
|
|
54430
55814
|
exports.mapPythBanksToOraclePrices = mapPythBanksToOraclePrices;
|
|
54431
55815
|
exports.mapSwbBanksToOraclePrices = mapSwbBanksToOraclePrices;
|
|
54432
55816
|
exports.marginfiAccountToDto = marginfiAccountToDto;
|
|
@@ -54463,6 +55847,7 @@ exports.toBankDto = toBankDto;
|
|
|
54463
55847
|
exports.toBigNumber = toBigNumber;
|
|
54464
55848
|
exports.toEmodeSettingsDto = toEmodeSettingsDto;
|
|
54465
55849
|
exports.toInterestRateConfigDto = toInterestRateConfigDto;
|
|
55850
|
+
exports.toJupiterConfig = toJupiterConfig;
|
|
54466
55851
|
exports.toNumber = toNumber;
|
|
54467
55852
|
exports.uiToNative = uiToNative;
|
|
54468
55853
|
exports.uiToNativeBigNumber = uiToNativeBigNumber;
|