@0dotxyz/p0-ts-sdk 2.2.0-alpha.4 → 2.2.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2245 -911
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +374 -176
- package/dist/index.d.ts +374 -176
- package/dist/index.js +2231 -913
- package/dist/index.js.map +1 -1
- package/dist/vendor.cjs +365 -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 +356 -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
|
|
|
@@ -115,12 +118,15 @@ function getConfig(environment = "production", overrides) {
|
|
|
115
118
|
|
|
116
119
|
// src/errors/transaction-building.errors.ts
|
|
117
120
|
var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCode2) => {
|
|
118
|
-
TransactionBuildingErrorCode2["
|
|
119
|
-
TransactionBuildingErrorCode2["
|
|
121
|
+
TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_LOOP"] = "SWAP_SIZE_EXCEEDED_LOOP";
|
|
122
|
+
TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_REPAY"] = "SWAP_SIZE_EXCEEDED_REPAY";
|
|
123
|
+
TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_POSITION_SWAP"] = "SWAP_SIZE_EXCEEDED_POSITION_SWAP";
|
|
120
124
|
TransactionBuildingErrorCode2["ORACLE_CRANK_FAILED"] = "ORACLE_CRANK_FAILED";
|
|
121
125
|
TransactionBuildingErrorCode2["KAMINO_RESERVE_NOT_FOUND"] = "KAMINO_RESERVE_NOT_FOUND";
|
|
122
126
|
TransactionBuildingErrorCode2["DRIFT_STATE_NOT_FOUND"] = "DRIFT_STATE_NOT_FOUND";
|
|
123
127
|
TransactionBuildingErrorCode2["JUPLEND_STATE_NOT_FOUND"] = "JUPLEND_STATE_NOT_FOUND";
|
|
128
|
+
TransactionBuildingErrorCode2["SWITCHBOARD_FEED_UPDATE_FAILED"] = "SWITCHBOARD_FEED_UPDATE_FAILED";
|
|
129
|
+
TransactionBuildingErrorCode2["SWAP_QUOTE_FAILED"] = "SWAP_QUOTE_FAILED";
|
|
124
130
|
return TransactionBuildingErrorCode2;
|
|
125
131
|
})(TransactionBuildingErrorCode || {});
|
|
126
132
|
var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
@@ -135,21 +141,25 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
135
141
|
Error.captureStackTrace(this, _TransactionBuildingError);
|
|
136
142
|
}
|
|
137
143
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
static swapSizeExceededLoop(bytes, accountKeys, provider) {
|
|
145
|
+
return new _TransactionBuildingError(
|
|
146
|
+
"SWAP_SIZE_EXCEEDED_LOOP" /* SWAP_SIZE_EXCEEDED_LOOP */,
|
|
147
|
+
`${provider ?? "Swap"} instruction size exceeds available transaction size`,
|
|
148
|
+
{ bytes, accountKeys, provider }
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
static swapSizeExceededRepay(bytes, accountKeys, provider) {
|
|
142
152
|
return new _TransactionBuildingError(
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
{ bytes, accountKeys }
|
|
153
|
+
"SWAP_SIZE_EXCEEDED_REPAY" /* SWAP_SIZE_EXCEEDED_REPAY */,
|
|
154
|
+
`${provider ?? "Swap"} instruction size exceeds available transaction size`,
|
|
155
|
+
{ bytes, accountKeys, provider }
|
|
146
156
|
);
|
|
147
157
|
}
|
|
148
|
-
static
|
|
158
|
+
static swapSizeExceededPositionSwap(bytes, accountKeys, provider) {
|
|
149
159
|
return new _TransactionBuildingError(
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
{ bytes, accountKeys }
|
|
160
|
+
"SWAP_SIZE_EXCEEDED_POSITION_SWAP" /* SWAP_SIZE_EXCEEDED_POSITION_SWAP */,
|
|
161
|
+
`${provider ?? "Swap"} instruction size exceeds available transaction size`,
|
|
162
|
+
{ bytes, accountKeys, provider }
|
|
153
163
|
);
|
|
154
164
|
}
|
|
155
165
|
/**
|
|
@@ -193,6 +203,26 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
193
203
|
{ bankAddress, bankMint, bankSymbol }
|
|
194
204
|
);
|
|
195
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Failed to update Switchboard price feeds
|
|
208
|
+
*/
|
|
209
|
+
static switchboardFeedUpdateFailed(oracleKeys, reason) {
|
|
210
|
+
return new _TransactionBuildingError(
|
|
211
|
+
"SWITCHBOARD_FEED_UPDATE_FAILED" /* SWITCHBOARD_FEED_UPDATE_FAILED */,
|
|
212
|
+
`Switchboard feed update failed: ${reason}`,
|
|
213
|
+
{ oracleKeys, reason }
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Failed to get a swap quote from any provider
|
|
218
|
+
*/
|
|
219
|
+
static swapQuoteFailed(provider, inputMint, outputMint, reason) {
|
|
220
|
+
return new _TransactionBuildingError(
|
|
221
|
+
"SWAP_QUOTE_FAILED" /* SWAP_QUOTE_FAILED */,
|
|
222
|
+
`${provider} swap quote failed for ${inputMint} \u2192 ${outputMint}: ${reason}`,
|
|
223
|
+
{ provider, inputMint, outputMint, reason }
|
|
224
|
+
);
|
|
225
|
+
}
|
|
196
226
|
/**
|
|
197
227
|
* Generic escape hatch for custom errors
|
|
198
228
|
*/
|
|
@@ -345,6 +375,7 @@ var MAX_U64 = BigInt("18446744073709551615").toString();
|
|
|
345
375
|
|
|
346
376
|
// src/constants/transaction.consts.ts
|
|
347
377
|
var MAX_TX_SIZE = 1232;
|
|
378
|
+
var MAX_ACCOUNT_LOCKS = 64;
|
|
348
379
|
var BUNDLE_TX_SIZE = 81;
|
|
349
380
|
var PRIORITY_TX_SIZE = 44;
|
|
350
381
|
var WSOL_MINT = new web3_js.PublicKey("So11111111111111111111111111111111111111112");
|
|
@@ -14893,8 +14924,40 @@ function getTxSize(tx) {
|
|
|
14893
14924
|
const signaturesSize = (numRequiredSignatures - numSigners) * 64 + 1;
|
|
14894
14925
|
try {
|
|
14895
14926
|
const baseTxSize = isVersioned ? tx.serialize().length : tx.serialize({ requireAllSignatures: false, verifySignatures: false }).length;
|
|
14896
|
-
|
|
14897
|
-
|
|
14927
|
+
const totalSize = baseTxSize + feePayerSize + signaturesSize;
|
|
14928
|
+
if (isVersioned && totalSize > 1232) {
|
|
14929
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14930
|
+
const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
14931
|
+
const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
|
|
14932
|
+
console.warn("[getTxSize] oversized TX", {
|
|
14933
|
+
totalSize,
|
|
14934
|
+
overshoot: totalSize - 1232,
|
|
14935
|
+
staticKeys: staticAccountKeys.length,
|
|
14936
|
+
numSignatures: header.numRequiredSignatures,
|
|
14937
|
+
numLuts: addressTableLookups.length,
|
|
14938
|
+
lutWritable,
|
|
14939
|
+
lutReadonly,
|
|
14940
|
+
totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
|
|
14941
|
+
});
|
|
14942
|
+
}
|
|
14943
|
+
return totalSize;
|
|
14944
|
+
} catch (err) {
|
|
14945
|
+
if (isVersioned) {
|
|
14946
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14947
|
+
const lutWritable = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
14948
|
+
const lutReadonly = addressTableLookups.reduce((s, l) => s + l.readonlyIndexes.length, 0);
|
|
14949
|
+
console.warn("[getTxSize] serialize failed", {
|
|
14950
|
+
error: err.message,
|
|
14951
|
+
staticKeys: staticAccountKeys.length,
|
|
14952
|
+
numSignatures: header.numRequiredSignatures,
|
|
14953
|
+
numLuts: addressTableLookups.length,
|
|
14954
|
+
lutWritable,
|
|
14955
|
+
lutReadonly,
|
|
14956
|
+
totalAccounts: staticAccountKeys.length + lutWritable + lutReadonly
|
|
14957
|
+
});
|
|
14958
|
+
} else {
|
|
14959
|
+
console.warn("[getTxSize] serialize failed", { error: err.message });
|
|
14960
|
+
}
|
|
14898
14961
|
return 9999;
|
|
14899
14962
|
}
|
|
14900
14963
|
}
|
|
@@ -14909,6 +14972,47 @@ function getAccountKeys(tx, lookupTableAccounts) {
|
|
|
14909
14972
|
} else {
|
|
14910
14973
|
return tx.compileMessage().getAccountKeys().length;
|
|
14911
14974
|
}
|
|
14975
|
+
} catch (err) {
|
|
14976
|
+
console.warn("[getAccountKeys] decompile failed", { error: err.message });
|
|
14977
|
+
return 9999;
|
|
14978
|
+
}
|
|
14979
|
+
}
|
|
14980
|
+
function getWritableAccountKeys(tx) {
|
|
14981
|
+
const isVersioned = isV0Tx(tx);
|
|
14982
|
+
try {
|
|
14983
|
+
if (isVersioned) {
|
|
14984
|
+
const { header, staticAccountKeys, addressTableLookups } = tx.message;
|
|
14985
|
+
const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
|
|
14986
|
+
const writableLut = addressTableLookups.reduce(
|
|
14987
|
+
(sum, lookup) => sum + lookup.writableIndexes.length,
|
|
14988
|
+
0
|
|
14989
|
+
);
|
|
14990
|
+
return writableStatic + writableLut;
|
|
14991
|
+
} else {
|
|
14992
|
+
const message = tx.compileMessage();
|
|
14993
|
+
const { numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts } = message.header;
|
|
14994
|
+
const totalKeys = message.accountKeys.length;
|
|
14995
|
+
const writableSigned = numRequiredSignatures - numReadonlySignedAccounts;
|
|
14996
|
+
const writableUnsigned = totalKeys - numRequiredSignatures - numReadonlyUnsignedAccounts;
|
|
14997
|
+
return writableSigned + writableUnsigned;
|
|
14998
|
+
}
|
|
14999
|
+
} catch {
|
|
15000
|
+
return 9999;
|
|
15001
|
+
}
|
|
15002
|
+
}
|
|
15003
|
+
function getTotalAccountKeys(tx) {
|
|
15004
|
+
const isVersioned = isV0Tx(tx);
|
|
15005
|
+
try {
|
|
15006
|
+
if (isVersioned) {
|
|
15007
|
+
const { staticAccountKeys, addressTableLookups } = tx.message;
|
|
15008
|
+
const lutAccounts = addressTableLookups.reduce(
|
|
15009
|
+
(sum, lookup) => sum + lookup.writableIndexes.length + lookup.readonlyIndexes.length,
|
|
15010
|
+
0
|
|
15011
|
+
);
|
|
15012
|
+
return staticAccountKeys.length + lutAccounts;
|
|
15013
|
+
} else {
|
|
15014
|
+
return tx.compileMessage().accountKeys.length;
|
|
15015
|
+
}
|
|
14912
15016
|
} catch {
|
|
14913
15017
|
return 9999;
|
|
14914
15018
|
}
|
|
@@ -20146,6 +20250,14 @@ var HealthCacheSimulationError = class _HealthCacheSimulationError extends Error
|
|
|
20146
20250
|
}
|
|
20147
20251
|
};
|
|
20148
20252
|
|
|
20253
|
+
// src/services/account/types/action.types.ts
|
|
20254
|
+
var SwapProvider = /* @__PURE__ */ ((SwapProvider2) => {
|
|
20255
|
+
SwapProvider2["JUPITER"] = "JUPITER";
|
|
20256
|
+
SwapProvider2["TITAN"] = "TITAN";
|
|
20257
|
+
SwapProvider2["DFLOW"] = "DFLOW";
|
|
20258
|
+
return SwapProvider2;
|
|
20259
|
+
})(SwapProvider || {});
|
|
20260
|
+
|
|
20149
20261
|
// src/services/account/utils/deserialize.utils.ts
|
|
20150
20262
|
var EMPTY_HEALTH_CACHE = {
|
|
20151
20263
|
assetValue: {
|
|
@@ -44194,6 +44306,346 @@ function makeUpdateJupLendRate({ lendingState }) {
|
|
|
44194
44306
|
lendingState.rewardsRateModel
|
|
44195
44307
|
);
|
|
44196
44308
|
}
|
|
44309
|
+
var SUBPROTOCOL = "v1.api.titan.ag";
|
|
44310
|
+
var UINT64_MAX = (1n << 64n) - 1n;
|
|
44311
|
+
function toBigInt(value) {
|
|
44312
|
+
if (typeof value === "bigint") {
|
|
44313
|
+
if (value < 0n || value > UINT64_MAX) {
|
|
44314
|
+
throw new RangeError(`Amount out of uint64 range: ${value}`);
|
|
44315
|
+
}
|
|
44316
|
+
return value;
|
|
44317
|
+
}
|
|
44318
|
+
if (!Number.isInteger(value)) {
|
|
44319
|
+
throw new TypeError(`Amount must be a whole number, got ${value}`);
|
|
44320
|
+
}
|
|
44321
|
+
if (value < 0) {
|
|
44322
|
+
throw new RangeError(`Amount must be non-negative, got ${value}`);
|
|
44323
|
+
}
|
|
44324
|
+
return BigInt(value);
|
|
44325
|
+
}
|
|
44326
|
+
var ConnectionClosed = class _ConnectionClosed extends Error {
|
|
44327
|
+
code;
|
|
44328
|
+
reason;
|
|
44329
|
+
constructor(code, reason) {
|
|
44330
|
+
super(`Client WebSocket closed with code ${code}: ${reason}`);
|
|
44331
|
+
this.name = "ConnectionClosed";
|
|
44332
|
+
Object.setPrototypeOf(this, _ConnectionClosed.prototype);
|
|
44333
|
+
this.code = code;
|
|
44334
|
+
this.reason = reason;
|
|
44335
|
+
}
|
|
44336
|
+
};
|
|
44337
|
+
var ErrorResponse = class _ErrorResponse extends Error {
|
|
44338
|
+
response;
|
|
44339
|
+
constructor(response) {
|
|
44340
|
+
super(`Request ${response.requestId} failed with code ${response.code}: ${response.message}`);
|
|
44341
|
+
this.name = "ErrorResponse";
|
|
44342
|
+
Object.setPrototypeOf(this, _ErrorResponse.prototype);
|
|
44343
|
+
this.response = response;
|
|
44344
|
+
}
|
|
44345
|
+
};
|
|
44346
|
+
var StreamError = class _StreamError extends Error {
|
|
44347
|
+
streamId;
|
|
44348
|
+
errorCode;
|
|
44349
|
+
errorMessage;
|
|
44350
|
+
constructor(packet) {
|
|
44351
|
+
const code = packet.errorCode ?? 0;
|
|
44352
|
+
const message = packet.errorMessage ?? "";
|
|
44353
|
+
super(`Stream ${packet.id} ended with error code ${code}: ${message}`);
|
|
44354
|
+
this.name = "StreamError";
|
|
44355
|
+
Object.setPrototypeOf(this, _StreamError.prototype);
|
|
44356
|
+
this.streamId = packet.id;
|
|
44357
|
+
this.errorCode = code;
|
|
44358
|
+
this.errorMessage = message;
|
|
44359
|
+
}
|
|
44360
|
+
};
|
|
44361
|
+
var encoder = new msgpack.Encoder({ useBigInt64: true });
|
|
44362
|
+
var decoder = new msgpack.Decoder({ useBigInt64: true });
|
|
44363
|
+
var V1Client = class _V1Client {
|
|
44364
|
+
socket;
|
|
44365
|
+
nextId = 0;
|
|
44366
|
+
_closed = false;
|
|
44367
|
+
_closing = false;
|
|
44368
|
+
pending = /* @__PURE__ */ new Map();
|
|
44369
|
+
streams = /* @__PURE__ */ new Map();
|
|
44370
|
+
streamStopping = /* @__PURE__ */ new Map();
|
|
44371
|
+
closeListeners = [];
|
|
44372
|
+
// --- Static connect ---
|
|
44373
|
+
static connect(url) {
|
|
44374
|
+
return new Promise((resolve, reject) => {
|
|
44375
|
+
const ws = new WebSocket__default.default(url, [SUBPROTOCOL]);
|
|
44376
|
+
ws.binaryType = "arraybuffer";
|
|
44377
|
+
const onOpen = () => {
|
|
44378
|
+
ws.off("error", onError);
|
|
44379
|
+
ws.off("close", onClose);
|
|
44380
|
+
resolve(new _V1Client(ws));
|
|
44381
|
+
};
|
|
44382
|
+
const onError = (err) => {
|
|
44383
|
+
ws.off("open", onOpen);
|
|
44384
|
+
ws.off("close", onClose);
|
|
44385
|
+
reject(err);
|
|
44386
|
+
};
|
|
44387
|
+
const onClose = (code, reason) => {
|
|
44388
|
+
ws.off("open", onOpen);
|
|
44389
|
+
ws.off("error", onError);
|
|
44390
|
+
reject(
|
|
44391
|
+
new Error(
|
|
44392
|
+
`WebSocket closed before open (code=${code}${reason.length ? `, reason=${reason.toString()}` : ""})`
|
|
44393
|
+
)
|
|
44394
|
+
);
|
|
44395
|
+
};
|
|
44396
|
+
ws.once("open", onOpen);
|
|
44397
|
+
ws.once("error", onError);
|
|
44398
|
+
ws.once("close", onClose);
|
|
44399
|
+
});
|
|
44400
|
+
}
|
|
44401
|
+
// --- Constructor ---
|
|
44402
|
+
constructor(socket) {
|
|
44403
|
+
this.socket = socket;
|
|
44404
|
+
this.socket.on("message", (data) => {
|
|
44405
|
+
this.handleMessage(data);
|
|
44406
|
+
});
|
|
44407
|
+
this.socket.on("close", (code, reason) => {
|
|
44408
|
+
this.handleClose(code, reason.toString());
|
|
44409
|
+
});
|
|
44410
|
+
this.socket.on("error", (err) => {
|
|
44411
|
+
this.handleError(err);
|
|
44412
|
+
});
|
|
44413
|
+
}
|
|
44414
|
+
nextRequestId() {
|
|
44415
|
+
return this.nextId++;
|
|
44416
|
+
}
|
|
44417
|
+
// --- Public API ---
|
|
44418
|
+
get closed() {
|
|
44419
|
+
return this._closed;
|
|
44420
|
+
}
|
|
44421
|
+
close() {
|
|
44422
|
+
if (this._closed) return Promise.resolve();
|
|
44423
|
+
return new Promise((resolve, reject) => {
|
|
44424
|
+
this.closeListeners.push({ resolve, reject });
|
|
44425
|
+
if (!this._closing) {
|
|
44426
|
+
this._closing = true;
|
|
44427
|
+
this.socket.close();
|
|
44428
|
+
}
|
|
44429
|
+
});
|
|
44430
|
+
}
|
|
44431
|
+
newSwapQuoteStream(params) {
|
|
44432
|
+
const requestId = this.nextRequestId();
|
|
44433
|
+
const promise = new Promise(
|
|
44434
|
+
(resolve, reject) => {
|
|
44435
|
+
this.pending.set(requestId, {
|
|
44436
|
+
resolve,
|
|
44437
|
+
reject,
|
|
44438
|
+
kind: "NewSwapQuoteStream"
|
|
44439
|
+
});
|
|
44440
|
+
}
|
|
44441
|
+
);
|
|
44442
|
+
const normalized = {
|
|
44443
|
+
...params,
|
|
44444
|
+
swap: { ...params.swap, amount: toBigInt(params.swap.amount) }
|
|
44445
|
+
};
|
|
44446
|
+
const message = {
|
|
44447
|
+
id: requestId,
|
|
44448
|
+
data: { NewSwapQuoteStream: normalized }
|
|
44449
|
+
};
|
|
44450
|
+
this.send(message);
|
|
44451
|
+
return promise;
|
|
44452
|
+
}
|
|
44453
|
+
stopStream(streamId) {
|
|
44454
|
+
const requestId = this.nextRequestId();
|
|
44455
|
+
const promise = new Promise((resolve, reject) => {
|
|
44456
|
+
this.pending.set(requestId, {
|
|
44457
|
+
resolve,
|
|
44458
|
+
reject,
|
|
44459
|
+
kind: "StopStream"
|
|
44460
|
+
});
|
|
44461
|
+
});
|
|
44462
|
+
const message = {
|
|
44463
|
+
id: requestId,
|
|
44464
|
+
data: { StopStream: { id: streamId } }
|
|
44465
|
+
};
|
|
44466
|
+
this.send(message);
|
|
44467
|
+
return promise;
|
|
44468
|
+
}
|
|
44469
|
+
// --- Send ---
|
|
44470
|
+
send(message) {
|
|
44471
|
+
try {
|
|
44472
|
+
const encoded = encoder.encode(message);
|
|
44473
|
+
this.socket.send(encoded);
|
|
44474
|
+
} catch (err) {
|
|
44475
|
+
const req = this.pending.get(message.id);
|
|
44476
|
+
if (req) {
|
|
44477
|
+
this.pending.delete(message.id);
|
|
44478
|
+
req.reject(err);
|
|
44479
|
+
}
|
|
44480
|
+
}
|
|
44481
|
+
}
|
|
44482
|
+
// --- Message handling ---
|
|
44483
|
+
handleMessage(raw) {
|
|
44484
|
+
let buf;
|
|
44485
|
+
if (raw instanceof ArrayBuffer) {
|
|
44486
|
+
buf = new Uint8Array(raw);
|
|
44487
|
+
} else if (Buffer.isBuffer(raw)) {
|
|
44488
|
+
buf = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
44489
|
+
} else if (Array.isArray(raw)) {
|
|
44490
|
+
buf = new Uint8Array(Buffer.concat(raw));
|
|
44491
|
+
} else {
|
|
44492
|
+
return;
|
|
44493
|
+
}
|
|
44494
|
+
let message;
|
|
44495
|
+
try {
|
|
44496
|
+
message = decoder.decode(buf);
|
|
44497
|
+
} catch {
|
|
44498
|
+
this.socket.close(3002, "failed to decode message");
|
|
44499
|
+
return;
|
|
44500
|
+
}
|
|
44501
|
+
if ("Response" in message) {
|
|
44502
|
+
this.handleResponse(message.Response);
|
|
44503
|
+
} else if ("Error" in message) {
|
|
44504
|
+
this.handleResponseError(message.Error);
|
|
44505
|
+
} else if ("StreamData" in message) {
|
|
44506
|
+
this.handleStreamData(message.StreamData);
|
|
44507
|
+
} else if ("StreamEnd" in message) {
|
|
44508
|
+
this.handleStreamEnd(message.StreamEnd);
|
|
44509
|
+
}
|
|
44510
|
+
}
|
|
44511
|
+
handleResponse(msg) {
|
|
44512
|
+
const req = this.pending.get(msg.requestId);
|
|
44513
|
+
if (!req) return;
|
|
44514
|
+
this.pending.delete(msg.requestId);
|
|
44515
|
+
if ("NewSwapQuoteStream" in msg.data && req.kind === "NewSwapQuoteStream") {
|
|
44516
|
+
const streamInfo = msg.stream;
|
|
44517
|
+
if (!streamInfo) {
|
|
44518
|
+
req.reject(new Error("No stream associated with NewSwapQuoteStream response"));
|
|
44519
|
+
return;
|
|
44520
|
+
}
|
|
44521
|
+
const stream = new ReadableStream({
|
|
44522
|
+
start: (controller) => {
|
|
44523
|
+
this.streams.set(streamInfo.id, controller);
|
|
44524
|
+
},
|
|
44525
|
+
cancel: () => {
|
|
44526
|
+
return this.cancelStream(streamInfo.id);
|
|
44527
|
+
}
|
|
44528
|
+
});
|
|
44529
|
+
const result = {
|
|
44530
|
+
response: msg.data.NewSwapQuoteStream,
|
|
44531
|
+
stream,
|
|
44532
|
+
streamId: streamInfo.id
|
|
44533
|
+
};
|
|
44534
|
+
req.resolve(result);
|
|
44535
|
+
} else if ("StreamStopped" in msg.data && req.kind === "StopStream") {
|
|
44536
|
+
req.resolve(msg.data.StreamStopped);
|
|
44537
|
+
} else {
|
|
44538
|
+
req.reject(new Error(`Unexpected response type for ${req.kind}`));
|
|
44539
|
+
}
|
|
44540
|
+
}
|
|
44541
|
+
handleResponseError(error) {
|
|
44542
|
+
const req = this.pending.get(error.requestId);
|
|
44543
|
+
if (!req) return;
|
|
44544
|
+
this.pending.delete(error.requestId);
|
|
44545
|
+
req.reject(new ErrorResponse(error));
|
|
44546
|
+
}
|
|
44547
|
+
handleStreamData(packet) {
|
|
44548
|
+
const controller = this.streams.get(packet.id);
|
|
44549
|
+
if (!controller) return;
|
|
44550
|
+
if (packet.payload.SwapQuotes !== void 0) {
|
|
44551
|
+
controller.enqueue(packet.payload.SwapQuotes);
|
|
44552
|
+
}
|
|
44553
|
+
}
|
|
44554
|
+
handleStreamEnd(packet) {
|
|
44555
|
+
const controller = this.streams.get(packet.id);
|
|
44556
|
+
if (!controller) return;
|
|
44557
|
+
this.streams.delete(packet.id);
|
|
44558
|
+
this.streamStopping.delete(packet.id);
|
|
44559
|
+
if (packet.errorCode !== void 0) {
|
|
44560
|
+
controller.error(new StreamError(packet));
|
|
44561
|
+
} else {
|
|
44562
|
+
controller.close();
|
|
44563
|
+
}
|
|
44564
|
+
}
|
|
44565
|
+
async cancelStream(streamId) {
|
|
44566
|
+
if (this.streamStopping.get(streamId) || !this.streams.has(streamId)) return;
|
|
44567
|
+
this.streamStopping.set(streamId, true);
|
|
44568
|
+
await this.stopStream(streamId);
|
|
44569
|
+
}
|
|
44570
|
+
// --- Connection lifecycle ---
|
|
44571
|
+
rejectAll(error) {
|
|
44572
|
+
for (const req of this.pending.values()) {
|
|
44573
|
+
req.reject(error);
|
|
44574
|
+
}
|
|
44575
|
+
this.pending.clear();
|
|
44576
|
+
for (const controller of this.streams.values()) {
|
|
44577
|
+
controller.error(error);
|
|
44578
|
+
}
|
|
44579
|
+
this.streams.clear();
|
|
44580
|
+
this.streamStopping.clear();
|
|
44581
|
+
}
|
|
44582
|
+
handleClose(code, reason) {
|
|
44583
|
+
this._closed = true;
|
|
44584
|
+
this.rejectAll(new ConnectionClosed(code, reason));
|
|
44585
|
+
for (const listener of this.closeListeners) {
|
|
44586
|
+
listener.resolve();
|
|
44587
|
+
}
|
|
44588
|
+
this.closeListeners = [];
|
|
44589
|
+
}
|
|
44590
|
+
handleError(err) {
|
|
44591
|
+
this.rejectAll(err);
|
|
44592
|
+
this.socket.close(3002);
|
|
44593
|
+
}
|
|
44594
|
+
};
|
|
44595
|
+
function deserializeSerializedInstruction(ix) {
|
|
44596
|
+
return new web3_js.TransactionInstruction({
|
|
44597
|
+
programId: new web3_js.PublicKey(Buffer.from(ix.p, "base64")),
|
|
44598
|
+
keys: ix.a.map((account) => ({
|
|
44599
|
+
pubkey: new web3_js.PublicKey(Buffer.from(account.p, "base64")),
|
|
44600
|
+
isSigner: account.s,
|
|
44601
|
+
isWritable: account.w
|
|
44602
|
+
})),
|
|
44603
|
+
data: Buffer.from(ix.d, "base64")
|
|
44604
|
+
});
|
|
44605
|
+
}
|
|
44606
|
+
function selectBestRoute(quotes, swapMode) {
|
|
44607
|
+
const routes = Object.values(quotes);
|
|
44608
|
+
if (routes.length === 0) return null;
|
|
44609
|
+
return routes.reduce((best, route) => {
|
|
44610
|
+
if (swapMode === "ExactIn") {
|
|
44611
|
+
return route.outAmount > best.outAmount ? route : best;
|
|
44612
|
+
} else {
|
|
44613
|
+
return route.inAmount < best.inAmount ? route : best;
|
|
44614
|
+
}
|
|
44615
|
+
});
|
|
44616
|
+
}
|
|
44617
|
+
function buildSwapQuoteResult(route, swapMode) {
|
|
44618
|
+
const slippageBps = route.slippageBps;
|
|
44619
|
+
let otherAmountThreshold;
|
|
44620
|
+
if (swapMode === "ExactIn") {
|
|
44621
|
+
otherAmountThreshold = String(Math.floor(route.outAmount * (1 - slippageBps / 1e4)));
|
|
44622
|
+
} else {
|
|
44623
|
+
otherAmountThreshold = String(Math.ceil(route.inAmount * (1 + slippageBps / 1e4)));
|
|
44624
|
+
}
|
|
44625
|
+
return {
|
|
44626
|
+
inAmount: String(route.inAmount),
|
|
44627
|
+
outAmount: String(route.outAmount),
|
|
44628
|
+
otherAmountThreshold,
|
|
44629
|
+
slippageBps,
|
|
44630
|
+
platformFee: route.platformFee ? {
|
|
44631
|
+
amount: String(route.platformFee.amount),
|
|
44632
|
+
feeBps: route.platformFee.fee_bps
|
|
44633
|
+
} : void 0,
|
|
44634
|
+
contextSlot: route.contextSlot,
|
|
44635
|
+
timeTaken: route.timeTaken
|
|
44636
|
+
};
|
|
44637
|
+
}
|
|
44638
|
+
async function resolveLookupTables(connection, lutPubkeys) {
|
|
44639
|
+
if (lutPubkeys.length === 0) return [];
|
|
44640
|
+
const lutAccountsRaw = await connection.getMultipleAccountsInfo(lutPubkeys);
|
|
44641
|
+
return lutAccountsRaw.map((accountInfo, index) => {
|
|
44642
|
+
if (!accountInfo) return null;
|
|
44643
|
+
return new web3_js.AddressLookupTableAccount({
|
|
44644
|
+
key: lutPubkeys[index],
|
|
44645
|
+
state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
|
|
44646
|
+
});
|
|
44647
|
+
}).filter((account) => account !== null);
|
|
44648
|
+
}
|
|
44197
44649
|
|
|
44198
44650
|
// src/vendor/klend/utils/klend/interest-rate.utils.ts
|
|
44199
44651
|
function getKaminoTotalSupply(reserve) {
|
|
@@ -46715,18 +47167,18 @@ async function buildLoopFlashloanTx({
|
|
|
46715
47167
|
overrideInferAccounts,
|
|
46716
47168
|
blockhash
|
|
46717
47169
|
}) {
|
|
46718
|
-
const swapResult = [];
|
|
46719
47170
|
const cuRequestIxs = [
|
|
46720
47171
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
46721
47172
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
46722
47173
|
];
|
|
47174
|
+
let amountToDeposit;
|
|
47175
|
+
let swapInstructions = [];
|
|
47176
|
+
let setupInstructions = [];
|
|
47177
|
+
let swapLookupTables = [];
|
|
47178
|
+
let swapQuote;
|
|
47179
|
+
let sizeConstraintUsed = 0;
|
|
46723
47180
|
if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
|
|
46724
|
-
|
|
46725
|
-
amountToDeposit: borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0),
|
|
46726
|
-
swapInstructions: [],
|
|
46727
|
-
setupInstructions: [],
|
|
46728
|
-
swapLookupTables: []
|
|
46729
|
-
});
|
|
47181
|
+
amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
|
|
46730
47182
|
} else {
|
|
46731
47183
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
46732
47184
|
new web3_js.PublicKey(depositOpts.depositBank.mint),
|
|
@@ -46734,36 +47186,46 @@ async function buildLoopFlashloanTx({
|
|
|
46734
47186
|
true,
|
|
46735
47187
|
depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
46736
47188
|
);
|
|
46737
|
-
const
|
|
46738
|
-
|
|
46739
|
-
|
|
46740
|
-
|
|
46741
|
-
|
|
46742
|
-
|
|
46743
|
-
|
|
46744
|
-
|
|
46745
|
-
|
|
46746
|
-
|
|
47189
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
47190
|
+
program,
|
|
47191
|
+
marginfiAccount,
|
|
47192
|
+
bankMap,
|
|
47193
|
+
bankMetadataMap,
|
|
47194
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
47195
|
+
primaryIx: {
|
|
47196
|
+
type: "borrow",
|
|
47197
|
+
bank: borrowOpts.borrowBank,
|
|
47198
|
+
tokenProgram: borrowOpts.tokenProgram
|
|
47199
|
+
},
|
|
47200
|
+
secondaryIx: {
|
|
47201
|
+
type: "deposit",
|
|
47202
|
+
bank: depositOpts.depositBank,
|
|
47203
|
+
tokenProgram: depositOpts.tokenProgram
|
|
46747
47204
|
},
|
|
47205
|
+
overrideInferAccounts
|
|
47206
|
+
});
|
|
47207
|
+
const swapResponse = await getSwapIxsForFlashloan({
|
|
47208
|
+
inputMint: borrowOpts.borrowBank.mint.toBase58(),
|
|
47209
|
+
outputMint: depositOpts.depositBank.mint.toBase58(),
|
|
47210
|
+
amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
|
|
47211
|
+
swapMode: "ExactIn",
|
|
46748
47212
|
authority: marginfiAccount.authority,
|
|
46749
47213
|
connection,
|
|
46750
47214
|
destinationTokenAccount,
|
|
46751
|
-
|
|
46752
|
-
|
|
46753
|
-
|
|
46754
|
-
const outAmountThreshold = nativeToUi(
|
|
46755
|
-
response.quoteResponse.otherAmountThreshold,
|
|
46756
|
-
depositOpts.depositBank.mintDecimals
|
|
46757
|
-
);
|
|
46758
|
-
const amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
|
|
46759
|
-
swapResult.push({
|
|
46760
|
-
amountToDeposit,
|
|
46761
|
-
swapInstructions: [response.swapInstruction],
|
|
46762
|
-
setupInstructions: response.setupInstructions,
|
|
46763
|
-
swapLookupTables: response.addressLookupTableAddresses,
|
|
46764
|
-
quoteResponse: response.quoteResponse
|
|
46765
|
-
});
|
|
47215
|
+
swapOpts,
|
|
47216
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
47217
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
46766
47218
|
});
|
|
47219
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
47220
|
+
const outAmountThreshold = nativeToUi(
|
|
47221
|
+
swapResponse.quoteResponse.otherAmountThreshold,
|
|
47222
|
+
depositOpts.depositBank.mintDecimals
|
|
47223
|
+
);
|
|
47224
|
+
amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
|
|
47225
|
+
swapInstructions = swapResponse.swapInstructions;
|
|
47226
|
+
setupInstructions = swapResponse.setupInstructions;
|
|
47227
|
+
swapLookupTables = swapResponse.addressLookupTableAddresses;
|
|
47228
|
+
swapQuote = swapResponse.quoteResponse;
|
|
46767
47229
|
}
|
|
46768
47230
|
const borrowIxs = await makeBorrowIx3({
|
|
46769
47231
|
program,
|
|
@@ -46780,140 +47242,136 @@ async function buildLoopFlashloanTx({
|
|
|
46780
47242
|
overrideInferAccounts
|
|
46781
47243
|
}
|
|
46782
47244
|
});
|
|
46783
|
-
|
|
46784
|
-
|
|
46785
|
-
|
|
46786
|
-
|
|
46787
|
-
|
|
46788
|
-
|
|
46789
|
-
|
|
46790
|
-
|
|
46791
|
-
|
|
46792
|
-
|
|
46793
|
-
case 3 /* KAMINO */: {
|
|
46794
|
-
const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
46795
|
-
if (!reserve) {
|
|
46796
|
-
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
46797
|
-
depositOpts.depositBank.address.toBase58(),
|
|
46798
|
-
depositOpts.depositBank.mint.toBase58(),
|
|
46799
|
-
depositOpts.depositBank.tokenSymbol
|
|
46800
|
-
);
|
|
46801
|
-
}
|
|
46802
|
-
depositIxs = await makeKaminoDepositIx3({
|
|
46803
|
-
program,
|
|
46804
|
-
bank: depositOpts.depositBank,
|
|
46805
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
46806
|
-
amount: amountToDeposit,
|
|
46807
|
-
accountAddress: marginfiAccount.address,
|
|
46808
|
-
authority: marginfiAccount.authority,
|
|
46809
|
-
group: marginfiAccount.group,
|
|
46810
|
-
reserve,
|
|
46811
|
-
opts: {
|
|
46812
|
-
wrapAndUnwrapSol: false,
|
|
46813
|
-
overrideInferAccounts
|
|
46814
|
-
}
|
|
46815
|
-
});
|
|
46816
|
-
break;
|
|
47245
|
+
let depositIxs;
|
|
47246
|
+
switch (depositOpts.depositBank.config.assetTag) {
|
|
47247
|
+
case 3 /* KAMINO */: {
|
|
47248
|
+
const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
47249
|
+
if (!reserve) {
|
|
47250
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
47251
|
+
depositOpts.depositBank.address.toBase58(),
|
|
47252
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
47253
|
+
depositOpts.depositBank.tokenSymbol
|
|
47254
|
+
);
|
|
46817
47255
|
}
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
|
|
46822
|
-
|
|
46823
|
-
|
|
46824
|
-
|
|
46825
|
-
|
|
47256
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
47257
|
+
program,
|
|
47258
|
+
bank: depositOpts.depositBank,
|
|
47259
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
47260
|
+
amount: amountToDeposit,
|
|
47261
|
+
accountAddress: marginfiAccount.address,
|
|
47262
|
+
authority: marginfiAccount.authority,
|
|
47263
|
+
group: marginfiAccount.group,
|
|
47264
|
+
reserve,
|
|
47265
|
+
opts: {
|
|
47266
|
+
wrapAndUnwrapSol: false,
|
|
47267
|
+
overrideInferAccounts
|
|
46826
47268
|
}
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
depositIxs = await makeDriftDepositIx3({
|
|
46830
|
-
program,
|
|
46831
|
-
bank: depositOpts.depositBank,
|
|
46832
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
46833
|
-
amount: amountToDeposit,
|
|
46834
|
-
accountAddress: marginfiAccount.address,
|
|
46835
|
-
authority: marginfiAccount.authority,
|
|
46836
|
-
group: marginfiAccount.group,
|
|
46837
|
-
driftMarketIndex,
|
|
46838
|
-
driftOracle,
|
|
46839
|
-
opts: {
|
|
46840
|
-
wrapAndUnwrapSol: false,
|
|
46841
|
-
overrideInferAccounts
|
|
46842
|
-
}
|
|
46843
|
-
});
|
|
46844
|
-
break;
|
|
46845
|
-
}
|
|
46846
|
-
case 6 /* JUPLEND */: {
|
|
46847
|
-
depositIxs = await makeJuplendDepositIx2({
|
|
46848
|
-
program,
|
|
46849
|
-
bank: depositOpts.depositBank,
|
|
46850
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
46851
|
-
amount: amountToDeposit,
|
|
46852
|
-
accountAddress: marginfiAccount.address,
|
|
46853
|
-
authority: marginfiAccount.authority,
|
|
46854
|
-
group: marginfiAccount.group,
|
|
46855
|
-
opts: {
|
|
46856
|
-
wrapAndUnwrapSol: false,
|
|
46857
|
-
overrideInferAccounts
|
|
46858
|
-
}
|
|
46859
|
-
});
|
|
46860
|
-
break;
|
|
46861
|
-
}
|
|
46862
|
-
default: {
|
|
46863
|
-
depositIxs = await makeDepositIx3({
|
|
46864
|
-
program,
|
|
46865
|
-
bank: depositOpts.depositBank,
|
|
46866
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
46867
|
-
amount: amountToDeposit,
|
|
46868
|
-
accountAddress: marginfiAccount.address,
|
|
46869
|
-
authority: marginfiAccount.authority,
|
|
46870
|
-
group: marginfiAccount.group,
|
|
46871
|
-
opts: {
|
|
46872
|
-
wrapAndUnwrapSol: false,
|
|
46873
|
-
overrideInferAccounts
|
|
46874
|
-
}
|
|
46875
|
-
});
|
|
46876
|
-
break;
|
|
46877
|
-
}
|
|
47269
|
+
});
|
|
47270
|
+
break;
|
|
46878
47271
|
}
|
|
46879
|
-
|
|
46880
|
-
|
|
46881
|
-
|
|
46882
|
-
|
|
46883
|
-
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
46888
|
-
...flashloanParams,
|
|
46889
|
-
ixs: [
|
|
46890
|
-
...cuRequestIxs,
|
|
46891
|
-
...borrowIxs.instructions,
|
|
46892
|
-
...swapInstructions,
|
|
46893
|
-
...depositIxs.instructions
|
|
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);
|
|
46902
|
-
} else {
|
|
46903
|
-
continue;
|
|
47272
|
+
case 4 /* DRIFT */: {
|
|
47273
|
+
const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
|
|
47274
|
+
if (!driftState) {
|
|
47275
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
47276
|
+
depositOpts.depositBank.address.toBase58(),
|
|
47277
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
47278
|
+
depositOpts.depositBank.tokenSymbol
|
|
47279
|
+
);
|
|
46904
47280
|
}
|
|
46905
|
-
|
|
46906
|
-
|
|
46907
|
-
|
|
46908
|
-
|
|
46909
|
-
|
|
46910
|
-
|
|
46911
|
-
|
|
46912
|
-
|
|
46913
|
-
|
|
47281
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
47282
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
47283
|
+
depositIxs = await makeDriftDepositIx3({
|
|
47284
|
+
program,
|
|
47285
|
+
bank: depositOpts.depositBank,
|
|
47286
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
47287
|
+
amount: amountToDeposit,
|
|
47288
|
+
accountAddress: marginfiAccount.address,
|
|
47289
|
+
authority: marginfiAccount.authority,
|
|
47290
|
+
group: marginfiAccount.group,
|
|
47291
|
+
driftMarketIndex,
|
|
47292
|
+
driftOracle,
|
|
47293
|
+
opts: {
|
|
47294
|
+
wrapAndUnwrapSol: false,
|
|
47295
|
+
overrideInferAccounts
|
|
47296
|
+
}
|
|
47297
|
+
});
|
|
47298
|
+
break;
|
|
47299
|
+
}
|
|
47300
|
+
case 6 /* JUPLEND */: {
|
|
47301
|
+
depositIxs = await makeJuplendDepositIx2({
|
|
47302
|
+
program,
|
|
47303
|
+
bank: depositOpts.depositBank,
|
|
47304
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
47305
|
+
amount: amountToDeposit,
|
|
47306
|
+
accountAddress: marginfiAccount.address,
|
|
47307
|
+
authority: marginfiAccount.authority,
|
|
47308
|
+
group: marginfiAccount.group,
|
|
47309
|
+
opts: {
|
|
47310
|
+
wrapAndUnwrapSol: false,
|
|
47311
|
+
overrideInferAccounts
|
|
47312
|
+
}
|
|
47313
|
+
});
|
|
47314
|
+
break;
|
|
47315
|
+
}
|
|
47316
|
+
default: {
|
|
47317
|
+
depositIxs = await makeDepositIx3({
|
|
47318
|
+
program,
|
|
47319
|
+
bank: depositOpts.depositBank,
|
|
47320
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
47321
|
+
amount: amountToDeposit,
|
|
47322
|
+
accountAddress: marginfiAccount.address,
|
|
47323
|
+
authority: marginfiAccount.authority,
|
|
47324
|
+
group: marginfiAccount.group,
|
|
47325
|
+
opts: {
|
|
47326
|
+
wrapAndUnwrapSol: false,
|
|
47327
|
+
overrideInferAccounts
|
|
47328
|
+
}
|
|
47329
|
+
});
|
|
47330
|
+
break;
|
|
46914
47331
|
}
|
|
46915
47332
|
}
|
|
46916
|
-
|
|
47333
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
47334
|
+
const allNonFlIxs = [
|
|
47335
|
+
...cuRequestIxs,
|
|
47336
|
+
...borrowIxs.instructions,
|
|
47337
|
+
...swapInstructions,
|
|
47338
|
+
...depositIxs.instructions
|
|
47339
|
+
];
|
|
47340
|
+
if (swapInstructions.length > 0) {
|
|
47341
|
+
compileFlashloanPrecheck({
|
|
47342
|
+
allIxs: allNonFlIxs,
|
|
47343
|
+
payer: marginfiAccount.authority,
|
|
47344
|
+
luts,
|
|
47345
|
+
sizeConstraint: sizeConstraintUsed,
|
|
47346
|
+
swapIxCount: swapInstructions.length,
|
|
47347
|
+
swapLutCount: swapLookupTables.length
|
|
47348
|
+
});
|
|
47349
|
+
}
|
|
47350
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
47351
|
+
program,
|
|
47352
|
+
marginfiAccount,
|
|
47353
|
+
bankMap,
|
|
47354
|
+
addressLookupTableAccounts: luts,
|
|
47355
|
+
blockhash,
|
|
47356
|
+
ixs: allNonFlIxs
|
|
47357
|
+
});
|
|
47358
|
+
const txSize = getTxSize(flashloanTx);
|
|
47359
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
47360
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
47361
|
+
throw TransactionBuildingError.swapSizeExceededLoop(
|
|
47362
|
+
txSize,
|
|
47363
|
+
totalKeys,
|
|
47364
|
+
swapOpts.swapConfig?.provider
|
|
47365
|
+
);
|
|
47366
|
+
}
|
|
47367
|
+
return {
|
|
47368
|
+
flashloanTx,
|
|
47369
|
+
setupInstructions,
|
|
47370
|
+
swapQuote,
|
|
47371
|
+
borrowIxs,
|
|
47372
|
+
depositIxs,
|
|
47373
|
+
amountToDeposit
|
|
47374
|
+
};
|
|
46917
47375
|
}
|
|
46918
47376
|
async function makeRepayIx3({
|
|
46919
47377
|
program,
|
|
@@ -47103,18 +47561,18 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47103
47561
|
overrideInferAccounts,
|
|
47104
47562
|
blockhash
|
|
47105
47563
|
}) {
|
|
47106
|
-
const swapResult = [];
|
|
47107
47564
|
const cuRequestIxs = [
|
|
47108
47565
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47109
47566
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
47110
47567
|
];
|
|
47568
|
+
let amountToRepay;
|
|
47569
|
+
let swapInstructions = [];
|
|
47570
|
+
let setupInstructions = [];
|
|
47571
|
+
let swapLookupTables = [];
|
|
47572
|
+
let swapQuote;
|
|
47573
|
+
let sizeConstraintUsed = 0;
|
|
47111
47574
|
if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
|
|
47112
|
-
|
|
47113
|
-
amountToRepay: withdrawOpts.withdrawAmount,
|
|
47114
|
-
swapInstructions: [],
|
|
47115
|
-
setupInstructions: [],
|
|
47116
|
-
swapLookupTables: []
|
|
47117
|
-
});
|
|
47575
|
+
amountToRepay = withdrawOpts.withdrawAmount;
|
|
47118
47576
|
} else {
|
|
47119
47577
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
47120
47578
|
new web3_js.PublicKey(repayOpts.repayBank.mint),
|
|
@@ -47122,41 +47580,50 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47122
47580
|
true,
|
|
47123
47581
|
repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47124
47582
|
);
|
|
47125
|
-
const
|
|
47126
|
-
|
|
47127
|
-
|
|
47128
|
-
|
|
47129
|
-
|
|
47130
|
-
|
|
47131
|
-
|
|
47132
|
-
|
|
47133
|
-
|
|
47134
|
-
|
|
47135
|
-
|
|
47136
|
-
|
|
47137
|
-
|
|
47583
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
47584
|
+
program,
|
|
47585
|
+
marginfiAccount,
|
|
47586
|
+
bankMap,
|
|
47587
|
+
bankMetadataMap,
|
|
47588
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
47589
|
+
primaryIx: {
|
|
47590
|
+
type: "withdraw",
|
|
47591
|
+
bank: withdrawOpts.withdrawBank,
|
|
47592
|
+
tokenProgram: withdrawOpts.tokenProgram
|
|
47593
|
+
},
|
|
47594
|
+
secondaryIx: {
|
|
47595
|
+
type: "repay",
|
|
47596
|
+
bank: repayOpts.repayBank,
|
|
47597
|
+
tokenProgram: repayOpts.tokenProgram
|
|
47138
47598
|
},
|
|
47599
|
+
overrideInferAccounts
|
|
47600
|
+
});
|
|
47601
|
+
const swapResponse = await getSwapIxsForFlashloan({
|
|
47602
|
+
inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
|
|
47603
|
+
outputMint: repayOpts.repayBank.mint.toBase58(),
|
|
47604
|
+
amount: uiToNative(
|
|
47605
|
+
withdrawOpts.withdrawAmount,
|
|
47606
|
+
withdrawOpts.withdrawBank.mintDecimals
|
|
47607
|
+
).toNumber(),
|
|
47608
|
+
swapMode: "ExactIn",
|
|
47139
47609
|
authority: marginfiAccount.authority,
|
|
47140
47610
|
connection,
|
|
47141
47611
|
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
|
-
});
|
|
47612
|
+
swapOpts,
|
|
47613
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
47614
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47159
47615
|
});
|
|
47616
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
47617
|
+
const { quoteResponse } = swapResponse;
|
|
47618
|
+
const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
|
|
47619
|
+
const outAmountThreshold = nativeToUi(
|
|
47620
|
+
quoteResponse.otherAmountThreshold,
|
|
47621
|
+
repayOpts.repayBank.mintDecimals
|
|
47622
|
+
);
|
|
47623
|
+
amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
|
|
47624
|
+
swapInstructions = swapResponse.swapInstructions;
|
|
47625
|
+
swapLookupTables = swapResponse.addressLookupTableAddresses;
|
|
47626
|
+
swapQuote = quoteResponse;
|
|
47160
47627
|
}
|
|
47161
47628
|
let withdrawIxs;
|
|
47162
47629
|
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
@@ -47294,68 +47761,70 @@ async function buildRepayWithCollatFlashloanTx({
|
|
|
47294
47761
|
break;
|
|
47295
47762
|
}
|
|
47296
47763
|
}
|
|
47297
|
-
|
|
47298
|
-
|
|
47299
|
-
|
|
47300
|
-
|
|
47301
|
-
|
|
47302
|
-
|
|
47303
|
-
|
|
47304
|
-
|
|
47305
|
-
|
|
47306
|
-
|
|
47307
|
-
|
|
47308
|
-
|
|
47309
|
-
|
|
47310
|
-
|
|
47311
|
-
|
|
47312
|
-
|
|
47313
|
-
|
|
47314
|
-
|
|
47315
|
-
|
|
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
|
|
47337
|
-
});
|
|
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
|
-
};
|
|
47764
|
+
const repayIxs = await makeRepayIx3({
|
|
47765
|
+
program,
|
|
47766
|
+
bank: repayOpts.repayBank,
|
|
47767
|
+
tokenProgram: repayOpts.tokenProgram,
|
|
47768
|
+
amount: amountToRepay,
|
|
47769
|
+
accountAddress: marginfiAccount.address,
|
|
47770
|
+
authority: marginfiAccount.authority,
|
|
47771
|
+
repayAll: isWholePosition(
|
|
47772
|
+
{
|
|
47773
|
+
amount: repayOpts.totalPositionAmount,
|
|
47774
|
+
isLending: true
|
|
47775
|
+
},
|
|
47776
|
+
amountToRepay,
|
|
47777
|
+
repayOpts.repayBank.mintDecimals
|
|
47778
|
+
),
|
|
47779
|
+
isSync: false,
|
|
47780
|
+
opts: {
|
|
47781
|
+
wrapAndUnwrapSol: false,
|
|
47782
|
+
overrideInferAccounts
|
|
47356
47783
|
}
|
|
47784
|
+
});
|
|
47785
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
47786
|
+
const allNonFlIxs = [
|
|
47787
|
+
...cuRequestIxs,
|
|
47788
|
+
...withdrawIxs.instructions,
|
|
47789
|
+
...swapInstructions,
|
|
47790
|
+
...repayIxs.instructions
|
|
47791
|
+
];
|
|
47792
|
+
if (swapInstructions.length > 0) {
|
|
47793
|
+
compileFlashloanPrecheck({
|
|
47794
|
+
allIxs: allNonFlIxs,
|
|
47795
|
+
payer: marginfiAccount.authority,
|
|
47796
|
+
luts,
|
|
47797
|
+
sizeConstraint: sizeConstraintUsed,
|
|
47798
|
+
swapIxCount: swapInstructions.length,
|
|
47799
|
+
swapLutCount: swapLookupTables.length
|
|
47800
|
+
});
|
|
47357
47801
|
}
|
|
47358
|
-
|
|
47802
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
47803
|
+
program,
|
|
47804
|
+
marginfiAccount,
|
|
47805
|
+
bankMap,
|
|
47806
|
+
addressLookupTableAccounts: luts,
|
|
47807
|
+
blockhash,
|
|
47808
|
+
ixs: allNonFlIxs,
|
|
47809
|
+
isSync: true
|
|
47810
|
+
});
|
|
47811
|
+
const txSize = getTxSize(flashloanTx);
|
|
47812
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
47813
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
47814
|
+
throw TransactionBuildingError.swapSizeExceededRepay(
|
|
47815
|
+
txSize,
|
|
47816
|
+
totalKeys,
|
|
47817
|
+
swapOpts.swapConfig?.provider
|
|
47818
|
+
);
|
|
47819
|
+
}
|
|
47820
|
+
return {
|
|
47821
|
+
flashloanTx,
|
|
47822
|
+
setupInstructions,
|
|
47823
|
+
swapQuote,
|
|
47824
|
+
withdrawIxs,
|
|
47825
|
+
repayIxs,
|
|
47826
|
+
amountToRepay
|
|
47827
|
+
};
|
|
47359
47828
|
}
|
|
47360
47829
|
|
|
47361
47830
|
// src/services/account/actions/emissions.ts
|
|
@@ -47509,11 +47978,16 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47509
47978
|
actualWithdrawAmount,
|
|
47510
47979
|
withdrawBank.mintDecimals
|
|
47511
47980
|
);
|
|
47512
|
-
const swapResult = [];
|
|
47513
47981
|
const cuRequestIxs = [
|
|
47514
47982
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47515
47983
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
47516
47984
|
];
|
|
47985
|
+
let amountToDeposit;
|
|
47986
|
+
let swapInstructions = [];
|
|
47987
|
+
let setupInstructions = [];
|
|
47988
|
+
let swapLookupTables = [];
|
|
47989
|
+
let swapQuote;
|
|
47990
|
+
let sizeConstraintUsed = 0;
|
|
47517
47991
|
let withdrawIxs;
|
|
47518
47992
|
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
47519
47993
|
case 3 /* KAMINO */: {
|
|
@@ -47623,12 +48097,7 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47623
48097
|
}
|
|
47624
48098
|
}
|
|
47625
48099
|
if (depositBank.mint.equals(withdrawBank.mint)) {
|
|
47626
|
-
|
|
47627
|
-
amountToDeposit: actualWithdrawAmount,
|
|
47628
|
-
swapInstructions: [],
|
|
47629
|
-
setupInstructions: [],
|
|
47630
|
-
swapLookupTables: []
|
|
47631
|
-
});
|
|
48100
|
+
amountToDeposit = actualWithdrawAmount;
|
|
47632
48101
|
} else {
|
|
47633
48102
|
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
47634
48103
|
depositBank.mint,
|
|
@@ -47636,175 +48105,168 @@ async function buildSwapCollateralFlashloanTx({
|
|
|
47636
48105
|
true,
|
|
47637
48106
|
depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47638
48107
|
);
|
|
47639
|
-
const
|
|
47640
|
-
|
|
47641
|
-
|
|
47642
|
-
|
|
47643
|
-
|
|
47644
|
-
|
|
47645
|
-
|
|
47646
|
-
|
|
47647
|
-
|
|
47648
|
-
|
|
47649
|
-
|
|
48108
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
48109
|
+
program,
|
|
48110
|
+
marginfiAccount,
|
|
48111
|
+
bankMap,
|
|
48112
|
+
bankMetadataMap,
|
|
48113
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
48114
|
+
primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
|
|
48115
|
+
secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
|
|
48116
|
+
overrideInferAccounts
|
|
48117
|
+
});
|
|
48118
|
+
const swapResponses = await getSwapIxsForFlashloan({
|
|
48119
|
+
inputMint: withdrawBank.mint.toBase58(),
|
|
48120
|
+
outputMint: depositBank.mint.toBase58(),
|
|
48121
|
+
amount: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
|
|
48122
|
+
swapMode: "ExactIn",
|
|
47650
48123
|
authority: marginfiAccount.authority,
|
|
47651
48124
|
connection,
|
|
47652
48125
|
destinationTokenAccount,
|
|
47653
|
-
|
|
47654
|
-
|
|
47655
|
-
|
|
47656
|
-
const outAmountThreshold = nativeToUi(
|
|
47657
|
-
response.quoteResponse.otherAmountThreshold,
|
|
47658
|
-
depositBank.mintDecimals
|
|
47659
|
-
);
|
|
47660
|
-
swapResult.push({
|
|
47661
|
-
amountToDeposit: outAmountThreshold,
|
|
47662
|
-
swapInstructions: [response.swapInstruction],
|
|
47663
|
-
setupInstructions: response.setupInstructions,
|
|
47664
|
-
swapLookupTables: response.addressLookupTableAddresses,
|
|
47665
|
-
quoteResponse: response.quoteResponse
|
|
47666
|
-
});
|
|
48126
|
+
swapOpts,
|
|
48127
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48128
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47667
48129
|
});
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
48130
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
48131
|
+
amountToDeposit = nativeToUi(
|
|
48132
|
+
swapResponses.quoteResponse.otherAmountThreshold,
|
|
48133
|
+
depositBank.mintDecimals
|
|
47672
48134
|
);
|
|
48135
|
+
swapInstructions = swapResponses.swapInstructions;
|
|
48136
|
+
setupInstructions = swapResponses.setupInstructions;
|
|
48137
|
+
swapLookupTables = swapResponses.addressLookupTableAddresses;
|
|
48138
|
+
swapQuote = swapResponses.quoteResponse;
|
|
47673
48139
|
}
|
|
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;
|
|
48140
|
+
let depositIxs;
|
|
48141
|
+
switch (depositBank.config.assetTag) {
|
|
48142
|
+
case 3 /* KAMINO */: {
|
|
48143
|
+
const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
48144
|
+
if (!reserve) {
|
|
48145
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
48146
|
+
depositBank.address.toBase58(),
|
|
48147
|
+
depositBank.mint.toBase58(),
|
|
48148
|
+
depositBank.tokenSymbol
|
|
48149
|
+
);
|
|
47708
48150
|
}
|
|
47709
|
-
|
|
47710
|
-
|
|
47711
|
-
|
|
47712
|
-
|
|
47713
|
-
|
|
47714
|
-
|
|
47715
|
-
|
|
47716
|
-
|
|
48151
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
48152
|
+
program,
|
|
48153
|
+
bank: depositBank,
|
|
48154
|
+
tokenProgram: depositTokenProgram,
|
|
48155
|
+
amount: amountToDeposit,
|
|
48156
|
+
accountAddress: marginfiAccount.address,
|
|
48157
|
+
authority: marginfiAccount.authority,
|
|
48158
|
+
group: marginfiAccount.group,
|
|
48159
|
+
reserve,
|
|
48160
|
+
opts: {
|
|
48161
|
+
wrapAndUnwrapSol: false,
|
|
48162
|
+
overrideInferAccounts
|
|
47717
48163
|
}
|
|
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
|
-
}
|
|
48164
|
+
});
|
|
48165
|
+
break;
|
|
47769
48166
|
}
|
|
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;
|
|
48167
|
+
case 4 /* DRIFT */: {
|
|
48168
|
+
const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
|
|
48169
|
+
if (!driftState) {
|
|
48170
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
48171
|
+
depositBank.address.toBase58(),
|
|
48172
|
+
depositBank.mint.toBase58(),
|
|
48173
|
+
depositBank.tokenSymbol
|
|
48174
|
+
);
|
|
47796
48175
|
}
|
|
47797
|
-
|
|
47798
|
-
|
|
47799
|
-
|
|
47800
|
-
|
|
47801
|
-
|
|
47802
|
-
|
|
47803
|
-
|
|
47804
|
-
|
|
48176
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
48177
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
48178
|
+
depositIxs = await makeDriftDepositIx3({
|
|
48179
|
+
program,
|
|
48180
|
+
bank: depositBank,
|
|
48181
|
+
tokenProgram: depositTokenProgram,
|
|
48182
|
+
amount: amountToDeposit,
|
|
48183
|
+
accountAddress: marginfiAccount.address,
|
|
48184
|
+
authority: marginfiAccount.authority,
|
|
48185
|
+
group: marginfiAccount.group,
|
|
48186
|
+
driftMarketIndex,
|
|
48187
|
+
driftOracle,
|
|
48188
|
+
opts: {
|
|
48189
|
+
wrapAndUnwrapSol: false,
|
|
48190
|
+
overrideInferAccounts
|
|
48191
|
+
}
|
|
48192
|
+
});
|
|
48193
|
+
break;
|
|
48194
|
+
}
|
|
48195
|
+
case 6 /* JUPLEND */: {
|
|
48196
|
+
depositIxs = await makeJuplendDepositIx2({
|
|
48197
|
+
program,
|
|
48198
|
+
bank: depositBank,
|
|
48199
|
+
tokenProgram: depositTokenProgram,
|
|
48200
|
+
amount: amountToDeposit,
|
|
48201
|
+
accountAddress: marginfiAccount.address,
|
|
48202
|
+
authority: marginfiAccount.authority,
|
|
48203
|
+
group: marginfiAccount.group,
|
|
48204
|
+
opts: {
|
|
48205
|
+
wrapAndUnwrapSol: false,
|
|
48206
|
+
overrideInferAccounts
|
|
48207
|
+
}
|
|
48208
|
+
});
|
|
48209
|
+
break;
|
|
47805
48210
|
}
|
|
48211
|
+
default: {
|
|
48212
|
+
depositIxs = await makeDepositIx3({
|
|
48213
|
+
program,
|
|
48214
|
+
bank: depositBank,
|
|
48215
|
+
tokenProgram: depositTokenProgram,
|
|
48216
|
+
amount: amountToDeposit,
|
|
48217
|
+
accountAddress: marginfiAccount.address,
|
|
48218
|
+
authority: marginfiAccount.authority,
|
|
48219
|
+
group: marginfiAccount.group,
|
|
48220
|
+
opts: {
|
|
48221
|
+
wrapAndUnwrapSol: false,
|
|
48222
|
+
overrideInferAccounts
|
|
48223
|
+
}
|
|
48224
|
+
});
|
|
48225
|
+
break;
|
|
48226
|
+
}
|
|
48227
|
+
}
|
|
48228
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
48229
|
+
const allNonFlIxs = [
|
|
48230
|
+
...cuRequestIxs,
|
|
48231
|
+
...withdrawIxs.instructions,
|
|
48232
|
+
...swapInstructions,
|
|
48233
|
+
...depositIxs.instructions
|
|
48234
|
+
];
|
|
48235
|
+
if (swapInstructions.length > 0) {
|
|
48236
|
+
compileFlashloanPrecheck({
|
|
48237
|
+
allIxs: allNonFlIxs,
|
|
48238
|
+
payer: marginfiAccount.authority,
|
|
48239
|
+
luts,
|
|
48240
|
+
sizeConstraint: sizeConstraintUsed,
|
|
48241
|
+
swapIxCount: swapInstructions.length,
|
|
48242
|
+
swapLutCount: swapLookupTables.length
|
|
48243
|
+
});
|
|
47806
48244
|
}
|
|
47807
|
-
|
|
48245
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
48246
|
+
program,
|
|
48247
|
+
marginfiAccount,
|
|
48248
|
+
bankMap,
|
|
48249
|
+
addressLookupTableAccounts: luts,
|
|
48250
|
+
blockhash,
|
|
48251
|
+
ixs: allNonFlIxs,
|
|
48252
|
+
isSync: true
|
|
48253
|
+
});
|
|
48254
|
+
const txSize = getTxSize(flashloanTx);
|
|
48255
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
48256
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
48257
|
+
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
48258
|
+
txSize,
|
|
48259
|
+
totalKeys,
|
|
48260
|
+
swapOpts.swapConfig?.provider
|
|
48261
|
+
);
|
|
48262
|
+
}
|
|
48263
|
+
return {
|
|
48264
|
+
flashloanTx,
|
|
48265
|
+
setupInstructions,
|
|
48266
|
+
swapQuote,
|
|
48267
|
+
withdrawIxs,
|
|
48268
|
+
depositIxs
|
|
48269
|
+
};
|
|
47808
48270
|
}
|
|
47809
48271
|
async function makeSwapDebtTx(params) {
|
|
47810
48272
|
const {
|
|
@@ -47942,7 +48404,6 @@ async function buildSwapDebtFlashloanTx({
|
|
|
47942
48404
|
throw new Error("repayAmount must be greater than 0");
|
|
47943
48405
|
}
|
|
47944
48406
|
const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
|
|
47945
|
-
const swapResult = [];
|
|
47946
48407
|
const cuRequestIxs = [
|
|
47947
48408
|
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
47948
48409
|
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
@@ -47953,313 +48414,120 @@ async function buildSwapDebtFlashloanTx({
|
|
|
47953
48414
|
true,
|
|
47954
48415
|
repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
47955
48416
|
);
|
|
47956
|
-
const
|
|
47957
|
-
const estimateQuote = await jupiterApiClient.quoteGet({
|
|
48417
|
+
const { otherAmountThreshold } = await getExactOutEstimate({
|
|
47958
48418
|
inputMint: borrowBank.mint.toBase58(),
|
|
47959
48419
|
outputMint: repayBank.mint.toBase58(),
|
|
47960
48420
|
amount: uiToNative(actualRepayAmount, repayBank.mintDecimals).toNumber(),
|
|
47961
|
-
|
|
47962
|
-
|
|
47963
|
-
slippageBps: swapOpts.jupiterOptions?.slippageBps
|
|
48421
|
+
swapOpts,
|
|
48422
|
+
connection
|
|
47964
48423
|
});
|
|
47965
|
-
const estimatedBorrowAmount = nativeToUi(
|
|
47966
|
-
|
|
47967
|
-
|
|
47968
|
-
|
|
47969
|
-
|
|
47970
|
-
|
|
47971
|
-
|
|
47972
|
-
|
|
47973
|
-
|
|
47974
|
-
|
|
47975
|
-
|
|
47976
|
-
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
48424
|
+
const estimatedBorrowAmount = nativeToUi(otherAmountThreshold, borrowBank.mintDecimals);
|
|
48425
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
48426
|
+
program,
|
|
48427
|
+
marginfiAccount,
|
|
48428
|
+
bankMap,
|
|
48429
|
+
bankMetadataMap,
|
|
48430
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
48431
|
+
primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
|
|
48432
|
+
secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
|
|
48433
|
+
overrideInferAccounts
|
|
48434
|
+
});
|
|
48435
|
+
const swapResponses = await getSwapIxsForFlashloan({
|
|
48436
|
+
inputMint: borrowBank.mint.toBase58(),
|
|
48437
|
+
outputMint: repayBank.mint.toBase58(),
|
|
48438
|
+
amount: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
|
|
48439
|
+
swapMode: "ExactIn",
|
|
47980
48440
|
authority: marginfiAccount.authority,
|
|
47981
48441
|
connection,
|
|
47982
48442
|
destinationTokenAccount,
|
|
47983
|
-
|
|
48443
|
+
swapOpts,
|
|
48444
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48445
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
47984
48446
|
});
|
|
47985
|
-
|
|
47986
|
-
|
|
47987
|
-
|
|
47988
|
-
|
|
47989
|
-
|
|
47990
|
-
|
|
47991
|
-
|
|
47992
|
-
|
|
47993
|
-
|
|
47994
|
-
|
|
47995
|
-
|
|
47996
|
-
|
|
47997
|
-
|
|
47998
|
-
|
|
47999
|
-
|
|
48000
|
-
|
|
48447
|
+
const { quoteResponse } = swapResponses;
|
|
48448
|
+
const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
|
|
48449
|
+
const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
|
|
48450
|
+
const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
|
|
48451
|
+
const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
|
|
48452
|
+
const borrowIxs = await makeBorrowIx3({
|
|
48453
|
+
program,
|
|
48454
|
+
bank: borrowBank,
|
|
48455
|
+
bankMap,
|
|
48456
|
+
tokenProgram: borrowTokenProgram,
|
|
48457
|
+
amount: borrowAmount,
|
|
48458
|
+
marginfiAccount,
|
|
48459
|
+
authority: marginfiAccount.authority,
|
|
48460
|
+
isSync: true,
|
|
48461
|
+
opts: {
|
|
48462
|
+
createAtas: false,
|
|
48463
|
+
wrapAndUnwrapSol: false,
|
|
48464
|
+
overrideInferAccounts
|
|
48465
|
+
}
|
|
48001
48466
|
});
|
|
48002
|
-
|
|
48003
|
-
|
|
48004
|
-
|
|
48005
|
-
|
|
48006
|
-
|
|
48007
|
-
|
|
48008
|
-
|
|
48467
|
+
const repayIxs = await makeRepayIx3({
|
|
48468
|
+
program,
|
|
48469
|
+
bank: repayBank,
|
|
48470
|
+
tokenProgram: repayTokenProgram,
|
|
48471
|
+
amount: amountToRepay,
|
|
48472
|
+
accountAddress: marginfiAccount.address,
|
|
48473
|
+
authority: marginfiAccount.authority,
|
|
48474
|
+
repayAll: isWholePosition(
|
|
48475
|
+
{
|
|
48476
|
+
amount: totalPositionAmount,
|
|
48477
|
+
isLending: false
|
|
48478
|
+
},
|
|
48009
48479
|
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
|
-
};
|
|
48087
|
-
}
|
|
48088
|
-
}
|
|
48089
|
-
throw new Error("Failed to build swap debt flashloan tx");
|
|
48090
|
-
}
|
|
48091
|
-
var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
|
|
48092
|
-
async function makeMintStakedLstIx(params) {
|
|
48093
|
-
const { amount, authority, stakeAccountPk, validator, connection } = params;
|
|
48094
|
-
const pool = findPoolAddress(validator);
|
|
48095
|
-
const lstMint = findPoolMintAddress(pool);
|
|
48096
|
-
const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
|
|
48097
|
-
const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
|
|
48098
|
-
const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
|
|
48099
|
-
connection.getAccountInfo(lstAta),
|
|
48100
|
-
connection.getParsedAccountInfo(stakeAccountPk),
|
|
48101
|
-
connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space)
|
|
48102
|
-
]);
|
|
48103
|
-
const stakeAccParsed = stakeAccInfoParsed?.value?.data;
|
|
48104
|
-
const amountLamports = Math.round(Number(amount) * web3_js.LAMPORTS_PER_SOL);
|
|
48105
|
-
const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
|
|
48106
|
-
const isFullStake = amountLamports >= stakeAccLamports;
|
|
48107
|
-
const instructions2 = [];
|
|
48108
|
-
const signers = [];
|
|
48109
|
-
if (!lstAccInfo) {
|
|
48110
|
-
instructions2.push(
|
|
48111
|
-
createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
|
|
48112
|
-
);
|
|
48113
|
-
}
|
|
48114
|
-
let targetStakePubkey;
|
|
48115
|
-
if (!isFullStake) {
|
|
48116
|
-
const splitStakeAccount = web3_js.Keypair.generate();
|
|
48117
|
-
signers.push(splitStakeAccount);
|
|
48118
|
-
targetStakePubkey = splitStakeAccount.publicKey;
|
|
48119
|
-
instructions2.push(
|
|
48120
|
-
...web3_js.StakeProgram.split(
|
|
48121
|
-
{
|
|
48122
|
-
stakePubkey: stakeAccountPk,
|
|
48123
|
-
authorizedPubkey: authority,
|
|
48124
|
-
splitStakePubkey: splitStakeAccount.publicKey,
|
|
48125
|
-
lamports: amountLamports
|
|
48126
|
-
},
|
|
48127
|
-
rentExemptReserve
|
|
48128
|
-
).instructions
|
|
48129
|
-
);
|
|
48130
|
-
} else {
|
|
48131
|
-
targetStakePubkey = stakeAccountPk;
|
|
48132
|
-
}
|
|
48133
|
-
const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
|
|
48134
|
-
web3_js.StakeProgram.authorize({
|
|
48135
|
-
stakePubkey: targetStakePubkey,
|
|
48136
|
-
authorizedPubkey: authority,
|
|
48137
|
-
newAuthorizedPubkey: poolStakeAuth,
|
|
48138
|
-
stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Staker
|
|
48139
|
-
}).instructions,
|
|
48140
|
-
web3_js.StakeProgram.authorize({
|
|
48141
|
-
stakePubkey: targetStakePubkey,
|
|
48142
|
-
authorizedPubkey: authority,
|
|
48143
|
-
newAuthorizedPubkey: poolStakeAuth,
|
|
48144
|
-
stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Withdrawer
|
|
48145
|
-
}).instructions
|
|
48146
|
-
]);
|
|
48147
|
-
[authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
|
|
48148
|
-
if (ix) {
|
|
48149
|
-
ix.keys = ix.keys.map((key) => ({
|
|
48150
|
-
...key,
|
|
48151
|
-
isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
|
|
48152
|
-
}));
|
|
48480
|
+
repayBank.mintDecimals
|
|
48481
|
+
),
|
|
48482
|
+
isSync: true,
|
|
48483
|
+
opts: {
|
|
48484
|
+
wrapAndUnwrapSol: false,
|
|
48485
|
+
overrideInferAccounts
|
|
48153
48486
|
}
|
|
48154
48487
|
});
|
|
48155
|
-
|
|
48156
|
-
|
|
48157
|
-
|
|
48158
|
-
|
|
48159
|
-
|
|
48160
|
-
|
|
48161
|
-
|
|
48162
|
-
|
|
48163
|
-
|
|
48164
|
-
|
|
48165
|
-
|
|
48166
|
-
|
|
48167
|
-
|
|
48168
|
-
const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
48169
|
-
const message = new web3_js.TransactionMessage({
|
|
48170
|
-
payerKey: params.authority,
|
|
48171
|
-
recentBlockhash: blockhash,
|
|
48172
|
-
instructions: instructions2
|
|
48173
|
-
}).compileToV0Message(luts);
|
|
48174
|
-
const tx = new web3_js.VersionedTransaction(message);
|
|
48175
|
-
return addTransactionMetadata(tx, {
|
|
48176
|
-
signers: keys,
|
|
48177
|
-
addressLookupTables: luts,
|
|
48178
|
-
type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
|
|
48179
|
-
});
|
|
48180
|
-
}
|
|
48181
|
-
async function makeRedeemStakedLstIx(params) {
|
|
48182
|
-
const { amount, authority, validator, connection } = params;
|
|
48183
|
-
const pool = findPoolAddress(validator);
|
|
48184
|
-
const lstMint = findPoolMintAddress(pool);
|
|
48185
|
-
const mintAuthority = findPoolMintAuthorityAddress(pool);
|
|
48186
|
-
const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
|
|
48187
|
-
const rentExemption = await connection.getMinimumBalanceForRentExemption(
|
|
48188
|
-
web3_js.StakeProgram.space
|
|
48189
|
-
);
|
|
48190
|
-
const stakeAmount = new BigNumber3__default.default(new BigNumber3__default.default(amount).toString());
|
|
48191
|
-
const instructions2 = [];
|
|
48192
|
-
const signers = [];
|
|
48193
|
-
const stakeAccount = web3_js.Keypair.generate();
|
|
48194
|
-
signers.push(stakeAccount);
|
|
48195
|
-
instructions2.push(
|
|
48196
|
-
web3_js.SystemProgram.createAccount({
|
|
48197
|
-
fromPubkey: authority,
|
|
48198
|
-
newAccountPubkey: stakeAccount.publicKey,
|
|
48199
|
-
lamports: rentExemption,
|
|
48200
|
-
space: web3_js.StakeProgram.space,
|
|
48201
|
-
programId: web3_js.StakeProgram.programId
|
|
48202
|
-
})
|
|
48203
|
-
);
|
|
48204
|
-
instructions2.push(
|
|
48205
|
-
createApproveInstruction(
|
|
48206
|
-
lstAta,
|
|
48207
|
-
mintAuthority,
|
|
48208
|
-
authority,
|
|
48209
|
-
BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
|
|
48210
|
-
)
|
|
48211
|
-
);
|
|
48212
|
-
const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
|
|
48213
|
-
pool,
|
|
48214
|
-
stakeAccount.publicKey,
|
|
48215
|
-
authority,
|
|
48216
|
-
lstAta,
|
|
48217
|
-
stakeAmount
|
|
48218
|
-
);
|
|
48219
|
-
instructions2.push(withdrawStakeIx);
|
|
48220
|
-
return { instructions: instructions2, keys: signers };
|
|
48221
|
-
}
|
|
48222
|
-
async function makeRedeemStakedLstTx(params) {
|
|
48223
|
-
const { connection, luts, blockhash: providedBlockhash } = params;
|
|
48224
|
-
const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
|
|
48225
|
-
const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
48226
|
-
const message = new web3_js.TransactionMessage({
|
|
48227
|
-
payerKey: params.authority,
|
|
48228
|
-
recentBlockhash: blockhash,
|
|
48229
|
-
instructions: instructions2
|
|
48230
|
-
}).compileToV0Message(luts);
|
|
48231
|
-
const tx = new web3_js.VersionedTransaction(message);
|
|
48232
|
-
return addTransactionMetadata(tx, {
|
|
48233
|
-
signers: keys,
|
|
48234
|
-
addressLookupTables: luts,
|
|
48235
|
-
type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
|
|
48236
|
-
});
|
|
48237
|
-
}
|
|
48238
|
-
async function makeMergeStakeAccountsTx(params) {
|
|
48239
|
-
const {
|
|
48240
|
-
authority,
|
|
48241
|
-
sourceStakeAccount,
|
|
48242
|
-
destinationStakeAccount,
|
|
48243
|
-
connection,
|
|
48488
|
+
const luts = [
|
|
48489
|
+
...addressLookupTableAccounts ?? [],
|
|
48490
|
+
...swapResponses.addressLookupTableAddresses
|
|
48491
|
+
];
|
|
48492
|
+
const allNonFlIxs = [
|
|
48493
|
+
...cuRequestIxs,
|
|
48494
|
+
...borrowIxs.instructions,
|
|
48495
|
+
...swapResponses.swapInstructions,
|
|
48496
|
+
...repayIxs.instructions
|
|
48497
|
+
];
|
|
48498
|
+
compileFlashloanPrecheck({
|
|
48499
|
+
allIxs: allNonFlIxs,
|
|
48500
|
+
payer: marginfiAccount.authority,
|
|
48244
48501
|
luts,
|
|
48245
|
-
|
|
48246
|
-
|
|
48247
|
-
|
|
48248
|
-
|
|
48249
|
-
|
|
48250
|
-
|
|
48251
|
-
|
|
48252
|
-
|
|
48253
|
-
|
|
48254
|
-
|
|
48255
|
-
|
|
48256
|
-
|
|
48257
|
-
}).compileToV0Message(luts);
|
|
48258
|
-
const tx = new web3_js.VersionedTransaction(message);
|
|
48259
|
-
return addTransactionMetadata(tx, {
|
|
48260
|
-
addressLookupTables: luts,
|
|
48261
|
-
type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
|
|
48502
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
48503
|
+
swapIxCount: swapResponses.swapInstructions.length,
|
|
48504
|
+
swapLutCount: swapResponses.addressLookupTableAddresses.length
|
|
48505
|
+
});
|
|
48506
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
48507
|
+
program,
|
|
48508
|
+
marginfiAccount,
|
|
48509
|
+
bankMap,
|
|
48510
|
+
addressLookupTableAccounts: luts,
|
|
48511
|
+
blockhash,
|
|
48512
|
+
ixs: allNonFlIxs,
|
|
48513
|
+
isSync: true
|
|
48262
48514
|
});
|
|
48515
|
+
const txSize = getTxSize(flashloanTx);
|
|
48516
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
48517
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
48518
|
+
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
48519
|
+
txSize,
|
|
48520
|
+
totalKeys,
|
|
48521
|
+
swapOpts.swapConfig?.provider
|
|
48522
|
+
);
|
|
48523
|
+
}
|
|
48524
|
+
return {
|
|
48525
|
+
flashloanTx,
|
|
48526
|
+
setupInstructions: swapResponses.setupInstructions,
|
|
48527
|
+
swapQuote: quoteResponse,
|
|
48528
|
+
borrowIxs,
|
|
48529
|
+
repayIxs
|
|
48530
|
+
};
|
|
48263
48531
|
}
|
|
48264
48532
|
|
|
48265
48533
|
// src/services/account/services/account-simulation.service.ts
|
|
@@ -48885,17 +49153,528 @@ function computeMaxWithdrawForBank(params) {
|
|
|
48885
49153
|
const maxWithdraw = initUntiedCollateralForBank.div(initWeightedPrice);
|
|
48886
49154
|
return maxWithdraw;
|
|
48887
49155
|
}
|
|
49156
|
+
var TITAN_FEE_WALLET = new web3_js.PublicKey("6ryqDDCwKFZfSiHQrYRkjTEarbsLjg9TmuFg1RJorBk3");
|
|
49157
|
+
var getTitanFeeAccount = (mint) => {
|
|
49158
|
+
return getAssociatedTokenAddressSync(mint, TITAN_FEE_WALLET, true);
|
|
49159
|
+
};
|
|
49160
|
+
var checkTitanFeeAccount = async (connection, mint) => {
|
|
49161
|
+
const feeAccount = getTitanFeeAccount(mint);
|
|
49162
|
+
const hasFeeAccount = !!await connection.getAccountInfo(feeAccount);
|
|
49163
|
+
return { feeAccount, hasFeeAccount, feeWallet: TITAN_FEE_WALLET };
|
|
49164
|
+
};
|
|
49165
|
+
function deserializeTitanInstruction(ix) {
|
|
49166
|
+
return new web3_js.TransactionInstruction({
|
|
49167
|
+
programId: new web3_js.PublicKey(ix.p),
|
|
49168
|
+
keys: ix.a.map((account) => ({
|
|
49169
|
+
pubkey: new web3_js.PublicKey(account.p),
|
|
49170
|
+
isSigner: account.s,
|
|
49171
|
+
isWritable: account.w
|
|
49172
|
+
})),
|
|
49173
|
+
data: Buffer.from(ix.d)
|
|
49174
|
+
});
|
|
49175
|
+
}
|
|
49176
|
+
var getTitanSwapIxsForFlashloan = async ({
|
|
49177
|
+
quoteParams,
|
|
49178
|
+
authority,
|
|
49179
|
+
connection,
|
|
49180
|
+
destinationTokenAccount,
|
|
49181
|
+
apiConfig
|
|
49182
|
+
}) => {
|
|
49183
|
+
const basePath = apiConfig?.basePath ?? "";
|
|
49184
|
+
const feeMint = new web3_js.PublicKey(
|
|
49185
|
+
quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint
|
|
49186
|
+
);
|
|
49187
|
+
const { feeAccount, hasFeeAccount } = await checkTitanFeeAccount(connection, feeMint);
|
|
49188
|
+
let finalQuoteParams = quoteParams;
|
|
49189
|
+
if (!hasFeeAccount) {
|
|
49190
|
+
console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
|
|
49191
|
+
finalQuoteParams = {
|
|
49192
|
+
...quoteParams,
|
|
49193
|
+
platformFeeBps: void 0
|
|
49194
|
+
};
|
|
49195
|
+
}
|
|
49196
|
+
if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
|
|
49197
|
+
return getTitanSwapIxsViaWebSocket(
|
|
49198
|
+
{ quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
|
|
49199
|
+
hasFeeAccount ? feeAccount : void 0
|
|
49200
|
+
);
|
|
49201
|
+
} else {
|
|
49202
|
+
return getTitanSwapIxsViaHttpProxy(
|
|
49203
|
+
{ quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
|
|
49204
|
+
hasFeeAccount ? feeAccount : void 0
|
|
49205
|
+
);
|
|
49206
|
+
}
|
|
49207
|
+
};
|
|
49208
|
+
async function getTitanSwapIxsViaWebSocket(params, feeAccount) {
|
|
49209
|
+
const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
|
|
49210
|
+
const {
|
|
49211
|
+
inputMint,
|
|
49212
|
+
outputMint,
|
|
49213
|
+
amount,
|
|
49214
|
+
swapMode,
|
|
49215
|
+
slippageBps,
|
|
49216
|
+
platformFeeBps,
|
|
49217
|
+
directRoutesOnly,
|
|
49218
|
+
sizeConstraint,
|
|
49219
|
+
maxSwapAccounts,
|
|
49220
|
+
maxSwapTotalAccounts
|
|
49221
|
+
} = quoteParams;
|
|
49222
|
+
const wsUrl = apiConfig?.basePath;
|
|
49223
|
+
if (!wsUrl) {
|
|
49224
|
+
throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
|
|
49225
|
+
}
|
|
49226
|
+
const txParams = {
|
|
49227
|
+
userPublicKey: authority.toBytes(),
|
|
49228
|
+
outputAccount: destinationTokenAccount.toBytes()
|
|
49229
|
+
};
|
|
49230
|
+
if (feeAccount && platformFeeBps) {
|
|
49231
|
+
txParams.feeBps = platformFeeBps;
|
|
49232
|
+
txParams.feeAccount = feeAccount.toBytes();
|
|
49233
|
+
}
|
|
49234
|
+
const client = await V1Client.connect(wsUrl);
|
|
49235
|
+
try {
|
|
49236
|
+
const { stream } = await client.newSwapQuoteStream({
|
|
49237
|
+
swap: {
|
|
49238
|
+
inputMint: new web3_js.PublicKey(inputMint).toBytes(),
|
|
49239
|
+
outputMint: new web3_js.PublicKey(outputMint).toBytes(),
|
|
49240
|
+
amount,
|
|
49241
|
+
swapMode,
|
|
49242
|
+
slippageBps,
|
|
49243
|
+
onlyDirectRoutes: directRoutesOnly,
|
|
49244
|
+
addSizeConstraint: sizeConstraint !== void 0,
|
|
49245
|
+
sizeConstraint,
|
|
49246
|
+
accountsLimitWritable: maxSwapAccounts,
|
|
49247
|
+
accountsLimitTotal: maxSwapTotalAccounts
|
|
49248
|
+
},
|
|
49249
|
+
transaction: txParams,
|
|
49250
|
+
update: {
|
|
49251
|
+
num_quotes: 3
|
|
49252
|
+
}
|
|
49253
|
+
});
|
|
49254
|
+
const reader = stream.getReader();
|
|
49255
|
+
const { value: swapQuotes, done } = await reader.read();
|
|
49256
|
+
reader.releaseLock();
|
|
49257
|
+
if (done || !swapQuotes) {
|
|
49258
|
+
throw new Error("Titan swap quote stream ended without data");
|
|
49259
|
+
}
|
|
49260
|
+
const quotes = swapQuotes;
|
|
49261
|
+
const bestRoute = selectBestRoute(quotes.quotes, swapMode);
|
|
49262
|
+
if (!bestRoute) {
|
|
49263
|
+
throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
|
|
49264
|
+
}
|
|
49265
|
+
const swapInstructions = bestRoute.instructions.map(deserializeTitanInstruction);
|
|
49266
|
+
const lutPubkeys = bestRoute.addressLookupTables.map((lutBytes) => new web3_js.PublicKey(lutBytes));
|
|
49267
|
+
const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
|
|
49268
|
+
const quoteResponse = {
|
|
49269
|
+
...buildSwapQuoteResult(bestRoute, swapMode),
|
|
49270
|
+
provider: "TITAN" /* TITAN */
|
|
49271
|
+
};
|
|
49272
|
+
return {
|
|
49273
|
+
swapInstructions,
|
|
49274
|
+
setupInstructions: [],
|
|
49275
|
+
addressLookupTableAddresses,
|
|
49276
|
+
quoteResponse
|
|
49277
|
+
};
|
|
49278
|
+
} finally {
|
|
49279
|
+
if (!client.closed) {
|
|
49280
|
+
await client.close();
|
|
49281
|
+
}
|
|
49282
|
+
}
|
|
49283
|
+
}
|
|
49284
|
+
async function getTitanSwapIxsViaHttpProxy(params, feeAccount) {
|
|
49285
|
+
const { quoteParams, authority, connection, destinationTokenAccount, apiConfig } = params;
|
|
49286
|
+
const {
|
|
49287
|
+
inputMint,
|
|
49288
|
+
outputMint,
|
|
49289
|
+
amount,
|
|
49290
|
+
swapMode,
|
|
49291
|
+
slippageBps,
|
|
49292
|
+
platformFeeBps,
|
|
49293
|
+
directRoutesOnly,
|
|
49294
|
+
sizeConstraint,
|
|
49295
|
+
maxSwapAccounts,
|
|
49296
|
+
maxSwapTotalAccounts
|
|
49297
|
+
} = quoteParams;
|
|
49298
|
+
const basePath = apiConfig?.basePath;
|
|
49299
|
+
if (!basePath) {
|
|
49300
|
+
throw new Error("Titan proxy URL is required (apiConfig.basePath)");
|
|
49301
|
+
}
|
|
49302
|
+
const txBody = {
|
|
49303
|
+
userPublicKey: authority.toBase58(),
|
|
49304
|
+
outputAccount: destinationTokenAccount.toBase58()
|
|
49305
|
+
};
|
|
49306
|
+
if (feeAccount && platformFeeBps) {
|
|
49307
|
+
txBody.feeBps = platformFeeBps;
|
|
49308
|
+
txBody.feeAccount = feeAccount.toBase58();
|
|
49309
|
+
}
|
|
49310
|
+
const response = await fetch(`${basePath}/swap-quote`, {
|
|
49311
|
+
method: "POST",
|
|
49312
|
+
headers: {
|
|
49313
|
+
"Content-Type": "application/json",
|
|
49314
|
+
...apiConfig?.headers ?? {}
|
|
49315
|
+
},
|
|
49316
|
+
body: JSON.stringify({
|
|
49317
|
+
swap: {
|
|
49318
|
+
inputMint,
|
|
49319
|
+
outputMint,
|
|
49320
|
+
amount,
|
|
49321
|
+
swapMode,
|
|
49322
|
+
slippageBps,
|
|
49323
|
+
onlyDirectRoutes: directRoutesOnly,
|
|
49324
|
+
addSizeConstraint: sizeConstraint !== void 0,
|
|
49325
|
+
sizeConstraint,
|
|
49326
|
+
accountsLimitWritable: maxSwapAccounts,
|
|
49327
|
+
accountsLimitTotal: maxSwapTotalAccounts
|
|
49328
|
+
},
|
|
49329
|
+
transaction: txBody
|
|
49330
|
+
})
|
|
49331
|
+
});
|
|
49332
|
+
if (!response.ok) {
|
|
49333
|
+
const errorData = await response.json().catch(() => ({}));
|
|
49334
|
+
throw new Error(
|
|
49335
|
+
`Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
|
|
49336
|
+
);
|
|
49337
|
+
}
|
|
49338
|
+
const data = await response.json();
|
|
49339
|
+
const bestRoute = selectBestRoute(data.quotes, swapMode);
|
|
49340
|
+
if (!bestRoute) {
|
|
49341
|
+
throw new Error(`No Titan swap routes found for ${inputMint} -> ${outputMint}`);
|
|
49342
|
+
}
|
|
49343
|
+
const swapInstructions = bestRoute.instructions.map(deserializeSerializedInstruction);
|
|
49344
|
+
const lutPubkeys = bestRoute.addressLookupTables.map(
|
|
49345
|
+
(b64) => new web3_js.PublicKey(Buffer.from(b64, "base64"))
|
|
49346
|
+
);
|
|
49347
|
+
const addressLookupTableAddresses = await resolveLookupTables(connection, lutPubkeys);
|
|
49348
|
+
const quoteResponse = {
|
|
49349
|
+
...buildSwapQuoteResult(bestRoute, swapMode),
|
|
49350
|
+
provider: "TITAN" /* TITAN */
|
|
49351
|
+
};
|
|
49352
|
+
return {
|
|
49353
|
+
swapInstructions,
|
|
49354
|
+
setupInstructions: [],
|
|
49355
|
+
addressLookupTableAddresses,
|
|
49356
|
+
quoteResponse
|
|
49357
|
+
};
|
|
49358
|
+
}
|
|
49359
|
+
var getTitanExactOutEstimate = async (params) => {
|
|
49360
|
+
const basePath = params.apiConfig?.basePath ?? "";
|
|
49361
|
+
if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
|
|
49362
|
+
return getTitanExactOutViaWebSocket(params);
|
|
49363
|
+
} else {
|
|
49364
|
+
return getTitanExactOutViaHttpProxy(params);
|
|
49365
|
+
}
|
|
49366
|
+
};
|
|
49367
|
+
async function getTitanExactOutViaWebSocket(params) {
|
|
49368
|
+
const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
|
|
49369
|
+
const wsUrl = apiConfig?.basePath;
|
|
49370
|
+
if (!wsUrl) {
|
|
49371
|
+
throw new Error("Titan WebSocket URL is required (apiConfig.basePath)");
|
|
49372
|
+
}
|
|
49373
|
+
const client = await V1Client.connect(wsUrl);
|
|
49374
|
+
try {
|
|
49375
|
+
const { stream } = await client.newSwapQuoteStream({
|
|
49376
|
+
swap: {
|
|
49377
|
+
inputMint: new web3_js.PublicKey(inputMint).toBytes(),
|
|
49378
|
+
outputMint: new web3_js.PublicKey(outputMint).toBytes(),
|
|
49379
|
+
amount,
|
|
49380
|
+
swapMode: "ExactOut" /* ExactOut */,
|
|
49381
|
+
slippageBps
|
|
49382
|
+
},
|
|
49383
|
+
transaction: {
|
|
49384
|
+
userPublicKey: new Uint8Array(32)
|
|
49385
|
+
// placeholder, not executing
|
|
49386
|
+
},
|
|
49387
|
+
update: {
|
|
49388
|
+
num_quotes: 1
|
|
49389
|
+
}
|
|
49390
|
+
});
|
|
49391
|
+
const reader = stream.getReader();
|
|
49392
|
+
const { value: swapQuotes, done } = await reader.read();
|
|
49393
|
+
reader.releaseLock();
|
|
49394
|
+
if (done || !swapQuotes) {
|
|
49395
|
+
throw new Error("Titan ExactOut estimate stream ended without data");
|
|
49396
|
+
}
|
|
49397
|
+
const quotes = swapQuotes;
|
|
49398
|
+
const bestRoute = selectBestRoute(quotes.quotes, "ExactOut");
|
|
49399
|
+
if (!bestRoute) {
|
|
49400
|
+
throw new Error(`No Titan ExactOut routes found for ${inputMint} -> ${outputMint}`);
|
|
49401
|
+
}
|
|
49402
|
+
const quoteResult = {
|
|
49403
|
+
...buildSwapQuoteResult(bestRoute, "ExactOut"),
|
|
49404
|
+
provider: "TITAN" /* TITAN */
|
|
49405
|
+
};
|
|
49406
|
+
return {
|
|
49407
|
+
otherAmountThreshold: quoteResult.otherAmountThreshold,
|
|
49408
|
+
quoteResult
|
|
49409
|
+
};
|
|
49410
|
+
} finally {
|
|
49411
|
+
if (!client.closed) {
|
|
49412
|
+
await client.close();
|
|
49413
|
+
}
|
|
49414
|
+
}
|
|
49415
|
+
}
|
|
49416
|
+
async function getTitanExactOutViaHttpProxy(params) {
|
|
49417
|
+
const { inputMint, outputMint, amount, slippageBps, apiConfig } = params;
|
|
49418
|
+
const basePath = apiConfig?.basePath;
|
|
49419
|
+
if (!basePath) {
|
|
49420
|
+
throw new Error("Titan proxy URL is required (apiConfig.basePath)");
|
|
49421
|
+
}
|
|
49422
|
+
const response = await fetch(`${basePath}/exact-out-estimate`, {
|
|
49423
|
+
method: "POST",
|
|
49424
|
+
headers: {
|
|
49425
|
+
"Content-Type": "application/json",
|
|
49426
|
+
...apiConfig?.headers ?? {}
|
|
49427
|
+
},
|
|
49428
|
+
body: JSON.stringify({
|
|
49429
|
+
inputMint,
|
|
49430
|
+
outputMint,
|
|
49431
|
+
amount,
|
|
49432
|
+
slippageBps
|
|
49433
|
+
})
|
|
49434
|
+
});
|
|
49435
|
+
if (!response.ok) {
|
|
49436
|
+
const errorData = await response.json().catch(() => ({}));
|
|
49437
|
+
throw new Error(
|
|
49438
|
+
`Titan proxy error (${response.status}): ${errorData.message ?? response.statusText}`
|
|
49439
|
+
);
|
|
49440
|
+
}
|
|
49441
|
+
const data = await response.json();
|
|
49442
|
+
const quoteResult = {
|
|
49443
|
+
inAmount: String(data.inAmount),
|
|
49444
|
+
outAmount: String(data.outAmount),
|
|
49445
|
+
otherAmountThreshold: data.otherAmountThreshold,
|
|
49446
|
+
slippageBps: data.slippageBps,
|
|
49447
|
+
provider: "TITAN" /* TITAN */
|
|
49448
|
+
};
|
|
49449
|
+
return {
|
|
49450
|
+
otherAmountThreshold: data.otherAmountThreshold,
|
|
49451
|
+
quoteResult
|
|
49452
|
+
};
|
|
49453
|
+
}
|
|
49454
|
+
|
|
49455
|
+
// src/services/account/utils/swap.utils.ts
|
|
49456
|
+
function getSwapProviderFn({
|
|
49457
|
+
attemptProvider,
|
|
49458
|
+
maxSwapTotalAccounts,
|
|
49459
|
+
inputMint,
|
|
49460
|
+
outputMint,
|
|
49461
|
+
amount,
|
|
49462
|
+
swapMode,
|
|
49463
|
+
authority,
|
|
49464
|
+
connection,
|
|
49465
|
+
destinationTokenAccount,
|
|
49466
|
+
swapOpts,
|
|
49467
|
+
sizeConstraint
|
|
49468
|
+
}) {
|
|
49469
|
+
switch (attemptProvider) {
|
|
49470
|
+
case "TITAN" /* TITAN */:
|
|
49471
|
+
return (apiConfig) => getTitanSwapIxsForFlashloan({
|
|
49472
|
+
quoteParams: {
|
|
49473
|
+
inputMint,
|
|
49474
|
+
outputMint,
|
|
49475
|
+
amount,
|
|
49476
|
+
swapMode,
|
|
49477
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
49478
|
+
platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
|
|
49479
|
+
directRoutesOnly: swapOpts.swapConfig?.directRoutesOnly,
|
|
49480
|
+
sizeConstraint,
|
|
49481
|
+
maxSwapTotalAccounts
|
|
49482
|
+
},
|
|
49483
|
+
authority,
|
|
49484
|
+
connection,
|
|
49485
|
+
destinationTokenAccount,
|
|
49486
|
+
apiConfig
|
|
49487
|
+
});
|
|
49488
|
+
case "JUPITER" /* JUPITER */:
|
|
49489
|
+
return (apiConfig) => getJupiterSwapIxsForFlashloan({
|
|
49490
|
+
quoteParams: {
|
|
49491
|
+
inputMint,
|
|
49492
|
+
outputMint,
|
|
49493
|
+
amount,
|
|
49494
|
+
swapMode,
|
|
49495
|
+
dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
|
|
49496
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
49497
|
+
platformFeeBps: swapOpts.swapConfig?.platformFeeBps,
|
|
49498
|
+
onlyDirectRoutes: swapOpts.swapConfig?.directRoutesOnly ?? false
|
|
49499
|
+
},
|
|
49500
|
+
authority,
|
|
49501
|
+
connection,
|
|
49502
|
+
destinationTokenAccount,
|
|
49503
|
+
apiConfig,
|
|
49504
|
+
maxSwapAccounts: maxSwapTotalAccounts
|
|
49505
|
+
});
|
|
49506
|
+
default:
|
|
49507
|
+
return void 0;
|
|
49508
|
+
}
|
|
49509
|
+
}
|
|
49510
|
+
function getExactOutProviderFn({
|
|
49511
|
+
attemptProvider,
|
|
49512
|
+
inputMint,
|
|
49513
|
+
outputMint,
|
|
49514
|
+
amount,
|
|
49515
|
+
swapOpts,
|
|
49516
|
+
apiConfig
|
|
49517
|
+
}) {
|
|
49518
|
+
switch (attemptProvider) {
|
|
49519
|
+
case "TITAN" /* TITAN */:
|
|
49520
|
+
return () => getTitanExactOutEstimate({
|
|
49521
|
+
inputMint,
|
|
49522
|
+
outputMint,
|
|
49523
|
+
amount,
|
|
49524
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
49525
|
+
apiConfig
|
|
49526
|
+
});
|
|
49527
|
+
case "JUPITER" /* JUPITER */:
|
|
49528
|
+
return async () => {
|
|
49529
|
+
const configParams = toJupiterConfig(apiConfig);
|
|
49530
|
+
const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
|
|
49531
|
+
const estimateQuote = await jupiterApiClient.quoteGet({
|
|
49532
|
+
inputMint,
|
|
49533
|
+
outputMint,
|
|
49534
|
+
amount,
|
|
49535
|
+
swapMode: "ExactOut",
|
|
49536
|
+
dynamicSlippage: swapOpts.swapConfig ? swapOpts.swapConfig.slippageMode === "DYNAMIC" : true,
|
|
49537
|
+
slippageBps: swapOpts.swapConfig?.slippageBps
|
|
49538
|
+
});
|
|
49539
|
+
const quoteResult = mapJupiterQuoteToSwapQuoteResult(estimateQuote);
|
|
49540
|
+
return { otherAmountThreshold: quoteResult.otherAmountThreshold, quoteResult };
|
|
49541
|
+
};
|
|
49542
|
+
default:
|
|
49543
|
+
return void 0;
|
|
49544
|
+
}
|
|
49545
|
+
}
|
|
49546
|
+
var getSwapIxsForFlashloan = async (params) => {
|
|
49547
|
+
const {
|
|
49548
|
+
inputMint,
|
|
49549
|
+
outputMint,
|
|
49550
|
+
amount,
|
|
49551
|
+
swapMode,
|
|
49552
|
+
authority,
|
|
49553
|
+
connection,
|
|
49554
|
+
destinationTokenAccount,
|
|
49555
|
+
swapOpts,
|
|
49556
|
+
sizeConstraint,
|
|
49557
|
+
maxSwapTotalAccounts
|
|
49558
|
+
} = params;
|
|
49559
|
+
if (swapOpts.swapIxs) {
|
|
49560
|
+
return {
|
|
49561
|
+
swapInstructions: swapOpts.swapIxs.instructions,
|
|
49562
|
+
setupInstructions: [],
|
|
49563
|
+
addressLookupTableAddresses: swapOpts.swapIxs.lookupTables,
|
|
49564
|
+
quoteResponse: {
|
|
49565
|
+
inAmount: String(amount),
|
|
49566
|
+
outAmount: "0",
|
|
49567
|
+
otherAmountThreshold: "0",
|
|
49568
|
+
slippageBps: 0
|
|
49569
|
+
}
|
|
49570
|
+
};
|
|
49571
|
+
}
|
|
49572
|
+
const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
|
|
49573
|
+
const attempts = [
|
|
49574
|
+
{ provider, apiConfig: swapOpts.swapConfig?.apiConfig },
|
|
49575
|
+
...swapOpts.swapConfig?.fallbackProviders ?? []
|
|
49576
|
+
];
|
|
49577
|
+
let lastError;
|
|
49578
|
+
for (const { provider: attemptProvider, apiConfig } of attempts) {
|
|
49579
|
+
const fn = getSwapProviderFn({
|
|
49580
|
+
attemptProvider,
|
|
49581
|
+
maxSwapTotalAccounts: params.maxSwapTotalAccounts,
|
|
49582
|
+
inputMint,
|
|
49583
|
+
outputMint,
|
|
49584
|
+
amount,
|
|
49585
|
+
swapMode,
|
|
49586
|
+
authority,
|
|
49587
|
+
connection,
|
|
49588
|
+
destinationTokenAccount,
|
|
49589
|
+
swapOpts,
|
|
49590
|
+
sizeConstraint
|
|
49591
|
+
});
|
|
49592
|
+
if (!fn) continue;
|
|
49593
|
+
try {
|
|
49594
|
+
return await fn(apiConfig);
|
|
49595
|
+
} catch (err) {
|
|
49596
|
+
if (err instanceof TransactionBuildingError) throw err;
|
|
49597
|
+
lastError = err;
|
|
49598
|
+
console.warn(`[swap] ${attemptProvider} failed:`, err instanceof Error ? err.message : err);
|
|
49599
|
+
}
|
|
49600
|
+
}
|
|
49601
|
+
const firstProvider = attempts[0]?.provider ?? "Swap";
|
|
49602
|
+
throw TransactionBuildingError.swapQuoteFailed(
|
|
49603
|
+
firstProvider,
|
|
49604
|
+
inputMint,
|
|
49605
|
+
outputMint,
|
|
49606
|
+
lastError?.message ?? "No swap route available"
|
|
49607
|
+
);
|
|
49608
|
+
};
|
|
49609
|
+
var getExactOutEstimate = async (params) => {
|
|
49610
|
+
const { inputMint, outputMint, amount, swapOpts, connection } = params;
|
|
49611
|
+
const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
|
|
49612
|
+
const attempts = [
|
|
49613
|
+
{ provider, apiConfig: swapOpts.swapConfig?.apiConfig },
|
|
49614
|
+
...swapOpts.swapConfig?.fallbackProviders ?? []
|
|
49615
|
+
];
|
|
49616
|
+
let lastError;
|
|
49617
|
+
for (const { provider: attemptProvider, apiConfig } of attempts) {
|
|
49618
|
+
const fn = getExactOutProviderFn({
|
|
49619
|
+
attemptProvider,
|
|
49620
|
+
inputMint,
|
|
49621
|
+
outputMint,
|
|
49622
|
+
amount,
|
|
49623
|
+
swapOpts,
|
|
49624
|
+
apiConfig
|
|
49625
|
+
});
|
|
49626
|
+
if (!fn) continue;
|
|
49627
|
+
try {
|
|
49628
|
+
return await fn(apiConfig);
|
|
49629
|
+
} catch (err) {
|
|
49630
|
+
if (err instanceof TransactionBuildingError) throw err;
|
|
49631
|
+
lastError = err;
|
|
49632
|
+
console.warn(
|
|
49633
|
+
`[exactout] ${attemptProvider} failed:`,
|
|
49634
|
+
err instanceof Error ? err.message : err
|
|
49635
|
+
);
|
|
49636
|
+
}
|
|
49637
|
+
}
|
|
49638
|
+
const firstProvider = attempts[0]?.provider ?? "Swap";
|
|
49639
|
+
throw TransactionBuildingError.swapQuoteFailed(
|
|
49640
|
+
firstProvider,
|
|
49641
|
+
inputMint,
|
|
49642
|
+
outputMint,
|
|
49643
|
+
lastError?.message ?? "No swap route available"
|
|
49644
|
+
);
|
|
49645
|
+
};
|
|
49646
|
+
function mapJupiterQuoteToSwapQuoteResult(quote) {
|
|
49647
|
+
return {
|
|
49648
|
+
inAmount: quote.inAmount,
|
|
49649
|
+
outAmount: quote.outAmount,
|
|
49650
|
+
otherAmountThreshold: quote.otherAmountThreshold,
|
|
49651
|
+
slippageBps: quote.slippageBps,
|
|
49652
|
+
platformFee: quote.platformFee ? {
|
|
49653
|
+
amount: quote.platformFee.amount ?? "0",
|
|
49654
|
+
feeBps: quote.platformFee.feeBps ?? 0
|
|
49655
|
+
} : void 0,
|
|
49656
|
+
priceImpactPct: quote.priceImpactPct,
|
|
49657
|
+
contextSlot: quote.contextSlot,
|
|
49658
|
+
timeTaken: quote.timeTaken,
|
|
49659
|
+
provider: "JUPITER" /* JUPITER */
|
|
49660
|
+
};
|
|
49661
|
+
}
|
|
49662
|
+
|
|
49663
|
+
// src/services/account/utils/jupiter.utils.ts
|
|
48888
49664
|
var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
|
|
48889
49665
|
var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
|
|
48890
49666
|
var getFeeAccount = (mint) => {
|
|
48891
|
-
const referralProgramPubkey = REFERRAL_PROGRAM_ID;
|
|
48892
|
-
const referralAccountPubkey = REFERRAL_ACCOUNT_PUBKEY;
|
|
48893
49667
|
const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
|
|
48894
|
-
[Buffer.from("referral_ata"),
|
|
48895
|
-
|
|
49668
|
+
[Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
|
|
49669
|
+
REFERRAL_PROGRAM_ID
|
|
48896
49670
|
);
|
|
48897
49671
|
return feeAccount.toBase58();
|
|
48898
49672
|
};
|
|
49673
|
+
var checkFeeAccount = async (connection, mint) => {
|
|
49674
|
+
const feeAccount = getFeeAccount(mint);
|
|
49675
|
+
const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
|
|
49676
|
+
return { feeAccount, hasFeeAccount };
|
|
49677
|
+
};
|
|
48899
49678
|
function deserializeJupiterInstruction(instruction) {
|
|
48900
49679
|
return new web3_js.TransactionInstruction({
|
|
48901
49680
|
programId: new web3_js.PublicKey(instruction.programId),
|
|
@@ -48907,17 +49686,26 @@ function deserializeJupiterInstruction(instruction) {
|
|
|
48907
49686
|
data: Buffer.from(instruction.data, "base64")
|
|
48908
49687
|
});
|
|
48909
49688
|
}
|
|
49689
|
+
function toJupiterConfig(apiConfig) {
|
|
49690
|
+
if (!apiConfig) return void 0;
|
|
49691
|
+
return {
|
|
49692
|
+
basePath: apiConfig.basePath,
|
|
49693
|
+
apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
|
|
49694
|
+
headers: apiConfig.headers
|
|
49695
|
+
};
|
|
49696
|
+
}
|
|
48910
49697
|
var getJupiterSwapIxsForFlashloan = async ({
|
|
48911
49698
|
quoteParams,
|
|
48912
49699
|
authority,
|
|
48913
49700
|
connection,
|
|
48914
49701
|
destinationTokenAccount,
|
|
48915
|
-
|
|
49702
|
+
apiConfig,
|
|
49703
|
+
maxSwapAccounts
|
|
48916
49704
|
}) => {
|
|
49705
|
+
const configParams = toJupiterConfig(apiConfig);
|
|
48917
49706
|
const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
|
|
48918
49707
|
const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
|
|
48919
|
-
const feeAccount =
|
|
48920
|
-
const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
|
|
49708
|
+
const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
|
|
48921
49709
|
const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
|
|
48922
49710
|
let finalQuoteParams = quoteParams;
|
|
48923
49711
|
if (!hasFeeAccount) {
|
|
@@ -48927,67 +49715,45 @@ var getJupiterSwapIxsForFlashloan = async ({
|
|
|
48927
49715
|
platformFeeBps: void 0
|
|
48928
49716
|
};
|
|
48929
49717
|
}
|
|
48930
|
-
const
|
|
48931
|
-
const
|
|
48932
|
-
|
|
48933
|
-
|
|
48934
|
-
|
|
48935
|
-
|
|
48936
|
-
|
|
48937
|
-
|
|
48938
|
-
|
|
48939
|
-
|
|
48940
|
-
|
|
48941
|
-
|
|
48942
|
-
|
|
48943
|
-
|
|
48944
|
-
|
|
48945
|
-
|
|
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
|
-
);
|
|
49718
|
+
const JUPITER_MAX_ACCOUNTS_MARGIN = 4;
|
|
49719
|
+
const maxAccounts = maxSwapAccounts !== void 0 ? maxSwapAccounts - JUPITER_MAX_ACCOUNTS_MARGIN : 40;
|
|
49720
|
+
const swapQuote = await jupiterApiClient.quoteGet({
|
|
49721
|
+
...finalQuoteParams,
|
|
49722
|
+
maxAccounts
|
|
49723
|
+
});
|
|
49724
|
+
const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
|
|
49725
|
+
swapRequest: {
|
|
49726
|
+
quoteResponse: swapQuote,
|
|
49727
|
+
userPublicKey: authority.toBase58(),
|
|
49728
|
+
feeAccount: hasFeeAccount ? feeAccount : void 0,
|
|
49729
|
+
wrapAndUnwrapSol: false,
|
|
49730
|
+
destinationTokenAccount: destinationTokenAccount.toBase58()
|
|
49731
|
+
}
|
|
49732
|
+
});
|
|
49733
|
+
const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
|
|
48956
49734
|
const lutAccountsRaw = await connection.getMultipleAccountsInfo(
|
|
48957
|
-
lutAddresses.
|
|
49735
|
+
lutAddresses.map((address) => new web3_js.PublicKey(address))
|
|
48958
49736
|
);
|
|
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
|
|
49737
|
+
const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
|
|
49738
|
+
const addressLookupTableAddress = lutAddresses[index];
|
|
49739
|
+
if (!accountInfo || !addressLookupTableAddress) {
|
|
49740
|
+
return null;
|
|
49741
|
+
}
|
|
49742
|
+
return new web3_js.AddressLookupTableAccount({
|
|
49743
|
+
key: new web3_js.PublicKey(addressLookupTableAddress),
|
|
49744
|
+
state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
|
|
48988
49745
|
});
|
|
48989
|
-
}
|
|
48990
|
-
|
|
49746
|
+
}).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
|
|
49747
|
+
const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
|
|
49748
|
+
const setupInstructions = swapInstructionResponse.setupInstructions.map(
|
|
49749
|
+
deserializeJupiterInstruction
|
|
49750
|
+
);
|
|
49751
|
+
return {
|
|
49752
|
+
swapInstructions: [instruction],
|
|
49753
|
+
setupInstructions,
|
|
49754
|
+
addressLookupTableAddresses: addressLookupTableAccounts,
|
|
49755
|
+
quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
|
|
49756
|
+
};
|
|
48991
49757
|
};
|
|
48992
49758
|
|
|
48993
49759
|
// src/services/account/utils/misc.utils.ts
|
|
@@ -49005,6 +49771,440 @@ function isWholePosition(position, amount, mintDecimals) {
|
|
|
49005
49771
|
const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
|
|
49006
49772
|
return amount >= closePositionTokenAmount;
|
|
49007
49773
|
}
|
|
49774
|
+
var SWAP_MERGE_OVERHEAD = 150;
|
|
49775
|
+
var FL_IX_OVERHEAD = 52;
|
|
49776
|
+
function compactU16Size(n) {
|
|
49777
|
+
return n < 128 ? 1 : n < 16384 ? 2 : 3;
|
|
49778
|
+
}
|
|
49779
|
+
function computeV0TxSize(ixs, payerKey, luts) {
|
|
49780
|
+
const keyMap = /* @__PURE__ */ new Map();
|
|
49781
|
+
const payerStr = payerKey.toBase58();
|
|
49782
|
+
keyMap.set(payerStr, { isSigner: true, isWritable: true });
|
|
49783
|
+
const programIds = /* @__PURE__ */ new Set();
|
|
49784
|
+
for (const ix of ixs) {
|
|
49785
|
+
const progStr = ix.programId.toBase58();
|
|
49786
|
+
programIds.add(progStr);
|
|
49787
|
+
if (!keyMap.has(progStr)) {
|
|
49788
|
+
keyMap.set(progStr, { isSigner: false, isWritable: false });
|
|
49789
|
+
}
|
|
49790
|
+
for (const meta of ix.keys) {
|
|
49791
|
+
const keyStr = meta.pubkey.toBase58();
|
|
49792
|
+
const existing = keyMap.get(keyStr);
|
|
49793
|
+
if (existing) {
|
|
49794
|
+
existing.isSigner = existing.isSigner || meta.isSigner;
|
|
49795
|
+
existing.isWritable = existing.isWritable || meta.isWritable;
|
|
49796
|
+
} else {
|
|
49797
|
+
keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
|
|
49798
|
+
}
|
|
49799
|
+
}
|
|
49800
|
+
}
|
|
49801
|
+
const lutLookup = /* @__PURE__ */ new Map();
|
|
49802
|
+
for (let li = 0; li < luts.length; li++) {
|
|
49803
|
+
const addresses = luts[li].state.addresses;
|
|
49804
|
+
for (let ai = 0; ai < addresses.length; ai++) {
|
|
49805
|
+
const addrStr = addresses[ai].toBase58();
|
|
49806
|
+
if (!lutLookup.has(addrStr)) {
|
|
49807
|
+
lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
|
|
49808
|
+
}
|
|
49809
|
+
}
|
|
49810
|
+
}
|
|
49811
|
+
let numStaticKeys = 0;
|
|
49812
|
+
let numWritableStaticKeys = 0;
|
|
49813
|
+
const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
|
|
49814
|
+
const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
|
|
49815
|
+
for (const [keyStr, props] of keyMap) {
|
|
49816
|
+
if (props.isSigner || programIds.has(keyStr)) {
|
|
49817
|
+
numStaticKeys++;
|
|
49818
|
+
if (props.isWritable) numWritableStaticKeys++;
|
|
49819
|
+
continue;
|
|
49820
|
+
}
|
|
49821
|
+
const lutEntry = lutLookup.get(keyStr);
|
|
49822
|
+
if (lutEntry) {
|
|
49823
|
+
if (props.isWritable) {
|
|
49824
|
+
lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
|
|
49825
|
+
} else {
|
|
49826
|
+
lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
|
|
49827
|
+
}
|
|
49828
|
+
} else {
|
|
49829
|
+
numStaticKeys++;
|
|
49830
|
+
if (props.isWritable) numWritableStaticKeys++;
|
|
49831
|
+
}
|
|
49832
|
+
}
|
|
49833
|
+
const fixedOverhead = 101;
|
|
49834
|
+
const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
|
|
49835
|
+
let ixSection = compactU16Size(ixs.length);
|
|
49836
|
+
for (const ix of ixs) {
|
|
49837
|
+
const numAccounts = ix.keys.length;
|
|
49838
|
+
ixSection += 1 + // programId index
|
|
49839
|
+
compactU16Size(numAccounts) + numAccounts + // account key indexes
|
|
49840
|
+
compactU16Size(ix.data.length) + ix.data.length;
|
|
49841
|
+
}
|
|
49842
|
+
let numUsedLuts = 0;
|
|
49843
|
+
let lutSection = 0;
|
|
49844
|
+
for (let li = 0; li < luts.length; li++) {
|
|
49845
|
+
const wCount = lutWritableIdxs[li].size;
|
|
49846
|
+
const rCount = lutReadonlyIdxs[li].size;
|
|
49847
|
+
if (wCount === 0 && rCount === 0) continue;
|
|
49848
|
+
numUsedLuts++;
|
|
49849
|
+
lutSection += 32 + // LUT address
|
|
49850
|
+
compactU16Size(wCount) + wCount + // writable indexes
|
|
49851
|
+
compactU16Size(rCount) + rCount;
|
|
49852
|
+
}
|
|
49853
|
+
lutSection += compactU16Size(numUsedLuts);
|
|
49854
|
+
let totalLutKeys = 0;
|
|
49855
|
+
for (let li = 0; li < luts.length; li++) {
|
|
49856
|
+
totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
|
|
49857
|
+
}
|
|
49858
|
+
const accountCount = numStaticKeys + totalLutKeys;
|
|
49859
|
+
let totalLutWritableKeys = 0;
|
|
49860
|
+
for (let li = 0; li < luts.length; li++) {
|
|
49861
|
+
totalLutWritableKeys += lutWritableIdxs[li].size;
|
|
49862
|
+
}
|
|
49863
|
+
const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
|
|
49864
|
+
const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
|
|
49865
|
+
return { size, accountCount, writableAccountCount };
|
|
49866
|
+
}
|
|
49867
|
+
function computeFlashLoanNonSwapBudget({
|
|
49868
|
+
program,
|
|
49869
|
+
marginfiAccount,
|
|
49870
|
+
ixs,
|
|
49871
|
+
bankMap,
|
|
49872
|
+
addressLookupTableAccounts
|
|
49873
|
+
}) {
|
|
49874
|
+
const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
|
|
49875
|
+
marginfiAccount.balances,
|
|
49876
|
+
ixs,
|
|
49877
|
+
program
|
|
49878
|
+
);
|
|
49879
|
+
const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
|
|
49880
|
+
const b = bankMap.get(key.toBase58());
|
|
49881
|
+
if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
|
|
49882
|
+
return b;
|
|
49883
|
+
});
|
|
49884
|
+
const endIndex = ixs.length + 1;
|
|
49885
|
+
const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
|
|
49886
|
+
program.programId,
|
|
49887
|
+
{ marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
|
|
49888
|
+
{ endIndex: new BN11__default.default(endIndex) }
|
|
49889
|
+
);
|
|
49890
|
+
const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
|
|
49891
|
+
const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
|
|
49892
|
+
program.programId,
|
|
49893
|
+
{ marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
|
|
49894
|
+
endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
|
|
49895
|
+
);
|
|
49896
|
+
const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
|
|
49897
|
+
const nonSwapMsg = new web3_js.TransactionMessage({
|
|
49898
|
+
payerKey: marginfiAccount.authority,
|
|
49899
|
+
recentBlockhash: web3_js.PublicKey.default.toBase58(),
|
|
49900
|
+
instructions: allNonSwapIxs
|
|
49901
|
+
}).compileToV0Message(addressLookupTableAccounts);
|
|
49902
|
+
const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
|
|
49903
|
+
const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
|
|
49904
|
+
const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
|
|
49905
|
+
(s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
|
|
49906
|
+
0
|
|
49907
|
+
);
|
|
49908
|
+
const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
|
|
49909
|
+
const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
|
|
49910
|
+
console.log("[flashloan-budget]", {
|
|
49911
|
+
method: "compiled",
|
|
49912
|
+
nonSwapSize,
|
|
49913
|
+
nonSwapTotal,
|
|
49914
|
+
sizeConstraint,
|
|
49915
|
+
maxSwapTotalAccounts
|
|
49916
|
+
});
|
|
49917
|
+
return { sizeConstraint, maxSwapTotalAccounts };
|
|
49918
|
+
}
|
|
49919
|
+
function compileFlashloanPrecheck({
|
|
49920
|
+
allIxs,
|
|
49921
|
+
payer,
|
|
49922
|
+
luts,
|
|
49923
|
+
sizeConstraint,
|
|
49924
|
+
swapIxCount,
|
|
49925
|
+
swapLutCount
|
|
49926
|
+
}) {
|
|
49927
|
+
const msg = new web3_js.TransactionMessage({
|
|
49928
|
+
payerKey: payer,
|
|
49929
|
+
recentBlockhash: web3_js.PublicKey.default.toBase58(),
|
|
49930
|
+
instructions: allIxs
|
|
49931
|
+
}).compileToV0Message(luts);
|
|
49932
|
+
const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
|
|
49933
|
+
const fullTxSize = rawSize + FL_IX_OVERHEAD;
|
|
49934
|
+
const overshoot = fullTxSize - MAX_TX_SIZE;
|
|
49935
|
+
const { header, staticAccountKeys, addressTableLookups } = msg;
|
|
49936
|
+
const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
|
|
49937
|
+
const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
|
|
49938
|
+
const writableAccounts = writableStatic + writableLut;
|
|
49939
|
+
const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
|
|
49940
|
+
(s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
|
|
49941
|
+
0
|
|
49942
|
+
);
|
|
49943
|
+
console.log("[flashloan-precheck]", {
|
|
49944
|
+
fullTxSize,
|
|
49945
|
+
overshoot,
|
|
49946
|
+
sizeConstraint,
|
|
49947
|
+
writableAccounts,
|
|
49948
|
+
totalAccounts,
|
|
49949
|
+
staticKeys: staticAccountKeys.length,
|
|
49950
|
+
numLuts: addressTableLookups.length,
|
|
49951
|
+
swapIxCount,
|
|
49952
|
+
swapLutCount
|
|
49953
|
+
});
|
|
49954
|
+
return { fullTxSize, overshoot, writableAccounts, totalAccounts };
|
|
49955
|
+
}
|
|
49956
|
+
async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
|
|
49957
|
+
const { bank, tokenProgram } = config;
|
|
49958
|
+
switch (config.type) {
|
|
49959
|
+
case "borrow":
|
|
49960
|
+
return makeBorrowIx3({
|
|
49961
|
+
program,
|
|
49962
|
+
bank,
|
|
49963
|
+
bankMap,
|
|
49964
|
+
tokenProgram,
|
|
49965
|
+
amount: 1,
|
|
49966
|
+
marginfiAccount,
|
|
49967
|
+
authority: marginfiAccount.authority,
|
|
49968
|
+
isSync: true,
|
|
49969
|
+
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
49970
|
+
});
|
|
49971
|
+
case "repay":
|
|
49972
|
+
return makeRepayIx3({
|
|
49973
|
+
program,
|
|
49974
|
+
bank,
|
|
49975
|
+
tokenProgram,
|
|
49976
|
+
amount: 1,
|
|
49977
|
+
accountAddress: marginfiAccount.address,
|
|
49978
|
+
authority: marginfiAccount.authority,
|
|
49979
|
+
repayAll: false,
|
|
49980
|
+
isSync: true,
|
|
49981
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
49982
|
+
});
|
|
49983
|
+
case "deposit":
|
|
49984
|
+
return buildDepositBudgetIx(
|
|
49985
|
+
config,
|
|
49986
|
+
program,
|
|
49987
|
+
marginfiAccount,
|
|
49988
|
+
bankMetadataMap,
|
|
49989
|
+
overrideInferAccounts
|
|
49990
|
+
);
|
|
49991
|
+
case "withdraw":
|
|
49992
|
+
return buildWithdrawBudgetIx(
|
|
49993
|
+
config,
|
|
49994
|
+
program,
|
|
49995
|
+
marginfiAccount,
|
|
49996
|
+
bankMap,
|
|
49997
|
+
bankMetadataMap,
|
|
49998
|
+
overrideInferAccounts
|
|
49999
|
+
);
|
|
50000
|
+
}
|
|
50001
|
+
}
|
|
50002
|
+
async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
|
|
50003
|
+
const { bank, tokenProgram } = config;
|
|
50004
|
+
const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
|
|
50005
|
+
switch (bank.config.assetTag) {
|
|
50006
|
+
case 3 /* KAMINO */: {
|
|
50007
|
+
const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
50008
|
+
if (!reserve) {
|
|
50009
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
50010
|
+
bank.address.toBase58(),
|
|
50011
|
+
bank.mint.toBase58(),
|
|
50012
|
+
bank.tokenSymbol
|
|
50013
|
+
);
|
|
50014
|
+
}
|
|
50015
|
+
return makeKaminoDepositIx3({
|
|
50016
|
+
program,
|
|
50017
|
+
bank,
|
|
50018
|
+
tokenProgram,
|
|
50019
|
+
amount: 1,
|
|
50020
|
+
accountAddress: marginfiAccount.address,
|
|
50021
|
+
authority: marginfiAccount.authority,
|
|
50022
|
+
group: marginfiAccount.group,
|
|
50023
|
+
reserve,
|
|
50024
|
+
isSync: true,
|
|
50025
|
+
opts
|
|
50026
|
+
});
|
|
50027
|
+
}
|
|
50028
|
+
case 4 /* DRIFT */: {
|
|
50029
|
+
const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
|
|
50030
|
+
if (!driftState) {
|
|
50031
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
50032
|
+
bank.address.toBase58(),
|
|
50033
|
+
bank.mint.toBase58(),
|
|
50034
|
+
bank.tokenSymbol
|
|
50035
|
+
);
|
|
50036
|
+
}
|
|
50037
|
+
return makeDriftDepositIx3({
|
|
50038
|
+
program,
|
|
50039
|
+
bank,
|
|
50040
|
+
tokenProgram,
|
|
50041
|
+
amount: 1,
|
|
50042
|
+
accountAddress: marginfiAccount.address,
|
|
50043
|
+
authority: marginfiAccount.authority,
|
|
50044
|
+
group: marginfiAccount.group,
|
|
50045
|
+
driftMarketIndex: driftState.spotMarketState.marketIndex,
|
|
50046
|
+
driftOracle: driftState.spotMarketState.oracle,
|
|
50047
|
+
isSync: true,
|
|
50048
|
+
opts
|
|
50049
|
+
});
|
|
50050
|
+
}
|
|
50051
|
+
case 6 /* JUPLEND */: {
|
|
50052
|
+
return makeJuplendDepositIx2({
|
|
50053
|
+
program,
|
|
50054
|
+
bank,
|
|
50055
|
+
tokenProgram,
|
|
50056
|
+
amount: 1,
|
|
50057
|
+
accountAddress: marginfiAccount.address,
|
|
50058
|
+
authority: marginfiAccount.authority,
|
|
50059
|
+
group: marginfiAccount.group,
|
|
50060
|
+
isSync: true,
|
|
50061
|
+
opts
|
|
50062
|
+
});
|
|
50063
|
+
}
|
|
50064
|
+
default: {
|
|
50065
|
+
return makeDepositIx3({
|
|
50066
|
+
program,
|
|
50067
|
+
bank,
|
|
50068
|
+
tokenProgram,
|
|
50069
|
+
amount: 1,
|
|
50070
|
+
accountAddress: marginfiAccount.address,
|
|
50071
|
+
authority: marginfiAccount.authority,
|
|
50072
|
+
group: marginfiAccount.group,
|
|
50073
|
+
isSync: true,
|
|
50074
|
+
opts
|
|
50075
|
+
});
|
|
50076
|
+
}
|
|
50077
|
+
}
|
|
50078
|
+
}
|
|
50079
|
+
async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
|
|
50080
|
+
const { bank, tokenProgram } = config;
|
|
50081
|
+
const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
|
|
50082
|
+
switch (bank.config.assetTag) {
|
|
50083
|
+
case 3 /* KAMINO */: {
|
|
50084
|
+
const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
50085
|
+
if (!reserve) {
|
|
50086
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
50087
|
+
bank.address.toBase58(),
|
|
50088
|
+
bank.mint.toBase58(),
|
|
50089
|
+
bank.tokenSymbol
|
|
50090
|
+
);
|
|
50091
|
+
}
|
|
50092
|
+
return makeKaminoWithdrawIx3({
|
|
50093
|
+
program,
|
|
50094
|
+
bank,
|
|
50095
|
+
bankMap,
|
|
50096
|
+
tokenProgram,
|
|
50097
|
+
cTokenAmount: 1,
|
|
50098
|
+
marginfiAccount,
|
|
50099
|
+
authority: marginfiAccount.authority,
|
|
50100
|
+
reserve,
|
|
50101
|
+
withdrawAll: false,
|
|
50102
|
+
isSync: true,
|
|
50103
|
+
opts
|
|
50104
|
+
});
|
|
50105
|
+
}
|
|
50106
|
+
case 4 /* DRIFT */: {
|
|
50107
|
+
const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
|
|
50108
|
+
if (!driftState) {
|
|
50109
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
50110
|
+
bank.address.toBase58(),
|
|
50111
|
+
bank.mint.toBase58(),
|
|
50112
|
+
bank.tokenSymbol
|
|
50113
|
+
);
|
|
50114
|
+
}
|
|
50115
|
+
return makeDriftWithdrawIx3({
|
|
50116
|
+
program,
|
|
50117
|
+
bank,
|
|
50118
|
+
bankMap,
|
|
50119
|
+
tokenProgram,
|
|
50120
|
+
amount: 1,
|
|
50121
|
+
marginfiAccount,
|
|
50122
|
+
authority: marginfiAccount.authority,
|
|
50123
|
+
driftSpotMarket: driftState.spotMarketState,
|
|
50124
|
+
userRewards: driftState.userRewards,
|
|
50125
|
+
withdrawAll: false,
|
|
50126
|
+
isSync: true,
|
|
50127
|
+
opts
|
|
50128
|
+
});
|
|
50129
|
+
}
|
|
50130
|
+
case 6 /* JUPLEND */: {
|
|
50131
|
+
const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
|
|
50132
|
+
if (!jupLendState) {
|
|
50133
|
+
throw TransactionBuildingError.jupLendStateNotFound(
|
|
50134
|
+
bank.address.toBase58(),
|
|
50135
|
+
bank.mint.toBase58(),
|
|
50136
|
+
bank.tokenSymbol
|
|
50137
|
+
);
|
|
50138
|
+
}
|
|
50139
|
+
return makeJuplendWithdrawIx2({
|
|
50140
|
+
program,
|
|
50141
|
+
bank,
|
|
50142
|
+
bankMap,
|
|
50143
|
+
tokenProgram,
|
|
50144
|
+
amount: 1,
|
|
50145
|
+
marginfiAccount,
|
|
50146
|
+
authority: marginfiAccount.authority,
|
|
50147
|
+
jupLendingState: jupLendState.jupLendingState,
|
|
50148
|
+
withdrawAll: false,
|
|
50149
|
+
opts
|
|
50150
|
+
});
|
|
50151
|
+
}
|
|
50152
|
+
default: {
|
|
50153
|
+
return makeWithdrawIx3({
|
|
50154
|
+
program,
|
|
50155
|
+
bank,
|
|
50156
|
+
bankMap,
|
|
50157
|
+
tokenProgram,
|
|
50158
|
+
amount: 1,
|
|
50159
|
+
marginfiAccount,
|
|
50160
|
+
authority: marginfiAccount.authority,
|
|
50161
|
+
withdrawAll: false,
|
|
50162
|
+
isSync: true,
|
|
50163
|
+
opts
|
|
50164
|
+
});
|
|
50165
|
+
}
|
|
50166
|
+
}
|
|
50167
|
+
}
|
|
50168
|
+
async function computeFlashloanSwapConstraints({
|
|
50169
|
+
program,
|
|
50170
|
+
marginfiAccount,
|
|
50171
|
+
bankMap,
|
|
50172
|
+
addressLookupTableAccounts,
|
|
50173
|
+
bankMetadataMap,
|
|
50174
|
+
primaryIx,
|
|
50175
|
+
secondaryIx,
|
|
50176
|
+
overrideInferAccounts
|
|
50177
|
+
}) {
|
|
50178
|
+
const cuRequestIxs = [
|
|
50179
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
50180
|
+
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
50181
|
+
];
|
|
50182
|
+
const [primaryResult, secondaryResult] = await Promise.all([
|
|
50183
|
+
buildBudgetIx(
|
|
50184
|
+
primaryIx,
|
|
50185
|
+
program,
|
|
50186
|
+
marginfiAccount,
|
|
50187
|
+
bankMap,
|
|
50188
|
+
bankMetadataMap,
|
|
50189
|
+
overrideInferAccounts
|
|
50190
|
+
),
|
|
50191
|
+
buildBudgetIx(
|
|
50192
|
+
secondaryIx,
|
|
50193
|
+
program,
|
|
50194
|
+
marginfiAccount,
|
|
50195
|
+
bankMap,
|
|
50196
|
+
bankMetadataMap,
|
|
50197
|
+
overrideInferAccounts
|
|
50198
|
+
)
|
|
50199
|
+
]);
|
|
50200
|
+
return computeFlashLoanNonSwapBudget({
|
|
50201
|
+
program,
|
|
50202
|
+
marginfiAccount,
|
|
50203
|
+
bankMap,
|
|
50204
|
+
addressLookupTableAccounts,
|
|
50205
|
+
ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
|
|
50206
|
+
});
|
|
50207
|
+
}
|
|
49008
50208
|
|
|
49009
50209
|
// src/services/price/utils/smart-crank.utils.ts
|
|
49010
50210
|
async function computeSmartCrank({
|
|
@@ -50208,7 +51408,7 @@ function computeMaxLeverage(depositBank, borrowBank, opts) {
|
|
|
50208
51408
|
ltv
|
|
50209
51409
|
};
|
|
50210
51410
|
}
|
|
50211
|
-
function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank,
|
|
51411
|
+
function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank, depositPriceUsd, borrowPriceUsd, opts) {
|
|
50212
51412
|
const initialCollateral = toBigNumber(principal);
|
|
50213
51413
|
const { maxLeverage } = computeMaxLeverage(depositBank, borrowBank, opts);
|
|
50214
51414
|
let clampedLeverage = targetLeverage;
|
|
@@ -50223,7 +51423,7 @@ function computeLoopingParams(principal, targetLeverage, depositBank, borrowBank
|
|
|
50223
51423
|
}
|
|
50224
51424
|
const totalDepositAmount = initialCollateral.times(new BigNumber3__default.default(clampedLeverage));
|
|
50225
51425
|
const additionalDepositAmount = totalDepositAmount.minus(initialCollateral);
|
|
50226
|
-
const totalBorrowAmount = additionalDepositAmount.times(
|
|
51426
|
+
const totalBorrowAmount = additionalDepositAmount.times(new BigNumber3__default.default(depositPriceUsd)).div(new BigNumber3__default.default(borrowPriceUsd));
|
|
50227
51427
|
return {
|
|
50228
51428
|
totalBorrowAmount: totalBorrowAmount.decimalPlaces(
|
|
50229
51429
|
borrowBank.mintDecimals,
|
|
@@ -51267,6 +52467,230 @@ function getValidatorVoteAccountByBank() {
|
|
|
51267
52467
|
}
|
|
51268
52468
|
return _voteAccountByBank;
|
|
51269
52469
|
}
|
|
52470
|
+
async function computeStakedBankMultipliers(stakedBanks, connection) {
|
|
52471
|
+
const multiplierByBank = /* @__PURE__ */ new Map();
|
|
52472
|
+
if (stakedBanks.length === 0) {
|
|
52473
|
+
return multiplierByBank;
|
|
52474
|
+
}
|
|
52475
|
+
const metadataMap = getStakedBankMetadataMap();
|
|
52476
|
+
const stakedBankAddresses = [];
|
|
52477
|
+
const poolStakeAddresses = [];
|
|
52478
|
+
const lstMintAddresses = [];
|
|
52479
|
+
for (const bank of stakedBanks) {
|
|
52480
|
+
const metadata = metadataMap.get(bank.address.toBase58());
|
|
52481
|
+
if (!metadata) {
|
|
52482
|
+
multiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
|
|
52483
|
+
continue;
|
|
52484
|
+
}
|
|
52485
|
+
const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
|
|
52486
|
+
stakedBankAddresses.push(bank.address.toBase58());
|
|
52487
|
+
poolStakeAddresses.push(findPoolStakeAddress(pool));
|
|
52488
|
+
lstMintAddresses.push(findPoolMintAddress(pool));
|
|
52489
|
+
}
|
|
52490
|
+
if (stakedBankAddresses.length === 0) {
|
|
52491
|
+
return multiplierByBank;
|
|
52492
|
+
}
|
|
52493
|
+
const allAddresses = [
|
|
52494
|
+
...poolStakeAddresses.map((a) => a.toBase58()),
|
|
52495
|
+
...lstMintAddresses.map((a) => a.toBase58())
|
|
52496
|
+
];
|
|
52497
|
+
const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses);
|
|
52498
|
+
const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
|
|
52499
|
+
const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
|
|
52500
|
+
for (let i = 0; i < stakedBankAddresses.length; i++) {
|
|
52501
|
+
const bankAddr = stakedBankAddresses[i];
|
|
52502
|
+
const poolStakeInfo = poolStakeInfos[i];
|
|
52503
|
+
const lstMintInfo = lstMintInfos[i];
|
|
52504
|
+
if (!poolStakeInfo || !lstMintInfo) {
|
|
52505
|
+
multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
|
|
52506
|
+
continue;
|
|
52507
|
+
}
|
|
52508
|
+
const stakeLamports = poolStakeInfo.lamports;
|
|
52509
|
+
const supplyBuffer = lstMintInfo.data.slice(36, 44);
|
|
52510
|
+
const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
|
|
52511
|
+
if (lstMintSupply === 0) {
|
|
52512
|
+
multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
|
|
52513
|
+
continue;
|
|
52514
|
+
}
|
|
52515
|
+
const adjustedStake = Math.max(stakeLamports - web3_js.LAMPORTS_PER_SOL, 0);
|
|
52516
|
+
const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
|
|
52517
|
+
multiplierByBank.set(bankAddr, multiplier);
|
|
52518
|
+
}
|
|
52519
|
+
return multiplierByBank;
|
|
52520
|
+
}
|
|
52521
|
+
var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
|
|
52522
|
+
async function makeMintStakedLstIx(params) {
|
|
52523
|
+
const { amount, authority, stakeAccountPk, validator, connection } = params;
|
|
52524
|
+
const pool = findPoolAddress(validator);
|
|
52525
|
+
const lstMint = findPoolMintAddress(pool);
|
|
52526
|
+
const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
|
|
52527
|
+
const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
|
|
52528
|
+
const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
|
|
52529
|
+
connection.getAccountInfo(lstAta),
|
|
52530
|
+
connection.getParsedAccountInfo(stakeAccountPk),
|
|
52531
|
+
connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space)
|
|
52532
|
+
]);
|
|
52533
|
+
const stakeAccParsed = stakeAccInfoParsed?.value?.data;
|
|
52534
|
+
const amountLamports = Math.round(Number(amount) * web3_js.LAMPORTS_PER_SOL);
|
|
52535
|
+
const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
|
|
52536
|
+
const isFullStake = amountLamports >= stakeAccLamports;
|
|
52537
|
+
const instructions2 = [];
|
|
52538
|
+
const signers = [];
|
|
52539
|
+
if (!lstAccInfo) {
|
|
52540
|
+
instructions2.push(
|
|
52541
|
+
createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
|
|
52542
|
+
);
|
|
52543
|
+
}
|
|
52544
|
+
let targetStakePubkey;
|
|
52545
|
+
if (!isFullStake) {
|
|
52546
|
+
const splitStakeAccount = web3_js.Keypair.generate();
|
|
52547
|
+
signers.push(splitStakeAccount);
|
|
52548
|
+
targetStakePubkey = splitStakeAccount.publicKey;
|
|
52549
|
+
instructions2.push(
|
|
52550
|
+
...web3_js.StakeProgram.split(
|
|
52551
|
+
{
|
|
52552
|
+
stakePubkey: stakeAccountPk,
|
|
52553
|
+
authorizedPubkey: authority,
|
|
52554
|
+
splitStakePubkey: splitStakeAccount.publicKey,
|
|
52555
|
+
lamports: amountLamports
|
|
52556
|
+
},
|
|
52557
|
+
rentExemptReserve
|
|
52558
|
+
).instructions
|
|
52559
|
+
);
|
|
52560
|
+
} else {
|
|
52561
|
+
targetStakePubkey = stakeAccountPk;
|
|
52562
|
+
}
|
|
52563
|
+
const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
|
|
52564
|
+
web3_js.StakeProgram.authorize({
|
|
52565
|
+
stakePubkey: targetStakePubkey,
|
|
52566
|
+
authorizedPubkey: authority,
|
|
52567
|
+
newAuthorizedPubkey: poolStakeAuth,
|
|
52568
|
+
stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Staker
|
|
52569
|
+
}).instructions,
|
|
52570
|
+
web3_js.StakeProgram.authorize({
|
|
52571
|
+
stakePubkey: targetStakePubkey,
|
|
52572
|
+
authorizedPubkey: authority,
|
|
52573
|
+
newAuthorizedPubkey: poolStakeAuth,
|
|
52574
|
+
stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Withdrawer
|
|
52575
|
+
}).instructions
|
|
52576
|
+
]);
|
|
52577
|
+
[authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
|
|
52578
|
+
if (ix) {
|
|
52579
|
+
ix.keys = ix.keys.map((key) => ({
|
|
52580
|
+
...key,
|
|
52581
|
+
isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
|
|
52582
|
+
}));
|
|
52583
|
+
}
|
|
52584
|
+
});
|
|
52585
|
+
instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
|
|
52586
|
+
const depositStakeIx = await SinglePoolInstruction.depositStake(
|
|
52587
|
+
pool,
|
|
52588
|
+
targetStakePubkey,
|
|
52589
|
+
lstAta,
|
|
52590
|
+
authority
|
|
52591
|
+
);
|
|
52592
|
+
instructions2.push(depositStakeIx);
|
|
52593
|
+
return { instructions: instructions2, keys: signers };
|
|
52594
|
+
}
|
|
52595
|
+
async function makeMintStakedLstTx(params) {
|
|
52596
|
+
const { connection, luts, blockhash: providedBlockhash } = params;
|
|
52597
|
+
const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
|
|
52598
|
+
const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
52599
|
+
const message = new web3_js.TransactionMessage({
|
|
52600
|
+
payerKey: params.authority,
|
|
52601
|
+
recentBlockhash: blockhash,
|
|
52602
|
+
instructions: instructions2
|
|
52603
|
+
}).compileToV0Message(luts);
|
|
52604
|
+
const tx = new web3_js.VersionedTransaction(message);
|
|
52605
|
+
return addTransactionMetadata(tx, {
|
|
52606
|
+
signers: keys,
|
|
52607
|
+
addressLookupTables: luts,
|
|
52608
|
+
type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
|
|
52609
|
+
});
|
|
52610
|
+
}
|
|
52611
|
+
async function makeRedeemStakedLstIx(params) {
|
|
52612
|
+
const { amount, authority, validator, connection } = params;
|
|
52613
|
+
const pool = findPoolAddress(validator);
|
|
52614
|
+
const lstMint = findPoolMintAddress(pool);
|
|
52615
|
+
const mintAuthority = findPoolMintAuthorityAddress(pool);
|
|
52616
|
+
const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
|
|
52617
|
+
const rentExemption = await connection.getMinimumBalanceForRentExemption(
|
|
52618
|
+
web3_js.StakeProgram.space
|
|
52619
|
+
);
|
|
52620
|
+
const stakeAmount = new BigNumber3__default.default(new BigNumber3__default.default(amount).toString());
|
|
52621
|
+
const instructions2 = [];
|
|
52622
|
+
const signers = [];
|
|
52623
|
+
const stakeAccount = web3_js.Keypair.generate();
|
|
52624
|
+
signers.push(stakeAccount);
|
|
52625
|
+
instructions2.push(
|
|
52626
|
+
web3_js.SystemProgram.createAccount({
|
|
52627
|
+
fromPubkey: authority,
|
|
52628
|
+
newAccountPubkey: stakeAccount.publicKey,
|
|
52629
|
+
lamports: rentExemption,
|
|
52630
|
+
space: web3_js.StakeProgram.space,
|
|
52631
|
+
programId: web3_js.StakeProgram.programId
|
|
52632
|
+
})
|
|
52633
|
+
);
|
|
52634
|
+
instructions2.push(
|
|
52635
|
+
createApproveInstruction(
|
|
52636
|
+
lstAta,
|
|
52637
|
+
mintAuthority,
|
|
52638
|
+
authority,
|
|
52639
|
+
BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
|
|
52640
|
+
)
|
|
52641
|
+
);
|
|
52642
|
+
const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
|
|
52643
|
+
pool,
|
|
52644
|
+
stakeAccount.publicKey,
|
|
52645
|
+
authority,
|
|
52646
|
+
lstAta,
|
|
52647
|
+
stakeAmount
|
|
52648
|
+
);
|
|
52649
|
+
instructions2.push(withdrawStakeIx);
|
|
52650
|
+
return { instructions: instructions2, keys: signers };
|
|
52651
|
+
}
|
|
52652
|
+
async function makeRedeemStakedLstTx(params) {
|
|
52653
|
+
const { connection, luts, blockhash: providedBlockhash } = params;
|
|
52654
|
+
const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
|
|
52655
|
+
const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
52656
|
+
const message = new web3_js.TransactionMessage({
|
|
52657
|
+
payerKey: params.authority,
|
|
52658
|
+
recentBlockhash: blockhash,
|
|
52659
|
+
instructions: instructions2
|
|
52660
|
+
}).compileToV0Message(luts);
|
|
52661
|
+
const tx = new web3_js.VersionedTransaction(message);
|
|
52662
|
+
return addTransactionMetadata(tx, {
|
|
52663
|
+
signers: keys,
|
|
52664
|
+
addressLookupTables: luts,
|
|
52665
|
+
type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
|
|
52666
|
+
});
|
|
52667
|
+
}
|
|
52668
|
+
async function makeMergeStakeAccountsTx(params) {
|
|
52669
|
+
const {
|
|
52670
|
+
authority,
|
|
52671
|
+
sourceStakeAccount,
|
|
52672
|
+
destinationStakeAccount,
|
|
52673
|
+
connection,
|
|
52674
|
+
luts,
|
|
52675
|
+
blockhash: providedBlockhash
|
|
52676
|
+
} = params;
|
|
52677
|
+
const mergeIx = web3_js.StakeProgram.merge({
|
|
52678
|
+
stakePubkey: destinationStakeAccount,
|
|
52679
|
+
sourceStakePubKey: sourceStakeAccount,
|
|
52680
|
+
authorizedPubkey: authority
|
|
52681
|
+
}).instructions;
|
|
52682
|
+
const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
52683
|
+
const message = new web3_js.TransactionMessage({
|
|
52684
|
+
payerKey: authority,
|
|
52685
|
+
recentBlockhash: blockhash,
|
|
52686
|
+
instructions: mergeIx
|
|
52687
|
+
}).compileToV0Message(luts);
|
|
52688
|
+
const tx = new web3_js.VersionedTransaction(message);
|
|
52689
|
+
return addTransactionMetadata(tx, {
|
|
52690
|
+
addressLookupTables: luts,
|
|
52691
|
+
type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
|
|
52692
|
+
});
|
|
52693
|
+
}
|
|
51270
52694
|
async function getKaminoMetadata(options) {
|
|
51271
52695
|
const kaminoBanks = options.banks.filter((b) => b.config.assetTag === 3 /* KAMINO */);
|
|
51272
52696
|
const DEFAULT_PUBKEY = web3_js.PublicKey.default;
|
|
@@ -52690,7 +54114,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52690
54114
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52691
54115
|
* @param params.depositOpts - Deposit configuration (bank, amount, mode)
|
|
52692
54116
|
* @param params.borrowOpts - Borrow configuration (bank, amount)
|
|
52693
|
-
* @param params.swapOpts -
|
|
54117
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52694
54118
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52695
54119
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52696
54120
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52728,7 +54152,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52728
54152
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52729
54153
|
* @param params.withdrawOpts - Withdraw configuration (bank, amount)
|
|
52730
54154
|
* @param params.repayOpts - Repay configuration (bank, optional amount)
|
|
52731
|
-
* @param params.swapOpts -
|
|
54155
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52732
54156
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52733
54157
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52734
54158
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52768,7 +54192,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52768
54192
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52769
54193
|
* @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
|
|
52770
54194
|
* @param params.depositOpts - Deposit configuration (bank, tokenProgram)
|
|
52771
|
-
* @param params.swapOpts -
|
|
54195
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52772
54196
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52773
54197
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52774
54198
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -52808,7 +54232,7 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
52808
54232
|
* @param params.oraclePrices - Map of current oracle prices
|
|
52809
54233
|
* @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
|
|
52810
54234
|
* @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
|
|
52811
|
-
* @param params.swapOpts -
|
|
54235
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
52812
54236
|
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
52813
54237
|
* @param params.overrideInferAccounts - Optional account overrides
|
|
52814
54238
|
* @param params.additionalIxs - Additional instructions to include
|
|
@@ -53703,66 +55127,6 @@ var MarginfiAccountWrapper = class {
|
|
|
53703
55127
|
return this.account.getHealthCheckAccounts(this.client.bankMap, mandatoryBanks, excludedBanks);
|
|
53704
55128
|
}
|
|
53705
55129
|
// ----------------------------------------------------------------------------
|
|
53706
|
-
// Native stake actions
|
|
53707
|
-
// Note: These call standalone action functions directly rather than routing
|
|
53708
|
-
// through this.account because they interact with the SPL stake pool program,
|
|
53709
|
-
// not the marginfi program. No MarginfiAccount state is needed.
|
|
53710
|
-
// ----------------------------------------------------------------------------
|
|
53711
|
-
/**
|
|
53712
|
-
* Creates a transaction to mint LST from a native stake account.
|
|
53713
|
-
*
|
|
53714
|
-
* Converts a native stake account (or a portion of it) into LST tokens
|
|
53715
|
-
* by depositing the stake into the single-validator pool.
|
|
53716
|
-
*
|
|
53717
|
-
* @param amount - SOL amount to convert (in UI units)
|
|
53718
|
-
* @param stakeAccountPk - The stake account to convert
|
|
53719
|
-
* @param validator - The validator vote account
|
|
53720
|
-
*/
|
|
53721
|
-
async makeMintStakedLstTx(amount, stakeAccountPk, validator) {
|
|
53722
|
-
return makeMintStakedLstTx({
|
|
53723
|
-
amount,
|
|
53724
|
-
authority: this.authority,
|
|
53725
|
-
stakeAccountPk,
|
|
53726
|
-
validator,
|
|
53727
|
-
connection: this.client.program.provider.connection,
|
|
53728
|
-
luts: this.client.addressLookupTables
|
|
53729
|
-
});
|
|
53730
|
-
}
|
|
53731
|
-
/**
|
|
53732
|
-
* Creates a transaction to redeem LST tokens back to a native stake account.
|
|
53733
|
-
*
|
|
53734
|
-
* Burns LST tokens and withdraws the underlying stake into a new stake account.
|
|
53735
|
-
*
|
|
53736
|
-
* @param amount - LST amount to redeem (in UI units)
|
|
53737
|
-
* @param validator - The validator vote account
|
|
53738
|
-
*/
|
|
53739
|
-
async makeRedeemStakedLstTx(amount, validator) {
|
|
53740
|
-
return makeRedeemStakedLstTx({
|
|
53741
|
-
amount,
|
|
53742
|
-
authority: this.authority,
|
|
53743
|
-
validator,
|
|
53744
|
-
connection: this.client.program.provider.connection,
|
|
53745
|
-
luts: this.client.addressLookupTables
|
|
53746
|
-
});
|
|
53747
|
-
}
|
|
53748
|
-
/**
|
|
53749
|
-
* Creates a transaction to merge two stake accounts.
|
|
53750
|
-
*
|
|
53751
|
-
* Both accounts must share the same authorized staker/withdrawer and vote account.
|
|
53752
|
-
*
|
|
53753
|
-
* @param sourceStakeAccount - The stake account to merge from (will be consumed)
|
|
53754
|
-
* @param destinationStakeAccount - The stake account to merge into
|
|
53755
|
-
*/
|
|
53756
|
-
async makeMergeStakeAccountsTx(sourceStakeAccount, destinationStakeAccount) {
|
|
53757
|
-
return makeMergeStakeAccountsTx({
|
|
53758
|
-
authority: this.authority,
|
|
53759
|
-
sourceStakeAccount,
|
|
53760
|
-
destinationStakeAccount,
|
|
53761
|
-
connection: this.client.program.provider.connection,
|
|
53762
|
-
luts: this.client.addressLookupTables
|
|
53763
|
-
});
|
|
53764
|
-
}
|
|
53765
|
-
// ----------------------------------------------------------------------------
|
|
53766
55130
|
// Helper methods
|
|
53767
55131
|
// ----------------------------------------------------------------------------
|
|
53768
55132
|
/**
|
|
@@ -54032,56 +55396,11 @@ var Project0Client = class _Project0Client {
|
|
|
54032
55396
|
break;
|
|
54033
55397
|
}
|
|
54034
55398
|
});
|
|
54035
|
-
const
|
|
54036
|
-
|
|
54037
|
-
|
|
54038
|
-
|
|
54039
|
-
|
|
54040
|
-
const lstMintAddresses = [];
|
|
54041
|
-
for (const bank of stakedBanks) {
|
|
54042
|
-
const metadata = metadataMap.get(bank.address.toBase58());
|
|
54043
|
-
if (!metadata) {
|
|
54044
|
-
assetShareMultiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
|
|
54045
|
-
continue;
|
|
54046
|
-
}
|
|
54047
|
-
const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
|
|
54048
|
-
stakedBankAddresses.push(bank.address.toBase58());
|
|
54049
|
-
poolStakeAddresses.push(findPoolStakeAddress(pool));
|
|
54050
|
-
lstMintAddresses.push(findPoolMintAddress(pool));
|
|
54051
|
-
}
|
|
54052
|
-
if (stakedBankAddresses.length > 0) {
|
|
54053
|
-
const allAddresses = [
|
|
54054
|
-
...poolStakeAddresses.map((a) => a.toBase58()),
|
|
54055
|
-
...lstMintAddresses.map((a) => a.toBase58())
|
|
54056
|
-
];
|
|
54057
|
-
const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(
|
|
54058
|
-
connection,
|
|
54059
|
-
allAddresses
|
|
54060
|
-
);
|
|
54061
|
-
const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
|
|
54062
|
-
const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
|
|
54063
|
-
for (let i = 0; i < stakedBankAddresses.length; i++) {
|
|
54064
|
-
const bankAddr = stakedBankAddresses[i];
|
|
54065
|
-
const poolStakeInfo = poolStakeInfos[i];
|
|
54066
|
-
const lstMintInfo = lstMintInfos[i];
|
|
54067
|
-
if (!poolStakeInfo || !lstMintInfo) {
|
|
54068
|
-
assetShareMultiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
|
|
54069
|
-
continue;
|
|
54070
|
-
}
|
|
54071
|
-
const stakeLamports = poolStakeInfo.lamports;
|
|
54072
|
-
const supplyBuffer = lstMintInfo.data.slice(36, 44);
|
|
54073
|
-
const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
|
|
54074
|
-
if (lstMintSupply === 0) {
|
|
54075
|
-
assetShareMultiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
|
|
54076
|
-
continue;
|
|
54077
|
-
}
|
|
54078
|
-
const LAMPORTS_PER_SOL5 = 1e9;
|
|
54079
|
-
const adjustedStake = Math.max(stakeLamports - LAMPORTS_PER_SOL5, 0);
|
|
54080
|
-
const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
|
|
54081
|
-
assetShareMultiplierByBank.set(bankAddr, multiplier);
|
|
54082
|
-
}
|
|
54083
|
-
}
|
|
54084
|
-
}
|
|
55399
|
+
const stakedMultipliers = await computeStakedBankMultipliers(
|
|
55400
|
+
banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */),
|
|
55401
|
+
connection
|
|
55402
|
+
);
|
|
55403
|
+
stakedMultipliers.forEach((v, k) => assetShareMultiplierByBank.set(k, v));
|
|
54085
55404
|
const emodePairs = getEmodePairs(banksArray);
|
|
54086
55405
|
return new _Project0Client(
|
|
54087
55406
|
program,
|
|
@@ -54156,6 +55475,7 @@ exports.MARGINFI_PROGRAM = MARGINFI_PROGRAM;
|
|
|
54156
55475
|
exports.MARGINFI_PROGRAM_STAGING = MARGINFI_PROGRAM_STAGING;
|
|
54157
55476
|
exports.MARGINFI_PROGRAM_STAGING_ALT = MARGINFI_PROGRAM_STAGING_ALT;
|
|
54158
55477
|
exports.MARGINFI_SPONSORED_SHARD_ID = MARGINFI_SPONSORED_SHARD_ID;
|
|
55478
|
+
exports.MAX_ACCOUNT_LOCKS = MAX_ACCOUNT_LOCKS;
|
|
54159
55479
|
exports.MAX_CONFIDENCE_INTERVAL_RATIO = MAX_CONFIDENCE_INTERVAL_RATIO;
|
|
54160
55480
|
exports.MAX_TX_SIZE = MAX_TX_SIZE;
|
|
54161
55481
|
exports.MAX_U64 = MAX_U64;
|
|
@@ -54191,6 +55511,7 @@ exports.SYSTEM_PROGRAM_ID = SYSTEM_PROGRAM_ID;
|
|
|
54191
55511
|
exports.SYSVAR_CLOCK_ID = SYSVAR_CLOCK_ID;
|
|
54192
55512
|
exports.SYSVAR_RENT_ID = SYSVAR_RENT_ID;
|
|
54193
55513
|
exports.SYSVAR_STAKE_HISTORY_ID = SYSVAR_STAKE_HISTORY_ID;
|
|
55514
|
+
exports.SwapProvider = SwapProvider;
|
|
54194
55515
|
exports.TRANSFER_ACCOUNT_AUTHORITY_FLAG = TRANSFER_ACCOUNT_AUTHORITY_FLAG;
|
|
54195
55516
|
exports.TransactionArenaKeyMap = TransactionArenaKeyMap;
|
|
54196
55517
|
exports.TransactionBuildingError = TransactionBuildingError;
|
|
@@ -54224,6 +55545,7 @@ exports.checkMultipleOraclesCrankability = checkMultipleOraclesCrankability;
|
|
|
54224
55545
|
exports.chunkedGetRawMultipleAccountInfoOrdered = chunkedGetRawMultipleAccountInfoOrdered;
|
|
54225
55546
|
exports.chunkedGetRawMultipleAccountInfoOrderedWithNulls = chunkedGetRawMultipleAccountInfoOrderedWithNulls;
|
|
54226
55547
|
exports.chunkedGetRawMultipleAccountInfos = chunkedGetRawMultipleAccountInfos;
|
|
55548
|
+
exports.compileFlashloanPrecheck = compileFlashloanPrecheck;
|
|
54227
55549
|
exports.composeRemainingAccounts = composeRemainingAccounts;
|
|
54228
55550
|
exports.computeAccountValue = computeAccountValue;
|
|
54229
55551
|
exports.computeActiveEmodePairs = computeActiveEmodePairs;
|
|
@@ -54234,6 +55556,8 @@ exports.computeBaseInterestRate = computeBaseInterestRate;
|
|
|
54234
55556
|
exports.computeClaimedEmissions = computeClaimedEmissions;
|
|
54235
55557
|
exports.computeClosePositionTokenAmount = computeClosePositionTokenAmount;
|
|
54236
55558
|
exports.computeEmodeImpacts = computeEmodeImpacts;
|
|
55559
|
+
exports.computeFlashLoanNonSwapBudget = computeFlashLoanNonSwapBudget;
|
|
55560
|
+
exports.computeFlashloanSwapConstraints = computeFlashloanSwapConstraints;
|
|
54237
55561
|
exports.computeFreeCollateralFromBalances = computeFreeCollateralFromBalances;
|
|
54238
55562
|
exports.computeFreeCollateralFromCache = computeFreeCollateralFromCache;
|
|
54239
55563
|
exports.computeHealthAccountMetas = computeHealthAccountMetas;
|
|
@@ -54258,10 +55582,12 @@ exports.computeQuantity = computeQuantity;
|
|
|
54258
55582
|
exports.computeQuantityUi = computeQuantityUi;
|
|
54259
55583
|
exports.computeRemainingCapacity = computeRemainingCapacity;
|
|
54260
55584
|
exports.computeSmartCrank = computeSmartCrank;
|
|
55585
|
+
exports.computeStakedBankMultipliers = computeStakedBankMultipliers;
|
|
54261
55586
|
exports.computeTotalOutstandingEmissions = computeTotalOutstandingEmissions;
|
|
54262
55587
|
exports.computeTvl = computeTvl;
|
|
54263
55588
|
exports.computeUsdValue = computeUsdValue;
|
|
54264
55589
|
exports.computeUtilizationRate = computeUtilizationRate;
|
|
55590
|
+
exports.computeV0TxSize = computeV0TxSize;
|
|
54265
55591
|
exports.convertVoteAccCoeffsToBankCoeffs = convertVoteAccCoeffsToBankCoeffs;
|
|
54266
55592
|
exports.createActiveEmodePairFromPairs = createActiveEmodePairFromPairs;
|
|
54267
55593
|
exports.createEmptyBalance = createEmptyBalance;
|
|
@@ -54337,6 +55663,7 @@ exports.getDriftCTokenMultiplier = getDriftCTokenMultiplier;
|
|
|
54337
55663
|
exports.getDriftMetadata = getDriftMetadata;
|
|
54338
55664
|
exports.getDriftStatesDto = getDriftStatesDto;
|
|
54339
55665
|
exports.getEmodePairs = getEmodePairs;
|
|
55666
|
+
exports.getExactOutEstimate = getExactOutEstimate;
|
|
54340
55667
|
exports.getHealthCacheStatusDescription = getHealthCacheStatusDescription;
|
|
54341
55668
|
exports.getHealthSimulationTransactions = getHealthSimulationTransactions;
|
|
54342
55669
|
exports.getJupLendFTokenMultiplier = getJupLendFTokenMultiplier;
|
|
@@ -54355,10 +55682,15 @@ exports.getOracleSourceNameFromKey = getOracleSourceNameFromKey;
|
|
|
54355
55682
|
exports.getPrice = getPrice;
|
|
54356
55683
|
exports.getPriceWithConfidence = getPriceWithConfidence;
|
|
54357
55684
|
exports.getStakedBankMetadataMap = getStakedBankMetadataMap;
|
|
55685
|
+
exports.getSwapIxsForFlashloan = getSwapIxsForFlashloan;
|
|
55686
|
+
exports.getTitanExactOutEstimate = getTitanExactOutEstimate;
|
|
55687
|
+
exports.getTitanSwapIxsForFlashloan = getTitanSwapIxsForFlashloan;
|
|
55688
|
+
exports.getTotalAccountKeys = getTotalAccountKeys;
|
|
54358
55689
|
exports.getTotalAssetQuantity = getTotalAssetQuantity;
|
|
54359
55690
|
exports.getTotalLiabilityQuantity = getTotalLiabilityQuantity;
|
|
54360
55691
|
exports.getTxSize = getTxSize;
|
|
54361
55692
|
exports.getValidatorVoteAccountByBank = getValidatorVoteAccountByBank;
|
|
55693
|
+
exports.getWritableAccountKeys = getWritableAccountKeys;
|
|
54362
55694
|
exports.groupToDto = groupToDto;
|
|
54363
55695
|
exports.hasAccountFlag = hasAccountFlag;
|
|
54364
55696
|
exports.hasEmodeEntryFlag = hasEmodeEntryFlag;
|
|
@@ -54427,6 +55759,7 @@ exports.makeWithdrawIx = makeWithdrawIx3;
|
|
|
54427
55759
|
exports.makeWithdrawTx = makeWithdrawTx;
|
|
54428
55760
|
exports.makeWrapSolIxs = makeWrapSolIxs;
|
|
54429
55761
|
exports.mapBrokenFeedsToOraclePrices = mapBrokenFeedsToOraclePrices;
|
|
55762
|
+
exports.mapJupiterQuoteToSwapQuoteResult = mapJupiterQuoteToSwapQuoteResult;
|
|
54430
55763
|
exports.mapPythBanksToOraclePrices = mapPythBanksToOraclePrices;
|
|
54431
55764
|
exports.mapSwbBanksToOraclePrices = mapSwbBanksToOraclePrices;
|
|
54432
55765
|
exports.marginfiAccountToDto = marginfiAccountToDto;
|
|
@@ -54463,6 +55796,7 @@ exports.toBankDto = toBankDto;
|
|
|
54463
55796
|
exports.toBigNumber = toBigNumber;
|
|
54464
55797
|
exports.toEmodeSettingsDto = toEmodeSettingsDto;
|
|
54465
55798
|
exports.toInterestRateConfigDto = toInterestRateConfigDto;
|
|
55799
|
+
exports.toJupiterConfig = toJupiterConfig;
|
|
54466
55800
|
exports.toNumber = toNumber;
|
|
54467
55801
|
exports.uiToNative = uiToNative;
|
|
54468
55802
|
exports.uiToNativeBigNumber = uiToNativeBigNumber;
|