@0dotxyz/p0-ts-sdk 2.5.5-alpha.4 → 2.5.5-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2644 -2129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +285 -32
- package/dist/index.d.ts +285 -32
- package/dist/index.js +2633 -2128
- package/dist/index.js.map +1 -1
- package/dist/vendor.cjs +1 -0
- package/dist/vendor.cjs.map +1 -1
- package/dist/vendor.js +1 -0
- package/dist/vendor.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -103,6 +103,7 @@ var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCod
|
|
|
103
103
|
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_INVALID_SELECTION"] = "TRANSFER_POSITIONS_INVALID_SELECTION";
|
|
104
104
|
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSUPPORTED_BANK"] = "TRANSFER_POSITIONS_UNSUPPORTED_BANK";
|
|
105
105
|
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSPLITTABLE"] = "TRANSFER_POSITIONS_UNSPLITTABLE";
|
|
106
|
+
TransactionBuildingErrorCode2["BRIDGE_CONFLICT"] = "BRIDGE_CONFLICT";
|
|
106
107
|
return TransactionBuildingErrorCode2;
|
|
107
108
|
})(TransactionBuildingErrorCode || {});
|
|
108
109
|
var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
@@ -233,6 +234,19 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
233
234
|
{ reason, sizeBytes, accountCount }
|
|
234
235
|
);
|
|
235
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* A bridged (double-hop) swap could not route because every bridge-token candidate bank
|
|
239
|
+
* conflicts with an existing opposite-side position on the account (marginfi forbids holding an
|
|
240
|
+
* asset and a liability on the same bank).
|
|
241
|
+
*/
|
|
242
|
+
static bridgeConflict(conflictingBanks, bridgeTokenSide) {
|
|
243
|
+
const banksList = conflictingBanks.map((c) => c.symbol ?? c.mint).join(", ");
|
|
244
|
+
return new _TransactionBuildingError(
|
|
245
|
+
"BRIDGE_CONFLICT" /* BRIDGE_CONFLICT */,
|
|
246
|
+
`Every bridge-token candidate conflicts with an existing opposite-side position: ${banksList}`,
|
|
247
|
+
{ conflictingBanks, bridgeTokenSide }
|
|
248
|
+
);
|
|
249
|
+
}
|
|
236
250
|
/**
|
|
237
251
|
* Generic escape hatch for custom errors
|
|
238
252
|
*/
|
|
@@ -249,6 +263,9 @@ var DECOMPOSABLE_SWAP_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
249
263
|
function isDecomposableSwapError(e) {
|
|
250
264
|
return e instanceof TransactionBuildingError && DECOMPOSABLE_SWAP_ERROR_CODES.has(e.code);
|
|
251
265
|
}
|
|
266
|
+
function isBridgeConflictError(e) {
|
|
267
|
+
return e instanceof TransactionBuildingError && e.code === "BRIDGE_CONFLICT" /* BRIDGE_CONFLICT */;
|
|
268
|
+
}
|
|
252
269
|
var PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED = Buffer.from("liquidity_vault_auth");
|
|
253
270
|
var PDA_BANK_INSURANCE_VAULT_AUTH_SEED = Buffer.from("insurance_vault_auth");
|
|
254
271
|
var PDA_BANK_FEE_VAULT_AUTH_SEED = Buffer.from("fee_vault_auth");
|
|
@@ -408,6 +425,7 @@ var PRIORITY_TX_SIZE = 44;
|
|
|
408
425
|
var WSOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
|
|
409
426
|
var LST_MINT = new PublicKey("LSTxxxnJzKDFSLr4dUkPcmCf5VyryEqzPLz5j4bpxFp");
|
|
410
427
|
var USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
428
|
+
var USDT_MINT = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");
|
|
411
429
|
var USDC_DECIMALS = 6;
|
|
412
430
|
|
|
413
431
|
// src/utils/accounting.utils.ts
|
|
@@ -67209,1775 +67227,298 @@ function annotateFit(route, req) {
|
|
|
67209
67227
|
};
|
|
67210
67228
|
}
|
|
67211
67229
|
|
|
67212
|
-
// src/
|
|
67213
|
-
|
|
67214
|
-
|
|
67215
|
-
|
|
67216
|
-
|
|
67217
|
-
|
|
67218
|
-
|
|
67219
|
-
|
|
67220
|
-
|
|
67221
|
-
addressLookupTableAccounts,
|
|
67222
|
-
connection,
|
|
67223
|
-
oraclePrices,
|
|
67224
|
-
crossbarUrl,
|
|
67225
|
-
additionalIxs = []
|
|
67226
|
-
} = params;
|
|
67227
|
-
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
67228
|
-
const setupIxs = await makeSetupIx({
|
|
67229
|
-
connection,
|
|
67230
|
-
authority: marginfiAccount.authority,
|
|
67231
|
-
tokens: [
|
|
67232
|
-
{
|
|
67233
|
-
mint: borrowOpts.borrowBank.mint,
|
|
67234
|
-
tokenProgram: borrowOpts.tokenProgram
|
|
67235
|
-
},
|
|
67236
|
-
{
|
|
67237
|
-
mint: depositOpts.depositBank.mint,
|
|
67238
|
-
tokenProgram: depositOpts.tokenProgram
|
|
67239
|
-
}
|
|
67240
|
-
]
|
|
67241
|
-
});
|
|
67242
|
-
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
67243
|
-
params.marginfiAccount,
|
|
67244
|
-
params.bankMap,
|
|
67245
|
-
[depositOpts.depositBank.address],
|
|
67246
|
-
params.bankMetadataMap,
|
|
67247
|
-
[borrowOpts.borrowBank.address, depositOpts.depositBank.address]
|
|
67248
|
-
);
|
|
67249
|
-
const { flashloanTx, setupInstructions, swapQuote, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
|
|
67250
|
-
...params,
|
|
67251
|
-
blockhash
|
|
67252
|
-
});
|
|
67253
|
-
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
67254
|
-
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
67255
|
-
return false;
|
|
67256
|
-
}
|
|
67257
|
-
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
67258
|
-
const mintKey = ix.keys[3]?.pubkey;
|
|
67259
|
-
if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
67260
|
-
return false;
|
|
67261
|
-
}
|
|
67262
|
-
}
|
|
67263
|
-
return true;
|
|
67264
|
-
});
|
|
67265
|
-
setupIxs.push(...jupiterSetupInstructions);
|
|
67266
|
-
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
67267
|
-
marginfiAccount,
|
|
67268
|
-
bankMap,
|
|
67269
|
-
oraclePrices,
|
|
67270
|
-
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
67271
|
-
instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
|
|
67272
|
-
program,
|
|
67273
|
-
connection,
|
|
67274
|
-
crossbarUrl
|
|
67275
|
-
});
|
|
67276
|
-
let additionalTxs = [];
|
|
67277
|
-
if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
|
|
67278
|
-
setupIxs.push(
|
|
67279
|
-
...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
|
|
67280
|
-
);
|
|
67230
|
+
// src/models/balance.ts
|
|
67231
|
+
var Balance = class _Balance {
|
|
67232
|
+
constructor(active, bankPk, assetShares, liabilityShares, emissionsOutstanding, lastUpdate) {
|
|
67233
|
+
this.active = active;
|
|
67234
|
+
this.bankPk = bankPk;
|
|
67235
|
+
this.assetShares = assetShares;
|
|
67236
|
+
this.liabilityShares = liabilityShares;
|
|
67237
|
+
this.emissionsOutstanding = emissionsOutstanding;
|
|
67238
|
+
this.lastUpdate = lastUpdate;
|
|
67281
67239
|
}
|
|
67282
|
-
|
|
67283
|
-
const
|
|
67284
|
-
|
|
67285
|
-
|
|
67286
|
-
|
|
67287
|
-
|
|
67288
|
-
|
|
67289
|
-
|
|
67290
|
-
|
|
67291
|
-
(tx) => addTransactionMetadata(tx, {
|
|
67292
|
-
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
67293
|
-
addressLookupTables: addressLookupTableAccounts
|
|
67294
|
-
})
|
|
67295
|
-
)
|
|
67240
|
+
static from(balanceRaw) {
|
|
67241
|
+
const props = parseBalanceRaw(balanceRaw);
|
|
67242
|
+
return new _Balance(
|
|
67243
|
+
props.active,
|
|
67244
|
+
props.bankPk,
|
|
67245
|
+
props.assetShares,
|
|
67246
|
+
props.liabilityShares,
|
|
67247
|
+
props.emissionsOutstanding,
|
|
67248
|
+
props.lastUpdate
|
|
67296
67249
|
);
|
|
67297
67250
|
}
|
|
67298
|
-
|
|
67299
|
-
|
|
67300
|
-
|
|
67301
|
-
|
|
67302
|
-
|
|
67303
|
-
|
|
67304
|
-
|
|
67305
|
-
|
|
67306
|
-
addressLookupTables: feedLuts,
|
|
67307
|
-
type: "CRANK" /* CRANK */
|
|
67308
|
-
})
|
|
67251
|
+
static fromBalanceType(balance) {
|
|
67252
|
+
return new _Balance(
|
|
67253
|
+
balance.active,
|
|
67254
|
+
balance.bankPk,
|
|
67255
|
+
balance.assetShares,
|
|
67256
|
+
balance.liabilityShares,
|
|
67257
|
+
balance.emissionsOutstanding,
|
|
67258
|
+
balance.lastUpdate
|
|
67309
67259
|
);
|
|
67310
67260
|
}
|
|
67311
|
-
|
|
67312
|
-
|
|
67313
|
-
|
|
67314
|
-
|
|
67315
|
-
|
|
67316
|
-
|
|
67317
|
-
|
|
67318
|
-
|
|
67319
|
-
|
|
67320
|
-
|
|
67321
|
-
|
|
67322
|
-
|
|
67323
|
-
params,
|
|
67324
|
-
innerIxs: descriptor.innerIxs,
|
|
67325
|
-
luts: descriptor.luts,
|
|
67326
|
-
swapIxCount: 0,
|
|
67327
|
-
swapLutCount: 0,
|
|
67328
|
-
sizeConstraint: descriptor.sizeConstraint
|
|
67261
|
+
static createEmpty(bankPk) {
|
|
67262
|
+
const balance = createEmptyBalance(bankPk);
|
|
67263
|
+
return this.fromBalanceType(balance);
|
|
67264
|
+
}
|
|
67265
|
+
computeUsdValue(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
|
|
67266
|
+
return computeBalanceUsdValue({
|
|
67267
|
+
balance: this,
|
|
67268
|
+
bank,
|
|
67269
|
+
oraclePrice,
|
|
67270
|
+
marginRequirement,
|
|
67271
|
+
assetShareValueMultiplier,
|
|
67272
|
+
activeEmodeWeights
|
|
67329
67273
|
});
|
|
67330
|
-
return {
|
|
67331
|
-
flashloanTx: flashloanTx2,
|
|
67332
|
-
setupInstructions: [],
|
|
67333
|
-
swapQuote: void 0,
|
|
67334
|
-
borrowIxs,
|
|
67335
|
-
depositIxs
|
|
67336
|
-
};
|
|
67337
67274
|
}
|
|
67338
|
-
|
|
67339
|
-
|
|
67340
|
-
|
|
67341
|
-
|
|
67342
|
-
|
|
67343
|
-
|
|
67344
|
-
|
|
67345
|
-
|
|
67346
|
-
const flashloanTx = await finalizeLoopFlashloanTx({
|
|
67347
|
-
params,
|
|
67348
|
-
innerIxs: finalIxs,
|
|
67349
|
-
luts,
|
|
67350
|
-
swapIxCount: engineResult.swapInstructions.length,
|
|
67351
|
-
swapLutCount: engineResult.swapLuts.length,
|
|
67352
|
-
sizeConstraint: descriptor.sizeConstraint
|
|
67353
|
-
});
|
|
67354
|
-
return {
|
|
67355
|
-
flashloanTx,
|
|
67356
|
-
setupInstructions: engineResult.setupInstructions,
|
|
67357
|
-
swapQuote: engineResult.quoteResponse,
|
|
67358
|
-
borrowIxs,
|
|
67359
|
-
depositIxs
|
|
67360
|
-
};
|
|
67361
|
-
}
|
|
67362
|
-
async function buildLoopNonSwapIxs(params) {
|
|
67363
|
-
const {
|
|
67364
|
-
program,
|
|
67365
|
-
marginfiAccount,
|
|
67366
|
-
bankMap,
|
|
67367
|
-
borrowOpts,
|
|
67368
|
-
depositOpts,
|
|
67369
|
-
bankMetadataMap,
|
|
67370
|
-
addressLookupTableAccounts,
|
|
67371
|
-
overrideInferAccounts
|
|
67372
|
-
} = params;
|
|
67373
|
-
const cuRequestIxs = [
|
|
67374
|
-
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
67375
|
-
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
67376
|
-
];
|
|
67377
|
-
const swapNeeded = !depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint);
|
|
67378
|
-
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
67379
|
-
new PublicKey(depositOpts.depositBank.mint),
|
|
67380
|
-
marginfiAccount.authority,
|
|
67381
|
-
true,
|
|
67382
|
-
depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
67383
|
-
);
|
|
67384
|
-
const principalUi = depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0;
|
|
67385
|
-
let depositAmountUi;
|
|
67386
|
-
let sizeConstraint = 0;
|
|
67387
|
-
let maxSwapTotalAccounts = 0;
|
|
67388
|
-
if (!swapNeeded) {
|
|
67389
|
-
depositAmountUi = borrowOpts.borrowAmount + principalUi;
|
|
67390
|
-
} else {
|
|
67391
|
-
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
67392
|
-
program,
|
|
67393
|
-
marginfiAccount,
|
|
67394
|
-
bankMap,
|
|
67395
|
-
bankMetadataMap,
|
|
67396
|
-
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
67397
|
-
primaryIx: {
|
|
67398
|
-
type: "borrow",
|
|
67399
|
-
bank: borrowOpts.borrowBank,
|
|
67400
|
-
tokenProgram: borrowOpts.tokenProgram
|
|
67401
|
-
},
|
|
67402
|
-
secondaryIx: {
|
|
67403
|
-
type: "deposit",
|
|
67404
|
-
bank: depositOpts.depositBank,
|
|
67405
|
-
tokenProgram: depositOpts.tokenProgram
|
|
67406
|
-
},
|
|
67407
|
-
overrideInferAccounts
|
|
67275
|
+
getUsdValueWithPriceBias(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
|
|
67276
|
+
return getBalanceUsdValueWithPriceBias({
|
|
67277
|
+
balance: this,
|
|
67278
|
+
bank,
|
|
67279
|
+
oraclePrice,
|
|
67280
|
+
marginRequirement,
|
|
67281
|
+
assetShareValueMultiplier,
|
|
67282
|
+
activeEmodeWeights
|
|
67408
67283
|
});
|
|
67409
|
-
sizeConstraint = swapConstraints.sizeConstraint;
|
|
67410
|
-
maxSwapTotalAccounts = swapConstraints.maxSwapTotalAccounts;
|
|
67411
|
-
const estimateUi = borrowOpts.borrowAmount * borrowOpts.marketPrice / depositOpts.marketPrice;
|
|
67412
|
-
depositAmountUi = estimateUi + principalUi;
|
|
67413
67284
|
}
|
|
67414
|
-
|
|
67415
|
-
|
|
67416
|
-
bank: borrowOpts.borrowBank,
|
|
67417
|
-
bankMap,
|
|
67418
|
-
tokenProgram: borrowOpts.tokenProgram,
|
|
67419
|
-
amount: borrowOpts.borrowAmount,
|
|
67420
|
-
marginfiAccount,
|
|
67421
|
-
authority: marginfiAccount.authority,
|
|
67422
|
-
isSync: false,
|
|
67423
|
-
opts: {
|
|
67424
|
-
createAtas: false,
|
|
67425
|
-
wrapAndUnwrapSol: false,
|
|
67426
|
-
overrideInferAccounts
|
|
67427
|
-
}
|
|
67428
|
-
});
|
|
67429
|
-
const depositIxs = await buildDepositIxs(params, depositAmountUi);
|
|
67430
|
-
const innerIxsBeforeSwap = [...cuRequestIxs, ...borrowIxs.instructions];
|
|
67431
|
-
const swapSlotIndex = innerIxsBeforeSwap.length;
|
|
67432
|
-
const innerIxs = [...innerIxsBeforeSwap, ...depositIxs.instructions];
|
|
67433
|
-
const depositIxIndex = innerIxs.findIndex(isDepositIx);
|
|
67434
|
-
if (depositIxIndex < 0) {
|
|
67435
|
-
throw new Error(
|
|
67436
|
-
"buildLoopNonSwapIxs: could not locate deposit instruction for amount patching"
|
|
67437
|
-
);
|
|
67285
|
+
computeQuantity(bank) {
|
|
67286
|
+
return computeQuantity(this, bank);
|
|
67438
67287
|
}
|
|
67439
|
-
|
|
67440
|
-
|
|
67441
|
-
swapSlotIndex,
|
|
67442
|
-
depositIxIndex,
|
|
67443
|
-
inputMint: borrowOpts.borrowBank.mint.toBase58(),
|
|
67444
|
-
outputMint: depositOpts.depositBank.mint.toBase58(),
|
|
67445
|
-
inputDecimals: borrowOpts.borrowBank.mintDecimals,
|
|
67446
|
-
outputDecimals: depositOpts.depositBank.mintDecimals,
|
|
67447
|
-
inAmountNative: uiToNative(
|
|
67448
|
-
borrowOpts.borrowAmount,
|
|
67449
|
-
borrowOpts.borrowBank.mintDecimals
|
|
67450
|
-
).toNumber(),
|
|
67451
|
-
destinationTokenAccount,
|
|
67452
|
-
sizeConstraint,
|
|
67453
|
-
maxSwapTotalAccounts,
|
|
67454
|
-
luts: addressLookupTableAccounts ?? []
|
|
67455
|
-
};
|
|
67456
|
-
return { descriptor, swapNeeded, borrowIxs, depositIxs };
|
|
67457
|
-
}
|
|
67458
|
-
async function buildDepositIxs(params, amountUi) {
|
|
67459
|
-
const { program, marginfiAccount, depositOpts, bankMetadataMap, overrideInferAccounts } = params;
|
|
67460
|
-
switch (depositOpts.depositBank.config.assetTag) {
|
|
67461
|
-
case 3 /* KAMINO */: {
|
|
67462
|
-
const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
67463
|
-
if (!reserve) {
|
|
67464
|
-
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
67465
|
-
depositOpts.depositBank.address.toBase58(),
|
|
67466
|
-
depositOpts.depositBank.mint.toBase58(),
|
|
67467
|
-
depositOpts.depositBank.tokenSymbol
|
|
67468
|
-
);
|
|
67469
|
-
}
|
|
67470
|
-
return makeKaminoDepositIx3({
|
|
67471
|
-
program,
|
|
67472
|
-
bank: depositOpts.depositBank,
|
|
67473
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
67474
|
-
amount: amountUi,
|
|
67475
|
-
accountAddress: marginfiAccount.address,
|
|
67476
|
-
authority: marginfiAccount.authority,
|
|
67477
|
-
group: marginfiAccount.group,
|
|
67478
|
-
reserve,
|
|
67479
|
-
opts: {
|
|
67480
|
-
wrapAndUnwrapSol: false,
|
|
67481
|
-
overrideInferAccounts
|
|
67482
|
-
}
|
|
67483
|
-
});
|
|
67484
|
-
}
|
|
67485
|
-
case 4 /* DRIFT */: {
|
|
67486
|
-
const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
|
|
67487
|
-
if (!driftState) {
|
|
67488
|
-
throw TransactionBuildingError.driftStateNotFound(
|
|
67489
|
-
depositOpts.depositBank.address.toBase58(),
|
|
67490
|
-
depositOpts.depositBank.mint.toBase58(),
|
|
67491
|
-
depositOpts.depositBank.tokenSymbol
|
|
67492
|
-
);
|
|
67493
|
-
}
|
|
67494
|
-
return makeDriftDepositIx3({
|
|
67495
|
-
program,
|
|
67496
|
-
bank: depositOpts.depositBank,
|
|
67497
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
67498
|
-
amount: amountUi,
|
|
67499
|
-
accountAddress: marginfiAccount.address,
|
|
67500
|
-
authority: marginfiAccount.authority,
|
|
67501
|
-
group: marginfiAccount.group,
|
|
67502
|
-
driftMarketIndex: driftState.spotMarketState.marketIndex,
|
|
67503
|
-
driftOracle: driftState.spotMarketState.oracle,
|
|
67504
|
-
opts: {
|
|
67505
|
-
wrapAndUnwrapSol: false,
|
|
67506
|
-
overrideInferAccounts
|
|
67507
|
-
}
|
|
67508
|
-
});
|
|
67509
|
-
}
|
|
67510
|
-
case 6 /* JUPLEND */: {
|
|
67511
|
-
return makeJuplendDepositIx2({
|
|
67512
|
-
program,
|
|
67513
|
-
bank: depositOpts.depositBank,
|
|
67514
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
67515
|
-
amount: amountUi,
|
|
67516
|
-
accountAddress: marginfiAccount.address,
|
|
67517
|
-
authority: marginfiAccount.authority,
|
|
67518
|
-
group: marginfiAccount.group,
|
|
67519
|
-
opts: {
|
|
67520
|
-
wrapAndUnwrapSol: false,
|
|
67521
|
-
overrideInferAccounts
|
|
67522
|
-
}
|
|
67523
|
-
});
|
|
67524
|
-
}
|
|
67525
|
-
default: {
|
|
67526
|
-
return makeDepositIx3({
|
|
67527
|
-
program,
|
|
67528
|
-
bank: depositOpts.depositBank,
|
|
67529
|
-
tokenProgram: depositOpts.tokenProgram,
|
|
67530
|
-
amount: amountUi,
|
|
67531
|
-
accountAddress: marginfiAccount.address,
|
|
67532
|
-
authority: marginfiAccount.authority,
|
|
67533
|
-
group: marginfiAccount.group,
|
|
67534
|
-
opts: {
|
|
67535
|
-
wrapAndUnwrapSol: false,
|
|
67536
|
-
overrideInferAccounts
|
|
67537
|
-
}
|
|
67538
|
-
});
|
|
67539
|
-
}
|
|
67288
|
+
computeQuantityUi(bank, assetShareValueMultiplier) {
|
|
67289
|
+
return computeQuantityUi(this, bank, assetShareValueMultiplier);
|
|
67540
67290
|
}
|
|
67541
|
-
|
|
67542
|
-
|
|
67543
|
-
const { connection, swapOpts, marginfiAccount, swapEngineRunner } = params;
|
|
67544
|
-
if (swapOpts.swapIxs) {
|
|
67545
|
-
return {
|
|
67546
|
-
swapInstructions: swapOpts.swapIxs.instructions,
|
|
67547
|
-
setupInstructions: [],
|
|
67548
|
-
swapLuts: swapOpts.swapIxs.lookupTables,
|
|
67549
|
-
quoteResponse: {
|
|
67550
|
-
inAmount: String(descriptor.inAmountNative),
|
|
67551
|
-
outAmount: "0",
|
|
67552
|
-
otherAmountThreshold: "0",
|
|
67553
|
-
slippageBps: 0
|
|
67554
|
-
},
|
|
67555
|
-
outputAmountNative: new BN9(0)
|
|
67556
|
-
};
|
|
67291
|
+
computeTotalOutstandingEmissions(bank) {
|
|
67292
|
+
return computeTotalOutstandingEmissions(this, bank);
|
|
67557
67293
|
}
|
|
67558
|
-
|
|
67559
|
-
|
|
67560
|
-
inputMint: descriptor.inputMint,
|
|
67561
|
-
outputMint: descriptor.outputMint,
|
|
67562
|
-
amountNative: descriptor.inAmountNative,
|
|
67563
|
-
inputDecimals: descriptor.inputDecimals,
|
|
67564
|
-
outputDecimals: descriptor.outputDecimals,
|
|
67565
|
-
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
67566
|
-
taker: marginfiAccount.authority,
|
|
67567
|
-
destinationTokenAccount: descriptor.destinationTokenAccount,
|
|
67568
|
-
connection,
|
|
67569
|
-
footprint: {
|
|
67570
|
-
instructions: descriptor.innerIxs,
|
|
67571
|
-
luts: descriptor.luts,
|
|
67572
|
-
payer: marginfiAccount.authority,
|
|
67573
|
-
sizeConstraint: descriptor.sizeConstraint,
|
|
67574
|
-
maxSwapTotalAccounts: descriptor.maxSwapTotalAccounts
|
|
67575
|
-
},
|
|
67576
|
-
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
67577
|
-
});
|
|
67578
|
-
return {
|
|
67579
|
-
swapInstructions: engineResult.swapInstructions,
|
|
67580
|
-
setupInstructions: engineResult.setupInstructions,
|
|
67581
|
-
swapLuts: engineResult.swapLuts,
|
|
67582
|
-
quoteResponse: engineResult.quoteResponse,
|
|
67583
|
-
outputAmountNative: engineResult.outputAmountNative
|
|
67584
|
-
};
|
|
67585
|
-
}
|
|
67586
|
-
async function finalizeLoopFlashloanTx({
|
|
67587
|
-
params,
|
|
67588
|
-
innerIxs,
|
|
67589
|
-
luts,
|
|
67590
|
-
swapIxCount,
|
|
67591
|
-
swapLutCount,
|
|
67592
|
-
sizeConstraint
|
|
67593
|
-
}) {
|
|
67594
|
-
const { program, marginfiAccount, bankMap, swapOpts, blockhash } = params;
|
|
67595
|
-
if (swapIxCount > 0) {
|
|
67596
|
-
compileFlashloanPrecheck({
|
|
67597
|
-
allIxs: innerIxs,
|
|
67598
|
-
payer: marginfiAccount.authority,
|
|
67599
|
-
luts,
|
|
67600
|
-
sizeConstraint,
|
|
67601
|
-
swapIxCount,
|
|
67602
|
-
swapLutCount
|
|
67603
|
-
});
|
|
67294
|
+
computeClaimedEmissions(bank, currentTimestamp) {
|
|
67295
|
+
return computeClaimedEmissions(this, bank, currentTimestamp);
|
|
67604
67296
|
}
|
|
67605
|
-
|
|
67606
|
-
|
|
67607
|
-
|
|
67608
|
-
|
|
67609
|
-
|
|
67610
|
-
|
|
67611
|
-
|
|
67612
|
-
|
|
67613
|
-
|
|
67614
|
-
|
|
67615
|
-
|
|
67616
|
-
|
|
67617
|
-
|
|
67618
|
-
|
|
67619
|
-
|
|
67297
|
+
};
|
|
67298
|
+
|
|
67299
|
+
// src/models/health-cache.ts
|
|
67300
|
+
var HealthCache = class _HealthCache {
|
|
67301
|
+
constructor(assetValue, liabilityValue, assetValueMaint, liabilityValueMaint, assetValueEquity, liabilityValueEquity, timestamp, flags, prices, simulationStatus) {
|
|
67302
|
+
this.assetValue = assetValue;
|
|
67303
|
+
this.liabilityValue = liabilityValue;
|
|
67304
|
+
this.assetValueMaint = assetValueMaint;
|
|
67305
|
+
this.liabilityValueMaint = liabilityValueMaint;
|
|
67306
|
+
this.assetValueEquity = assetValueEquity;
|
|
67307
|
+
this.liabilityValueEquity = liabilityValueEquity;
|
|
67308
|
+
this.timestamp = timestamp;
|
|
67309
|
+
this.flags = flags;
|
|
67310
|
+
this.prices = prices;
|
|
67311
|
+
this.simulationStatus = simulationStatus;
|
|
67312
|
+
}
|
|
67313
|
+
static fromHealthCacheType(healthCacheType) {
|
|
67314
|
+
return new _HealthCache(
|
|
67315
|
+
healthCacheType.assetValue,
|
|
67316
|
+
healthCacheType.liabilityValue,
|
|
67317
|
+
healthCacheType.assetValueMaint,
|
|
67318
|
+
healthCacheType.liabilityValueMaint,
|
|
67319
|
+
healthCacheType.assetValueEquity,
|
|
67320
|
+
healthCacheType.liabilityValueEquity,
|
|
67321
|
+
healthCacheType.timestamp,
|
|
67322
|
+
healthCacheType.flags,
|
|
67323
|
+
healthCacheType.prices,
|
|
67324
|
+
healthCacheType.simulationStatus
|
|
67620
67325
|
);
|
|
67621
67326
|
}
|
|
67622
|
-
|
|
67623
|
-
|
|
67624
|
-
async function makeSwapCollateralTx(params) {
|
|
67625
|
-
const {
|
|
67626
|
-
program,
|
|
67627
|
-
marginfiAccount,
|
|
67628
|
-
connection,
|
|
67629
|
-
bankMap,
|
|
67630
|
-
oraclePrices,
|
|
67631
|
-
withdrawOpts,
|
|
67632
|
-
depositOpts,
|
|
67633
|
-
bankMetadataMap,
|
|
67634
|
-
assetShareValueMultiplierByBank,
|
|
67635
|
-
addressLookupTableAccounts,
|
|
67636
|
-
crossbarUrl,
|
|
67637
|
-
additionalIxs = []
|
|
67638
|
-
} = params;
|
|
67639
|
-
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
67640
|
-
const setupIxs = await makeSetupIx({
|
|
67641
|
-
connection,
|
|
67642
|
-
authority: marginfiAccount.authority,
|
|
67643
|
-
tokens: [
|
|
67644
|
-
{ mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
|
|
67645
|
-
{ mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
|
|
67646
|
-
]
|
|
67647
|
-
});
|
|
67648
|
-
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
67649
|
-
marginfiAccount,
|
|
67650
|
-
bankMap,
|
|
67651
|
-
[withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
|
|
67652
|
-
bankMetadataMap
|
|
67653
|
-
);
|
|
67654
|
-
const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
|
|
67655
|
-
...params,
|
|
67656
|
-
blockhash
|
|
67657
|
-
});
|
|
67658
|
-
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
67659
|
-
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
67660
|
-
return false;
|
|
67661
|
-
}
|
|
67662
|
-
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
67663
|
-
const mintKey = ix.keys[3]?.pubkey;
|
|
67664
|
-
if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
|
|
67665
|
-
return false;
|
|
67666
|
-
}
|
|
67667
|
-
}
|
|
67668
|
-
return true;
|
|
67669
|
-
});
|
|
67670
|
-
setupIxs.push(...jupiterSetupInstructions);
|
|
67671
|
-
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
67672
|
-
marginfiAccount,
|
|
67673
|
-
bankMap,
|
|
67674
|
-
oraclePrices,
|
|
67675
|
-
assetShareValueMultiplierByBank,
|
|
67676
|
-
instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
67677
|
-
program,
|
|
67678
|
-
connection,
|
|
67679
|
-
crossbarUrl
|
|
67680
|
-
});
|
|
67681
|
-
let additionalTxs = [];
|
|
67682
|
-
if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
|
|
67683
|
-
const ixs = [...setupIxs, ...refreshIntegrationIxs.instructions];
|
|
67684
|
-
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
67685
|
-
blockhash,
|
|
67686
|
-
payerKey: marginfiAccount.authority,
|
|
67687
|
-
luts: addressLookupTableAccounts ?? []
|
|
67688
|
-
});
|
|
67689
|
-
additionalTxs.push(
|
|
67690
|
-
...txs.map(
|
|
67691
|
-
(tx) => addTransactionMetadata(tx, {
|
|
67692
|
-
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
67693
|
-
addressLookupTables: addressLookupTableAccounts
|
|
67694
|
-
})
|
|
67695
|
-
)
|
|
67696
|
-
);
|
|
67327
|
+
static from(healthCacheRaw) {
|
|
67328
|
+
return this.fromHealthCacheType(parseHealthCacheRaw(healthCacheRaw));
|
|
67697
67329
|
}
|
|
67698
|
-
|
|
67699
|
-
|
|
67700
|
-
|
|
67701
|
-
|
|
67702
|
-
|
|
67703
|
-
|
|
67704
|
-
|
|
67705
|
-
|
|
67706
|
-
|
|
67707
|
-
|
|
67708
|
-
|
|
67709
|
-
|
|
67330
|
+
};
|
|
67331
|
+
|
|
67332
|
+
// src/models/account.ts
|
|
67333
|
+
var MarginfiAccount = class _MarginfiAccount {
|
|
67334
|
+
constructor(address, group, authority, balances, accountFlags, emissionsDestinationAccount, healthCache) {
|
|
67335
|
+
this.address = address;
|
|
67336
|
+
this.group = group;
|
|
67337
|
+
this.authority = authority;
|
|
67338
|
+
this.balances = balances;
|
|
67339
|
+
this.accountFlags = accountFlags;
|
|
67340
|
+
this.emissionsDestinationAccount = emissionsDestinationAccount;
|
|
67341
|
+
this.healthCache = healthCache;
|
|
67710
67342
|
}
|
|
67711
|
-
|
|
67712
|
-
|
|
67713
|
-
|
|
67714
|
-
|
|
67715
|
-
|
|
67716
|
-
|
|
67717
|
-
|
|
67718
|
-
|
|
67719
|
-
program
|
|
67720
|
-
|
|
67721
|
-
|
|
67722
|
-
withdrawOpts,
|
|
67723
|
-
depositOpts,
|
|
67724
|
-
swapOpts,
|
|
67725
|
-
bankMetadataMap,
|
|
67726
|
-
assetShareValueMultiplierByBank,
|
|
67727
|
-
addressLookupTableAccounts,
|
|
67728
|
-
connection,
|
|
67729
|
-
overrideInferAccounts,
|
|
67730
|
-
blockhash,
|
|
67731
|
-
swapEngineRunner
|
|
67732
|
-
}) {
|
|
67733
|
-
const {
|
|
67734
|
-
withdrawBank,
|
|
67735
|
-
tokenProgram: withdrawTokenProgram,
|
|
67736
|
-
totalPositionAmount,
|
|
67737
|
-
withdrawAmount
|
|
67738
|
-
} = withdrawOpts;
|
|
67739
|
-
const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
|
|
67740
|
-
if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
|
|
67741
|
-
throw new Error("withdrawAmount must be greater than 0");
|
|
67343
|
+
/**
|
|
67344
|
+
* Fetches a marginfi account from on-chain data.
|
|
67345
|
+
*
|
|
67346
|
+
* @param address - The public key of the marginfi account
|
|
67347
|
+
* @param program - The Marginfi program instance
|
|
67348
|
+
*
|
|
67349
|
+
* @returns Promise resolving to a MarginfiAccount instance
|
|
67350
|
+
*/
|
|
67351
|
+
static async fetch(address, program) {
|
|
67352
|
+
const data = await program.account.marginfiAccount.fetch(address);
|
|
67353
|
+
return _MarginfiAccount.fromAccountParsed(address, data);
|
|
67742
67354
|
}
|
|
67743
|
-
|
|
67744
|
-
|
|
67745
|
-
{ amount: totalPositionAmount, isLending: true },
|
|
67746
|
-
actualWithdrawAmount,
|
|
67747
|
-
withdrawBank.mintDecimals
|
|
67748
|
-
);
|
|
67749
|
-
const cuRequestIxs = [
|
|
67750
|
-
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
67751
|
-
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
67752
|
-
];
|
|
67753
|
-
let amountToDeposit;
|
|
67754
|
-
let swapInstructions = [];
|
|
67755
|
-
let setupInstructions = [];
|
|
67756
|
-
let swapLookupTables = [];
|
|
67757
|
-
let swapQuote;
|
|
67758
|
-
let sizeConstraintUsed = 0;
|
|
67759
|
-
let withdrawIxs;
|
|
67760
|
-
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
67761
|
-
case 3 /* KAMINO */: {
|
|
67762
|
-
const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
67763
|
-
if (!reserve) {
|
|
67764
|
-
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
67765
|
-
withdrawOpts.withdrawBank.address.toBase58(),
|
|
67766
|
-
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
67767
|
-
withdrawOpts.withdrawBank.tokenSymbol
|
|
67768
|
-
);
|
|
67769
|
-
}
|
|
67770
|
-
const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
|
|
67771
|
-
const adjustedAmount = new BigNumber(actualWithdrawAmount).div(multiplier).times(1.0001).toNumber();
|
|
67772
|
-
withdrawIxs = await makeKaminoWithdrawIx3({
|
|
67773
|
-
program,
|
|
67774
|
-
bank: withdrawBank,
|
|
67775
|
-
bankMap,
|
|
67776
|
-
tokenProgram: withdrawTokenProgram,
|
|
67777
|
-
cTokenAmount: adjustedAmount,
|
|
67778
|
-
marginfiAccount,
|
|
67779
|
-
authority: marginfiAccount.authority,
|
|
67780
|
-
reserve,
|
|
67781
|
-
withdrawAll: isFullWithdraw,
|
|
67782
|
-
isSync: false,
|
|
67783
|
-
opts: {
|
|
67784
|
-
createAtas: false,
|
|
67785
|
-
wrapAndUnwrapSol: false,
|
|
67786
|
-
overrideInferAccounts
|
|
67787
|
-
}
|
|
67788
|
-
});
|
|
67789
|
-
break;
|
|
67790
|
-
}
|
|
67791
|
-
case 4 /* DRIFT */: {
|
|
67792
|
-
const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
|
|
67793
|
-
if (!driftState) {
|
|
67794
|
-
throw TransactionBuildingError.driftStateNotFound(
|
|
67795
|
-
withdrawOpts.withdrawBank.address.toBase58(),
|
|
67796
|
-
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
67797
|
-
withdrawOpts.withdrawBank.tokenSymbol
|
|
67798
|
-
);
|
|
67799
|
-
}
|
|
67800
|
-
withdrawIxs = await makeDriftWithdrawIx3({
|
|
67801
|
-
program,
|
|
67802
|
-
bank: withdrawOpts.withdrawBank,
|
|
67803
|
-
bankMap,
|
|
67804
|
-
tokenProgram: withdrawOpts.tokenProgram,
|
|
67805
|
-
amount: actualWithdrawAmount,
|
|
67806
|
-
marginfiAccount,
|
|
67807
|
-
authority: marginfiAccount.authority,
|
|
67808
|
-
driftSpotMarket: driftState.spotMarketState,
|
|
67809
|
-
userRewards: driftState.userRewards,
|
|
67810
|
-
withdrawAll: isFullWithdraw,
|
|
67811
|
-
isSync: false,
|
|
67812
|
-
opts: {
|
|
67813
|
-
createAtas: false,
|
|
67814
|
-
wrapAndUnwrapSol: false,
|
|
67815
|
-
overrideInferAccounts
|
|
67816
|
-
}
|
|
67817
|
-
});
|
|
67818
|
-
break;
|
|
67819
|
-
}
|
|
67820
|
-
case 6 /* JUPLEND */: {
|
|
67821
|
-
const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
|
|
67822
|
-
if (!jupLendState) {
|
|
67823
|
-
throw TransactionBuildingError.jupLendStateNotFound(
|
|
67824
|
-
withdrawOpts.withdrawBank.address.toBase58(),
|
|
67825
|
-
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
67826
|
-
withdrawOpts.withdrawBank.tokenSymbol
|
|
67827
|
-
);
|
|
67828
|
-
}
|
|
67829
|
-
withdrawIxs = await makeJuplendWithdrawIx2({
|
|
67830
|
-
program,
|
|
67831
|
-
bank: withdrawBank,
|
|
67832
|
-
bankMap,
|
|
67833
|
-
tokenProgram: withdrawTokenProgram,
|
|
67834
|
-
amount: actualWithdrawAmount,
|
|
67835
|
-
marginfiAccount,
|
|
67836
|
-
authority: marginfiAccount.authority,
|
|
67837
|
-
jupLendingState: jupLendState.jupLendingState,
|
|
67838
|
-
withdrawAll: isFullWithdraw,
|
|
67839
|
-
opts: {
|
|
67840
|
-
createAtas: false,
|
|
67841
|
-
wrapAndUnwrapSol: false,
|
|
67842
|
-
overrideInferAccounts
|
|
67843
|
-
}
|
|
67844
|
-
});
|
|
67845
|
-
break;
|
|
67846
|
-
}
|
|
67847
|
-
default: {
|
|
67848
|
-
withdrawIxs = await makeWithdrawIx3({
|
|
67849
|
-
program,
|
|
67850
|
-
bank: withdrawBank,
|
|
67851
|
-
bankMap,
|
|
67852
|
-
tokenProgram: withdrawTokenProgram,
|
|
67853
|
-
amount: actualWithdrawAmount,
|
|
67854
|
-
marginfiAccount,
|
|
67855
|
-
authority: marginfiAccount.authority,
|
|
67856
|
-
withdrawAll: isFullWithdraw,
|
|
67857
|
-
isSync: false,
|
|
67858
|
-
opts: {
|
|
67859
|
-
createAtas: false,
|
|
67860
|
-
wrapAndUnwrapSol: false,
|
|
67861
|
-
overrideInferAccounts
|
|
67862
|
-
}
|
|
67863
|
-
});
|
|
67864
|
-
break;
|
|
67865
|
-
}
|
|
67355
|
+
static decodeAccountRaw(encoded, idl) {
|
|
67356
|
+
return decodeAccountRaw(encoded, idl);
|
|
67866
67357
|
}
|
|
67867
|
-
|
|
67868
|
-
|
|
67869
|
-
|
|
67870
|
-
|
|
67871
|
-
|
|
67872
|
-
|
|
67873
|
-
|
|
67874
|
-
|
|
67875
|
-
|
|
67876
|
-
|
|
67877
|
-
depositBank.tokenSymbol
|
|
67878
|
-
);
|
|
67879
|
-
}
|
|
67880
|
-
depositIxs = await makeKaminoDepositIx3({
|
|
67881
|
-
program,
|
|
67882
|
-
bank: depositBank,
|
|
67883
|
-
tokenProgram: depositTokenProgram,
|
|
67884
|
-
amount: amountToDeposit,
|
|
67885
|
-
accountAddress: marginfiAccount.address,
|
|
67886
|
-
authority: marginfiAccount.authority,
|
|
67887
|
-
group: marginfiAccount.group,
|
|
67888
|
-
reserve,
|
|
67889
|
-
opts: {
|
|
67890
|
-
wrapAndUnwrapSol: false,
|
|
67891
|
-
overrideInferAccounts
|
|
67892
|
-
}
|
|
67893
|
-
});
|
|
67894
|
-
break;
|
|
67895
|
-
}
|
|
67896
|
-
case 4 /* DRIFT */: {
|
|
67897
|
-
const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
|
|
67898
|
-
if (!driftState) {
|
|
67899
|
-
throw TransactionBuildingError.driftStateNotFound(
|
|
67900
|
-
depositBank.address.toBase58(),
|
|
67901
|
-
depositBank.mint.toBase58(),
|
|
67902
|
-
depositBank.tokenSymbol
|
|
67903
|
-
);
|
|
67904
|
-
}
|
|
67905
|
-
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
67906
|
-
const driftOracle = driftState.spotMarketState.oracle;
|
|
67907
|
-
depositIxs = await makeDriftDepositIx3({
|
|
67908
|
-
program,
|
|
67909
|
-
bank: depositBank,
|
|
67910
|
-
tokenProgram: depositTokenProgram,
|
|
67911
|
-
amount: amountToDeposit,
|
|
67912
|
-
accountAddress: marginfiAccount.address,
|
|
67913
|
-
authority: marginfiAccount.authority,
|
|
67914
|
-
group: marginfiAccount.group,
|
|
67915
|
-
driftMarketIndex,
|
|
67916
|
-
driftOracle,
|
|
67917
|
-
opts: {
|
|
67918
|
-
wrapAndUnwrapSol: false,
|
|
67919
|
-
overrideInferAccounts
|
|
67920
|
-
}
|
|
67921
|
-
});
|
|
67922
|
-
break;
|
|
67923
|
-
}
|
|
67924
|
-
case 6 /* JUPLEND */: {
|
|
67925
|
-
depositIxs = await makeJuplendDepositIx2({
|
|
67926
|
-
program,
|
|
67927
|
-
bank: depositBank,
|
|
67928
|
-
tokenProgram: depositTokenProgram,
|
|
67929
|
-
amount: amountToDeposit,
|
|
67930
|
-
accountAddress: marginfiAccount.address,
|
|
67931
|
-
authority: marginfiAccount.authority,
|
|
67932
|
-
group: marginfiAccount.group,
|
|
67933
|
-
opts: {
|
|
67934
|
-
wrapAndUnwrapSol: false,
|
|
67935
|
-
overrideInferAccounts
|
|
67936
|
-
}
|
|
67937
|
-
});
|
|
67938
|
-
break;
|
|
67939
|
-
}
|
|
67940
|
-
default: {
|
|
67941
|
-
depositIxs = await makeDepositIx3({
|
|
67942
|
-
program,
|
|
67943
|
-
bank: depositBank,
|
|
67944
|
-
tokenProgram: depositTokenProgram,
|
|
67945
|
-
amount: amountToDeposit,
|
|
67946
|
-
accountAddress: marginfiAccount.address,
|
|
67947
|
-
authority: marginfiAccount.authority,
|
|
67948
|
-
group: marginfiAccount.group,
|
|
67949
|
-
opts: {
|
|
67950
|
-
wrapAndUnwrapSol: false,
|
|
67951
|
-
overrideInferAccounts
|
|
67952
|
-
}
|
|
67953
|
-
});
|
|
67954
|
-
break;
|
|
67955
|
-
}
|
|
67358
|
+
static fromAccountType(account) {
|
|
67359
|
+
return new _MarginfiAccount(
|
|
67360
|
+
account.address,
|
|
67361
|
+
account.group,
|
|
67362
|
+
account.authority,
|
|
67363
|
+
account.balances.map((b) => Balance.fromBalanceType(b)),
|
|
67364
|
+
account.accountFlags,
|
|
67365
|
+
account.emissionsDestinationAccount,
|
|
67366
|
+
account.healthCache
|
|
67367
|
+
);
|
|
67956
67368
|
}
|
|
67957
|
-
|
|
67958
|
-
|
|
67959
|
-
|
|
67960
|
-
|
|
67961
|
-
|
|
67962
|
-
|
|
67369
|
+
/**
|
|
67370
|
+
* Creates a MarginfiAccount instance from parsed account data.
|
|
67371
|
+
*
|
|
67372
|
+
* @param marginfiAccountPk - The public key of the marginfi account
|
|
67373
|
+
* @param accountData - The raw account data from the program
|
|
67374
|
+
*
|
|
67375
|
+
* @returns A new MarginfiAccount instance
|
|
67376
|
+
*/
|
|
67377
|
+
static fromAccountParsed(marginfiAccountPk, accountData) {
|
|
67378
|
+
const props = parseMarginfiAccountRaw(marginfiAccountPk, accountData);
|
|
67379
|
+
return new _MarginfiAccount(
|
|
67380
|
+
props.address,
|
|
67381
|
+
props.group,
|
|
67382
|
+
props.authority,
|
|
67383
|
+
props.balances.map((b) => Balance.fromBalanceType(b)),
|
|
67384
|
+
props.accountFlags,
|
|
67385
|
+
props.emissionsDestinationAccount,
|
|
67386
|
+
HealthCache.fromHealthCacheType(props.healthCache)
|
|
67963
67387
|
);
|
|
67964
|
-
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
67965
|
-
program,
|
|
67966
|
-
marginfiAccount,
|
|
67967
|
-
bankMap,
|
|
67968
|
-
bankMetadataMap,
|
|
67969
|
-
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
67970
|
-
primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
|
|
67971
|
-
secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
|
|
67972
|
-
overrideInferAccounts
|
|
67973
|
-
});
|
|
67974
|
-
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
67975
|
-
const runEngine = swapEngineRunner ?? runSwapEngine;
|
|
67976
|
-
const engineResult = await runEngine({
|
|
67977
|
-
inputMint: withdrawBank.mint.toBase58(),
|
|
67978
|
-
outputMint: depositBank.mint.toBase58(),
|
|
67979
|
-
amountNative: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
|
|
67980
|
-
inputDecimals: withdrawBank.mintDecimals,
|
|
67981
|
-
outputDecimals: depositBank.mintDecimals,
|
|
67982
|
-
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
67983
|
-
taker: marginfiAccount.authority,
|
|
67984
|
-
destinationTokenAccount,
|
|
67985
|
-
connection,
|
|
67986
|
-
footprint: {
|
|
67987
|
-
instructions: [...cuRequestIxs, ...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
67988
|
-
luts: addressLookupTableAccounts ?? [],
|
|
67989
|
-
payer: marginfiAccount.authority,
|
|
67990
|
-
sizeConstraint: swapConstraints.sizeConstraint,
|
|
67991
|
-
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
67992
|
-
},
|
|
67993
|
-
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
67994
|
-
});
|
|
67995
|
-
const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
|
|
67996
|
-
if (!depositIxToPatch) {
|
|
67997
|
-
throw new Error("swap-collateral: could not locate deposit instruction for amount patching");
|
|
67998
|
-
}
|
|
67999
|
-
patchDepositAmount(depositIxToPatch, engineResult.outputAmountNative);
|
|
68000
|
-
swapInstructions = engineResult.swapInstructions;
|
|
68001
|
-
setupInstructions = engineResult.setupInstructions;
|
|
68002
|
-
swapLookupTables = engineResult.swapLuts;
|
|
68003
|
-
swapQuote = engineResult.quoteResponse;
|
|
68004
67388
|
}
|
|
68005
|
-
|
|
68006
|
-
|
|
68007
|
-
|
|
68008
|
-
|
|
68009
|
-
|
|
68010
|
-
|
|
68011
|
-
|
|
68012
|
-
|
|
68013
|
-
|
|
68014
|
-
|
|
68015
|
-
|
|
68016
|
-
|
|
68017
|
-
|
|
68018
|
-
swapIxCount: swapInstructions.length,
|
|
68019
|
-
swapLutCount: swapLookupTables.length
|
|
67389
|
+
/**
|
|
67390
|
+
* Simulates and updates the health cache for this account.
|
|
67391
|
+
*
|
|
67392
|
+
* Fetches current oracle prices and computes fresh health values. Returns a new
|
|
67393
|
+
* account instance with updated health cache (does not mutate this instance).
|
|
67394
|
+
*
|
|
67395
|
+
* @param params - Configuration for health cache simulation (excluding marginfiAccount)
|
|
67396
|
+
* @returns Object containing the updated account and any errors
|
|
67397
|
+
*/
|
|
67398
|
+
async simulateHealthCache(params) {
|
|
67399
|
+
const accountWithHealthCache = await simulateAccountHealthCacheWithFallback({
|
|
67400
|
+
marginfiAccount: this,
|
|
67401
|
+
...params
|
|
68020
67402
|
});
|
|
67403
|
+
return {
|
|
67404
|
+
account: _MarginfiAccount.fromAccountType(accountWithHealthCache.marginfiAccount),
|
|
67405
|
+
error: accountWithHealthCache.error
|
|
67406
|
+
};
|
|
68021
67407
|
}
|
|
68022
|
-
|
|
68023
|
-
|
|
68024
|
-
|
|
68025
|
-
bankMap,
|
|
68026
|
-
addressLookupTableAccounts: luts,
|
|
68027
|
-
blockhash,
|
|
68028
|
-
ixs: allNonFlIxs,
|
|
68029
|
-
isSync: false
|
|
68030
|
-
});
|
|
68031
|
-
const txSize = getTxSize(flashloanTx);
|
|
68032
|
-
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
68033
|
-
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
68034
|
-
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
68035
|
-
txSize,
|
|
68036
|
-
totalKeys,
|
|
68037
|
-
swapOpts.swapConfig?.provider
|
|
68038
|
-
);
|
|
67408
|
+
static fromAccountDataRaw(marginfiAccountPk, rawData, idl) {
|
|
67409
|
+
const marginfiAccountData = _MarginfiAccount.decodeAccountRaw(rawData, idl);
|
|
67410
|
+
return _MarginfiAccount.fromAccountParsed(marginfiAccountPk, marginfiAccountData);
|
|
68039
67411
|
}
|
|
68040
|
-
|
|
68041
|
-
|
|
68042
|
-
|
|
68043
|
-
|
|
68044
|
-
|
|
68045
|
-
|
|
68046
|
-
|
|
68047
|
-
|
|
68048
|
-
|
|
68049
|
-
|
|
68050
|
-
program,
|
|
68051
|
-
marginfiAccount,
|
|
68052
|
-
connection,
|
|
68053
|
-
bankMap,
|
|
68054
|
-
oraclePrices,
|
|
68055
|
-
repayOpts,
|
|
68056
|
-
borrowOpts,
|
|
68057
|
-
bankMetadataMap,
|
|
68058
|
-
assetShareValueMultiplierByBank,
|
|
68059
|
-
addressLookupTableAccounts,
|
|
68060
|
-
crossbarUrl,
|
|
68061
|
-
additionalIxs = []
|
|
68062
|
-
} = params;
|
|
68063
|
-
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
68064
|
-
const setupIxs = await makeSetupIx({
|
|
68065
|
-
connection,
|
|
68066
|
-
authority: marginfiAccount.authority,
|
|
68067
|
-
tokens: [
|
|
68068
|
-
{ mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
|
|
68069
|
-
{ mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
|
|
68070
|
-
]
|
|
68071
|
-
});
|
|
68072
|
-
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
68073
|
-
marginfiAccount,
|
|
68074
|
-
bankMap,
|
|
68075
|
-
[],
|
|
68076
|
-
bankMetadataMap,
|
|
68077
|
-
[repayOpts.repayBank.address, borrowOpts.borrowBank.address]
|
|
68078
|
-
);
|
|
68079
|
-
const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
|
|
68080
|
-
...params,
|
|
68081
|
-
blockhash
|
|
68082
|
-
});
|
|
68083
|
-
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
68084
|
-
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
68085
|
-
return false;
|
|
68086
|
-
}
|
|
68087
|
-
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
68088
|
-
const mintKey = ix.keys[3]?.pubkey;
|
|
68089
|
-
if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
68090
|
-
return false;
|
|
68091
|
-
}
|
|
68092
|
-
}
|
|
68093
|
-
return true;
|
|
68094
|
-
});
|
|
68095
|
-
setupIxs.push(...jupiterSetupInstructions);
|
|
68096
|
-
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
68097
|
-
marginfiAccount,
|
|
68098
|
-
bankMap,
|
|
68099
|
-
oraclePrices,
|
|
68100
|
-
assetShareValueMultiplierByBank,
|
|
68101
|
-
instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
|
|
68102
|
-
program,
|
|
68103
|
-
connection,
|
|
68104
|
-
crossbarUrl
|
|
68105
|
-
});
|
|
68106
|
-
let additionalTxs = [];
|
|
68107
|
-
if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
|
|
68108
|
-
const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
|
|
68109
|
-
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
68110
|
-
blockhash,
|
|
68111
|
-
payerKey: marginfiAccount.authority,
|
|
68112
|
-
luts: addressLookupTableAccounts ?? []
|
|
68113
|
-
});
|
|
68114
|
-
additionalTxs.push(
|
|
68115
|
-
...txs.map(
|
|
68116
|
-
(tx) => addTransactionMetadata(tx, {
|
|
68117
|
-
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
68118
|
-
addressLookupTables: addressLookupTableAccounts
|
|
68119
|
-
})
|
|
68120
|
-
)
|
|
68121
|
-
);
|
|
67412
|
+
// ----------------------------------------------------------------------------
|
|
67413
|
+
// Attributes
|
|
67414
|
+
// ----------------------------------------------------------------------------
|
|
67415
|
+
/**
|
|
67416
|
+
* Gets all balances that are currently active (non-zero).
|
|
67417
|
+
*
|
|
67418
|
+
* @returns Array of active Balance instances
|
|
67419
|
+
*/
|
|
67420
|
+
get activeBalances() {
|
|
67421
|
+
return this.balances.filter((b) => b.active);
|
|
68122
67422
|
}
|
|
68123
|
-
|
|
68124
|
-
|
|
68125
|
-
|
|
68126
|
-
|
|
68127
|
-
|
|
68128
|
-
|
|
68129
|
-
|
|
68130
|
-
|
|
68131
|
-
|
|
68132
|
-
type: "CRANK" /* CRANK */
|
|
68133
|
-
})
|
|
68134
|
-
);
|
|
67423
|
+
/**
|
|
67424
|
+
* Gets the balance for a specific bank.
|
|
67425
|
+
*
|
|
67426
|
+
* @param bankPk - The public key of the bank
|
|
67427
|
+
*
|
|
67428
|
+
* @returns The Balance instance for the bank (may be empty)
|
|
67429
|
+
*/
|
|
67430
|
+
getBalance(bankPk) {
|
|
67431
|
+
return Balance.fromBalanceType(getBalance(bankPk, this.balances));
|
|
68135
67432
|
}
|
|
68136
|
-
|
|
68137
|
-
|
|
68138
|
-
|
|
68139
|
-
|
|
68140
|
-
|
|
68141
|
-
|
|
68142
|
-
|
|
68143
|
-
async function buildSwapDebtFlashloanTx({
|
|
68144
|
-
program,
|
|
68145
|
-
marginfiAccount,
|
|
68146
|
-
bankMap,
|
|
68147
|
-
repayOpts,
|
|
68148
|
-
borrowOpts,
|
|
68149
|
-
swapOpts,
|
|
68150
|
-
bankMetadataMap,
|
|
68151
|
-
addressLookupTableAccounts,
|
|
68152
|
-
connection,
|
|
68153
|
-
overrideInferAccounts,
|
|
68154
|
-
blockhash,
|
|
68155
|
-
swapEngineRunner
|
|
68156
|
-
}) {
|
|
68157
|
-
const {
|
|
68158
|
-
repayBank,
|
|
68159
|
-
tokenProgram: repayTokenProgram,
|
|
68160
|
-
totalPositionAmount,
|
|
68161
|
-
repayAmount
|
|
68162
|
-
} = repayOpts;
|
|
68163
|
-
const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
|
|
68164
|
-
if (repayAmount !== void 0 && repayAmount <= 0) {
|
|
68165
|
-
throw new Error("repayAmount must be greater than 0");
|
|
67433
|
+
/**
|
|
67434
|
+
* Checks if the account is disabled.
|
|
67435
|
+
*
|
|
67436
|
+
* @returns True if the account is disabled, false otherwise
|
|
67437
|
+
*/
|
|
67438
|
+
get isDisabled() {
|
|
67439
|
+
return this.accountFlags.includes(1 /* ACCOUNT_DISABLED */);
|
|
68166
67440
|
}
|
|
68167
|
-
|
|
68168
|
-
|
|
68169
|
-
|
|
68170
|
-
|
|
68171
|
-
|
|
68172
|
-
|
|
68173
|
-
|
|
68174
|
-
marginfiAccount.authority,
|
|
68175
|
-
true,
|
|
68176
|
-
repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
68177
|
-
);
|
|
68178
|
-
const estimatedBorrowAmount = computeBorrowEstimateForRepay({
|
|
68179
|
-
repayTargetUi: actualRepayAmount,
|
|
68180
|
-
repayMarketPrice: repayOpts.marketPrice,
|
|
68181
|
-
borrowMarketPrice: borrowOpts.marketPrice,
|
|
68182
|
-
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
68183
|
-
isRepayAll: actualRepayAmount >= totalPositionAmount
|
|
68184
|
-
});
|
|
68185
|
-
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
68186
|
-
program,
|
|
68187
|
-
marginfiAccount,
|
|
68188
|
-
bankMap,
|
|
68189
|
-
bankMetadataMap,
|
|
68190
|
-
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
68191
|
-
primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
|
|
68192
|
-
secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
|
|
68193
|
-
overrideInferAccounts
|
|
68194
|
-
});
|
|
68195
|
-
const footprintBorrowIxs = await makeBorrowIx3({
|
|
68196
|
-
program,
|
|
68197
|
-
bank: borrowBank,
|
|
68198
|
-
bankMap,
|
|
68199
|
-
tokenProgram: borrowTokenProgram,
|
|
68200
|
-
amount: estimatedBorrowAmount,
|
|
68201
|
-
marginfiAccount,
|
|
68202
|
-
authority: marginfiAccount.authority,
|
|
68203
|
-
isSync: true,
|
|
68204
|
-
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68205
|
-
});
|
|
68206
|
-
const footprintRepayIxs = await makeRepayIx3({
|
|
68207
|
-
program,
|
|
68208
|
-
bank: repayBank,
|
|
68209
|
-
tokenProgram: repayTokenProgram,
|
|
68210
|
-
amount: actualRepayAmount,
|
|
68211
|
-
accountAddress: marginfiAccount.address,
|
|
68212
|
-
authority: marginfiAccount.authority,
|
|
68213
|
-
isSync: true,
|
|
68214
|
-
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68215
|
-
});
|
|
68216
|
-
const runEngine = swapEngineRunner ?? runSwapEngine;
|
|
68217
|
-
const engineResult = await runEngine({
|
|
68218
|
-
inputMint: borrowBank.mint.toBase58(),
|
|
68219
|
-
outputMint: repayBank.mint.toBase58(),
|
|
68220
|
-
amountNative: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
|
|
68221
|
-
inputDecimals: borrowBank.mintDecimals,
|
|
68222
|
-
outputDecimals: repayBank.mintDecimals,
|
|
68223
|
-
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
68224
|
-
taker: marginfiAccount.authority,
|
|
68225
|
-
destinationTokenAccount,
|
|
68226
|
-
connection,
|
|
68227
|
-
footprint: {
|
|
68228
|
-
instructions: [
|
|
68229
|
-
...cuRequestIxs,
|
|
68230
|
-
...footprintBorrowIxs.instructions,
|
|
68231
|
-
...footprintRepayIxs.instructions
|
|
68232
|
-
],
|
|
68233
|
-
luts: addressLookupTableAccounts ?? [],
|
|
68234
|
-
payer: marginfiAccount.authority,
|
|
68235
|
-
sizeConstraint: swapConstraints.sizeConstraint,
|
|
68236
|
-
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
68237
|
-
},
|
|
68238
|
-
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
68239
|
-
});
|
|
68240
|
-
const quoteResponse = engineResult.quoteResponse;
|
|
68241
|
-
const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
|
|
68242
|
-
const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
|
|
68243
|
-
const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
|
|
68244
|
-
const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
|
|
68245
|
-
const borrowIxs = await makeBorrowIx3({
|
|
68246
|
-
program,
|
|
68247
|
-
bank: borrowBank,
|
|
68248
|
-
bankMap,
|
|
68249
|
-
tokenProgram: borrowTokenProgram,
|
|
68250
|
-
amount: borrowAmount,
|
|
68251
|
-
marginfiAccount,
|
|
68252
|
-
authority: marginfiAccount.authority,
|
|
68253
|
-
isSync: true,
|
|
68254
|
-
opts: {
|
|
68255
|
-
createAtas: false,
|
|
68256
|
-
wrapAndUnwrapSol: false,
|
|
68257
|
-
overrideInferAccounts
|
|
68258
|
-
}
|
|
68259
|
-
});
|
|
68260
|
-
const repayIxs = await makeRepayIx3({
|
|
68261
|
-
program,
|
|
68262
|
-
bank: repayBank,
|
|
68263
|
-
tokenProgram: repayTokenProgram,
|
|
68264
|
-
amount: amountToRepay,
|
|
68265
|
-
accountAddress: marginfiAccount.address,
|
|
68266
|
-
authority: marginfiAccount.authority,
|
|
68267
|
-
repayAll: isWholePosition(
|
|
68268
|
-
{
|
|
68269
|
-
amount: totalPositionAmount,
|
|
68270
|
-
isLending: false
|
|
68271
|
-
},
|
|
68272
|
-
amountToRepay,
|
|
68273
|
-
repayBank.mintDecimals
|
|
68274
|
-
),
|
|
68275
|
-
isSync: true,
|
|
68276
|
-
opts: {
|
|
68277
|
-
wrapAndUnwrapSol: false,
|
|
68278
|
-
overrideInferAccounts
|
|
68279
|
-
}
|
|
68280
|
-
});
|
|
68281
|
-
const luts = [...addressLookupTableAccounts ?? [], ...engineResult.swapLuts];
|
|
68282
|
-
const allNonFlIxs = [
|
|
68283
|
-
...cuRequestIxs,
|
|
68284
|
-
...borrowIxs.instructions,
|
|
68285
|
-
...engineResult.swapInstructions,
|
|
68286
|
-
...repayIxs.instructions
|
|
68287
|
-
];
|
|
68288
|
-
compileFlashloanPrecheck({
|
|
68289
|
-
allIxs: allNonFlIxs,
|
|
68290
|
-
payer: marginfiAccount.authority,
|
|
68291
|
-
luts,
|
|
68292
|
-
sizeConstraint: swapConstraints.sizeConstraint,
|
|
68293
|
-
swapIxCount: engineResult.swapInstructions.length,
|
|
68294
|
-
swapLutCount: engineResult.swapLuts.length
|
|
68295
|
-
});
|
|
68296
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
68297
|
-
program,
|
|
68298
|
-
marginfiAccount,
|
|
68299
|
-
bankMap,
|
|
68300
|
-
addressLookupTableAccounts: luts,
|
|
68301
|
-
blockhash,
|
|
68302
|
-
ixs: allNonFlIxs,
|
|
68303
|
-
isSync: true
|
|
68304
|
-
});
|
|
68305
|
-
const txSize = getTxSize(flashloanTx);
|
|
68306
|
-
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
68307
|
-
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
68308
|
-
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
68309
|
-
txSize,
|
|
68310
|
-
totalKeys,
|
|
68311
|
-
swapOpts.swapConfig?.provider
|
|
68312
|
-
);
|
|
67441
|
+
/**
|
|
67442
|
+
* Checks if the account is currently in a flash loan.
|
|
67443
|
+
*
|
|
67444
|
+
* @returns True if a flash loan is active, false otherwise
|
|
67445
|
+
*/
|
|
67446
|
+
get isFlashLoanEnabled() {
|
|
67447
|
+
return this.accountFlags.includes(2 /* ACCOUNT_IN_FLASHLOAN */);
|
|
68313
67448
|
}
|
|
68314
|
-
|
|
68315
|
-
|
|
68316
|
-
|
|
68317
|
-
|
|
68318
|
-
|
|
68319
|
-
|
|
68320
|
-
|
|
68321
|
-
}
|
|
68322
|
-
var DEFAULT_ROLL_SLIPPAGE_BPS = 50;
|
|
68323
|
-
var TRADE_PT_EVENT_AMOUNT_OUT_OFFSET = 138;
|
|
68324
|
-
var MERGE_EVENT_AMOUNT_SY_OUT_OFFSET = 296;
|
|
68325
|
-
async function makeRollPtTx(params) {
|
|
68326
|
-
const {
|
|
68327
|
-
program,
|
|
68328
|
-
marginfiAccount,
|
|
68329
|
-
connection,
|
|
68330
|
-
bankMap,
|
|
68331
|
-
oraclePrices,
|
|
68332
|
-
withdrawOpts,
|
|
68333
|
-
depositOpts,
|
|
68334
|
-
rollOpts,
|
|
68335
|
-
assetShareValueMultiplierByBank,
|
|
68336
|
-
addressLookupTableAccounts,
|
|
68337
|
-
crossbarUrl
|
|
68338
|
-
} = params;
|
|
68339
|
-
if (!rollOpts.maturedMarket && !rollOpts.maturedVault) {
|
|
68340
|
-
throw new Error("roll-pt: rollOpts.maturedMarket or maturedVault is required");
|
|
67449
|
+
/**
|
|
67450
|
+
* Checks if account authority transfer is enabled.
|
|
67451
|
+
*
|
|
67452
|
+
* @returns True if authority transfer is allowed, false otherwise
|
|
67453
|
+
*/
|
|
67454
|
+
get isTransferAccountAuthorityEnabled() {
|
|
67455
|
+
return this.accountFlags.includes(8 /* ACCOUNT_TRANSFER_AUTHORITY_ALLOWED */);
|
|
68341
67456
|
}
|
|
68342
|
-
|
|
68343
|
-
|
|
68344
|
-
|
|
68345
|
-
|
|
68346
|
-
|
|
68347
|
-
|
|
68348
|
-
|
|
68349
|
-
|
|
68350
|
-
|
|
68351
|
-
|
|
68352
|
-
owner: marginfiAccount.authority,
|
|
68353
|
-
market: rollOpts.successorMarket,
|
|
68354
|
-
ptTokenProgram: depositOpts.tokenProgram,
|
|
68355
|
-
syTokenProgram: rollOpts.syTokenProgram
|
|
68356
|
-
});
|
|
68357
|
-
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
68358
|
-
const setupIxs = await makeSetupIx({
|
|
68359
|
-
connection,
|
|
68360
|
-
authority: marginfiAccount.authority,
|
|
68361
|
-
tokens: [
|
|
68362
|
-
{ mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
|
|
68363
|
-
{ mint: merge.mergeAccounts.mintYt, tokenProgram: withdrawOpts.tokenProgram },
|
|
68364
|
-
{ mint: merge.underlying.mint, tokenProgram: merge.underlying.tokenProgram },
|
|
68365
|
-
{ mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
|
|
68366
|
-
]
|
|
68367
|
-
});
|
|
68368
|
-
const { flashloanTx, swapQuote, withdrawIxs, depositIxs } = await buildRollPtFlashloanTx({
|
|
68369
|
-
params,
|
|
68370
|
-
merge,
|
|
68371
|
-
clmm,
|
|
68372
|
-
setupIxs,
|
|
68373
|
-
blockhash
|
|
68374
|
-
});
|
|
68375
|
-
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
68376
|
-
marginfiAccount,
|
|
68377
|
-
bankMap,
|
|
68378
|
-
oraclePrices,
|
|
68379
|
-
assetShareValueMultiplierByBank,
|
|
68380
|
-
instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
68381
|
-
program,
|
|
68382
|
-
connection,
|
|
68383
|
-
crossbarUrl
|
|
68384
|
-
});
|
|
68385
|
-
const additionalTxs = [];
|
|
68386
|
-
if (setupIxs.length > 0) {
|
|
68387
|
-
const txs = splitInstructionsToFitTransactions([], setupIxs, {
|
|
68388
|
-
blockhash,
|
|
68389
|
-
payerKey: marginfiAccount.authority,
|
|
68390
|
-
luts: addressLookupTableAccounts ?? []
|
|
68391
|
-
});
|
|
68392
|
-
additionalTxs.push(
|
|
68393
|
-
...txs.map(
|
|
68394
|
-
(tx) => addTransactionMetadata(tx, {
|
|
68395
|
-
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
68396
|
-
addressLookupTables: addressLookupTableAccounts
|
|
68397
|
-
})
|
|
68398
|
-
)
|
|
68399
|
-
);
|
|
67457
|
+
/**
|
|
67458
|
+
* Sets the health cache for this account.
|
|
67459
|
+
*
|
|
67460
|
+
* Note: This mutates the account instance. Consider using simulateHealthCache()
|
|
67461
|
+
* for a pure functional approach that returns a new account instance.
|
|
67462
|
+
*
|
|
67463
|
+
* @param value - The new health cache to set
|
|
67464
|
+
*/
|
|
67465
|
+
setHealthCache(value) {
|
|
67466
|
+
this.healthCache = value;
|
|
68400
67467
|
}
|
|
68401
|
-
|
|
68402
|
-
|
|
68403
|
-
|
|
68404
|
-
|
|
68405
|
-
|
|
68406
|
-
|
|
68407
|
-
|
|
68408
|
-
|
|
68409
|
-
|
|
68410
|
-
|
|
68411
|
-
|
|
68412
|
-
);
|
|
67468
|
+
/**
|
|
67469
|
+
* Computes free collateral using cached health values.
|
|
67470
|
+
*
|
|
67471
|
+
* Free collateral represents the amount of collateral that is not backing any liabilities.
|
|
67472
|
+
*
|
|
67473
|
+
* @param opts - Optional configuration
|
|
67474
|
+
* @param opts.clamped - If true, clamps negative values to zero
|
|
67475
|
+
*
|
|
67476
|
+
* @returns The free collateral amount in USD
|
|
67477
|
+
*/
|
|
67478
|
+
computeFreeCollateralFromCache(opts) {
|
|
67479
|
+
return computeFreeCollateralFromCache(this, opts);
|
|
68413
67480
|
}
|
|
68414
|
-
|
|
68415
|
-
|
|
68416
|
-
|
|
68417
|
-
|
|
68418
|
-
|
|
68419
|
-
|
|
68420
|
-
|
|
68421
|
-
|
|
68422
|
-
|
|
68423
|
-
|
|
68424
|
-
|
|
68425
|
-
|
|
68426
|
-
|
|
68427
|
-
})
|
|
68428
|
-
const {
|
|
68429
|
-
program,
|
|
68430
|
-
marginfiAccount,
|
|
68431
|
-
bankMap,
|
|
68432
|
-
withdrawOpts,
|
|
68433
|
-
depositOpts,
|
|
68434
|
-
bankMetadataMap,
|
|
68435
|
-
connection,
|
|
68436
|
-
addressLookupTableAccounts,
|
|
68437
|
-
overrideInferAccounts,
|
|
68438
|
-
rollOpts
|
|
68439
|
-
} = params;
|
|
68440
|
-
const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount, withdrawAmount } = withdrawOpts;
|
|
68441
|
-
const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
|
|
68442
|
-
const authority = marginfiAccount.authority;
|
|
68443
|
-
if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
|
|
68444
|
-
throw new Error("withdrawAmount must be greater than 0");
|
|
67481
|
+
/**
|
|
67482
|
+
* Computes free collateral from balances using Initial margin requirements.
|
|
67483
|
+
*
|
|
67484
|
+
* Free collateral represents the amount of value available for new borrows or withdrawals.
|
|
67485
|
+
* By default, negative values are clamped to zero.
|
|
67486
|
+
*
|
|
67487
|
+
* @param params - Configuration for free collateral computation (excluding activeBalances)
|
|
67488
|
+
* @returns Free collateral value in USD (clamped to zero by default)
|
|
67489
|
+
*/
|
|
67490
|
+
computeFreeCollateralFromBalances(params) {
|
|
67491
|
+
return computeFreeCollateralFromBalances({
|
|
67492
|
+
activeBalances: this.activeBalances,
|
|
67493
|
+
...params
|
|
67494
|
+
});
|
|
68445
67495
|
}
|
|
68446
|
-
|
|
68447
|
-
|
|
68448
|
-
|
|
68449
|
-
|
|
68450
|
-
|
|
68451
|
-
|
|
68452
|
-
|
|
68453
|
-
|
|
68454
|
-
|
|
68455
|
-
|
|
68456
|
-
|
|
68457
|
-
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
68458
|
-
];
|
|
68459
|
-
const withdrawIxs = await makeWithdrawIx3({
|
|
68460
|
-
program,
|
|
68461
|
-
bank: withdrawBank,
|
|
68462
|
-
bankMap,
|
|
68463
|
-
tokenProgram: withdrawTokenProgram,
|
|
68464
|
-
amount: actualWithdrawAmount,
|
|
68465
|
-
marginfiAccount,
|
|
68466
|
-
authority,
|
|
68467
|
-
withdrawAll: isFullWithdraw,
|
|
68468
|
-
isSync: false,
|
|
68469
|
-
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68470
|
-
});
|
|
68471
|
-
const mergeIx = makeExponentMergeIx(merge.mergeAccounts, withdrawNative);
|
|
68472
|
-
const depositIxs = await makeDepositIx3({
|
|
68473
|
-
program,
|
|
68474
|
-
bank: depositBank,
|
|
68475
|
-
tokenProgram: depositTokenProgram,
|
|
68476
|
-
amount: 0,
|
|
68477
|
-
accountAddress: marginfiAccount.address,
|
|
68478
|
-
authority,
|
|
68479
|
-
group: marginfiAccount.group,
|
|
68480
|
-
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68481
|
-
});
|
|
68482
|
-
let luts;
|
|
68483
|
-
if (rollOpts.lookupTable) {
|
|
68484
|
-
const fetched = (await connection.getAddressLookupTable(rollOpts.lookupTable)).value;
|
|
68485
|
-
if (!fetched) {
|
|
68486
|
-
throw new Error(`roll-pt: PT-roll lookup table not found: ${rollOpts.lookupTable.toBase58()}`);
|
|
68487
|
-
}
|
|
68488
|
-
luts = [fetched, merge.addressLookupTable, clmm.addressLookupTable];
|
|
68489
|
-
} else {
|
|
68490
|
-
luts = [
|
|
68491
|
-
...addressLookupTableAccounts ?? [],
|
|
68492
|
-
merge.addressLookupTable,
|
|
68493
|
-
clmm.addressLookupTable
|
|
68494
|
-
];
|
|
67496
|
+
/**
|
|
67497
|
+
* Computes health components using cached health values.
|
|
67498
|
+
*
|
|
67499
|
+
* Returns weighted asset and liability values based on the margin requirement type.
|
|
67500
|
+
*
|
|
67501
|
+
* @param marginReqType - The margin requirement type (Initial, Maintenance, or Equity)
|
|
67502
|
+
*
|
|
67503
|
+
* @returns Object containing assets and liabilities values in USD
|
|
67504
|
+
*/
|
|
67505
|
+
computeHealthComponentsFromCache(marginRequirement) {
|
|
67506
|
+
return computeHealthComponentsFromCache(this, marginRequirement);
|
|
68495
67507
|
}
|
|
68496
|
-
|
|
68497
|
-
|
|
68498
|
-
|
|
68499
|
-
|
|
68500
|
-
|
|
68501
|
-
|
|
68502
|
-
|
|
68503
|
-
|
|
68504
|
-
|
|
68505
|
-
|
|
68506
|
-
|
|
68507
|
-
|
|
68508
|
-
|
|
68509
|
-
|
|
68510
|
-
throw new Error("roll-pt: merge would redeem 0 SY (empty/invalid matured vault state)");
|
|
68511
|
-
}
|
|
68512
|
-
const exactPtOut = await quoteClmmTradeOut({
|
|
68513
|
-
connection,
|
|
68514
|
-
clmm,
|
|
68515
|
-
amountInSyNative: syExact,
|
|
68516
|
-
payer: authority
|
|
68517
|
-
});
|
|
68518
|
-
const slippageBps = rollOpts.slippageBps ?? DEFAULT_ROLL_SLIPPAGE_BPS;
|
|
68519
|
-
const minPtOut = exactPtOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
68520
|
-
if (minPtOut <= 0n) {
|
|
68521
|
-
throw new Error("roll-pt: quoted PT out is 0 (insufficient CLMM liquidity for this size)");
|
|
68522
|
-
}
|
|
68523
|
-
const tradeIx = makeExponentClmmTradePtIx(
|
|
68524
|
-
clmm.tradePtAccounts,
|
|
68525
|
-
exponentClmmBuyPtArgs({ amountInSyNative: syExact, minPtOutNative: minPtOut })
|
|
68526
|
-
);
|
|
68527
|
-
const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
|
|
68528
|
-
if (!depositIxToPatch) {
|
|
68529
|
-
throw new Error("roll-pt: could not locate deposit instruction for amount patching");
|
|
68530
|
-
}
|
|
68531
|
-
patchDepositAmount(depositIxToPatch, new BN9(minPtOut.toString()));
|
|
68532
|
-
const allNonFlIxs = [
|
|
68533
|
-
...cuRequestIxs,
|
|
68534
|
-
...withdrawIxs.instructions,
|
|
68535
|
-
mergeIx,
|
|
68536
|
-
tradeIx,
|
|
68537
|
-
...depositIxs.instructions
|
|
68538
|
-
];
|
|
68539
|
-
const { sizeConstraint } = computeFlashLoanNonSwapBudget({
|
|
68540
|
-
program,
|
|
68541
|
-
marginfiAccount,
|
|
68542
|
-
bankMap,
|
|
68543
|
-
addressLookupTableAccounts: luts,
|
|
68544
|
-
ixs: allNonFlIxs
|
|
68545
|
-
});
|
|
68546
|
-
compileFlashloanPrecheck({
|
|
68547
|
-
allIxs: allNonFlIxs,
|
|
68548
|
-
payer: authority,
|
|
68549
|
-
luts,
|
|
68550
|
-
sizeConstraint,
|
|
68551
|
-
swapIxCount: 0,
|
|
68552
|
-
swapLutCount: 0
|
|
68553
|
-
});
|
|
68554
|
-
const flashloanTx = await makeFlashLoanTx({
|
|
68555
|
-
program,
|
|
68556
|
-
marginfiAccount,
|
|
68557
|
-
bankMap,
|
|
68558
|
-
addressLookupTableAccounts: luts,
|
|
68559
|
-
blockhash,
|
|
68560
|
-
ixs: allNonFlIxs,
|
|
68561
|
-
isSync: false
|
|
68562
|
-
});
|
|
68563
|
-
const txSize = getTxSize(flashloanTx);
|
|
68564
|
-
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
68565
|
-
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
68566
|
-
throw TransactionBuildingError.swapSizeExceededPositionSwap(txSize, totalKeys, void 0);
|
|
68567
|
-
}
|
|
68568
|
-
const swapQuote = {
|
|
68569
|
-
inAmount: syExact.toString(),
|
|
68570
|
-
outAmount: exactPtOut.toString(),
|
|
68571
|
-
otherAmountThreshold: minPtOut.toString(),
|
|
68572
|
-
slippageBps
|
|
68573
|
-
};
|
|
68574
|
-
return { flashloanTx, swapQuote, withdrawIxs, depositIxs };
|
|
68575
|
-
}
|
|
68576
|
-
async function simulateRollReturn({
|
|
68577
|
-
program,
|
|
68578
|
-
marginfiAccount,
|
|
68579
|
-
bankMap,
|
|
68580
|
-
connection,
|
|
68581
|
-
blockhash,
|
|
68582
|
-
luts,
|
|
68583
|
-
ixs,
|
|
68584
|
-
programId,
|
|
68585
|
-
label
|
|
68586
|
-
}) {
|
|
68587
|
-
const quoteTx = await makeFlashLoanTx({
|
|
68588
|
-
program,
|
|
68589
|
-
marginfiAccount,
|
|
68590
|
-
bankMap,
|
|
68591
|
-
addressLookupTableAccounts: luts,
|
|
68592
|
-
blockhash,
|
|
68593
|
-
ixs,
|
|
68594
|
-
isSync: false
|
|
68595
|
-
});
|
|
68596
|
-
const sim = await connection.simulateTransaction(quoteTx, {
|
|
68597
|
-
sigVerify: false,
|
|
68598
|
-
replaceRecentBlockhash: true
|
|
68599
|
-
});
|
|
68600
|
-
const logs = sim.value.logs ?? [];
|
|
68601
|
-
if (process.env.ROLL_DEBUG) {
|
|
68602
|
-
console.error(
|
|
68603
|
-
`[roll ${label} sim] err:`,
|
|
68604
|
-
JSON.stringify(sim.value.err),
|
|
68605
|
-
"returnData:",
|
|
68606
|
-
JSON.stringify(sim.value.returnData),
|
|
68607
|
-
"logsLen:",
|
|
68608
|
-
logs.length,
|
|
68609
|
-
"truncated:",
|
|
68610
|
-
logs.some((l) => l.includes("truncated"))
|
|
68611
|
-
);
|
|
68612
|
-
}
|
|
68613
|
-
const prefix = `Program return: ${programId.toBase58()} `;
|
|
68614
|
-
const line = [...logs].reverse().find((l) => l.startsWith(prefix));
|
|
68615
|
-
if (!line) {
|
|
68616
|
-
throw new Error(
|
|
68617
|
-
`roll-pt: could not read ${label} return data from quote simulation (err=${JSON.stringify(
|
|
68618
|
-
sim.value.err
|
|
68619
|
-
)})`
|
|
68620
|
-
);
|
|
68621
|
-
}
|
|
68622
|
-
return Buffer.from(line.slice(prefix.length), "base64");
|
|
68623
|
-
}
|
|
68624
|
-
function readReturnU64(data, offset, what) {
|
|
68625
|
-
if (data.length < offset + 8) {
|
|
68626
|
-
throw new Error(`roll-pt: ${what} return data too short (${data.length} bytes)`);
|
|
68627
|
-
}
|
|
68628
|
-
return data.readBigUInt64LE(offset);
|
|
68629
|
-
}
|
|
68630
|
-
async function quoteClmmTradeOut({
|
|
68631
|
-
connection,
|
|
68632
|
-
clmm,
|
|
68633
|
-
amountInSyNative,
|
|
68634
|
-
payer
|
|
68635
|
-
}) {
|
|
68636
|
-
const excluded = /* @__PURE__ */ new Set([
|
|
68637
|
-
clmm.tradePtAccounts.tokenSyEscrow.toBase58(),
|
|
68638
|
-
clmm.tradePtAccounts.tokenFeeTreasurySy.toBase58()
|
|
68639
|
-
]);
|
|
68640
|
-
const largest = await connection.getTokenLargestAccounts(clmm.sy.mint);
|
|
68641
|
-
const funded = largest.value.find(
|
|
68642
|
-
(a) => !excluded.has(a.address.toBase58()) && BigInt(a.amount) >= amountInSyNative
|
|
68643
|
-
);
|
|
68644
|
-
if (!funded) {
|
|
68645
|
-
throw new Error(
|
|
68646
|
-
"roll-pt: no SY holder large enough to quote the buy \u2014 the roll size exceeds available CLMM liquidity for this pair"
|
|
68647
|
-
);
|
|
68648
|
-
}
|
|
68649
|
-
const parsed = await connection.getParsedAccountInfo(funded.address);
|
|
68650
|
-
const info = parsed.value?.data?.parsed?.info;
|
|
68651
|
-
if (!info?.owner) throw new Error("roll-pt: could not resolve the quote SY holder's owner");
|
|
68652
|
-
const trader = new PublicKey(info.owner);
|
|
68653
|
-
const ptTokenProgram = clmm.pt.tokenProgram ?? TOKEN_PROGRAM_ID;
|
|
68654
|
-
const tokenPtTrader = getAssociatedTokenAddressSync(clmm.pt.mint, trader, true, ptTokenProgram);
|
|
68655
|
-
const quoteIx = makeExponentClmmTradePtIx(
|
|
68656
|
-
{ ...clmm.tradePtAccounts, trader, tokenSyTrader: funded.address, tokenPtTrader },
|
|
68657
|
-
exponentClmmBuyPtArgs({ amountInSyNative, minPtOutNative: 1n })
|
|
68658
|
-
);
|
|
68659
|
-
const createPtAta = createAssociatedTokenAccountIdempotentInstruction(
|
|
68660
|
-
payer,
|
|
68661
|
-
tokenPtTrader,
|
|
68662
|
-
trader,
|
|
68663
|
-
clmm.pt.mint,
|
|
68664
|
-
ptTokenProgram
|
|
68665
|
-
);
|
|
68666
|
-
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
68667
|
-
const message = new TransactionMessage({
|
|
68668
|
-
payerKey: payer,
|
|
68669
|
-
recentBlockhash: blockhash,
|
|
68670
|
-
instructions: [createPtAta, quoteIx]
|
|
68671
|
-
}).compileToV0Message([clmm.addressLookupTable]);
|
|
68672
|
-
const sim = await connection.simulateTransaction(new VersionedTransaction(message), {
|
|
68673
|
-
sigVerify: false,
|
|
68674
|
-
replaceRecentBlockhash: true
|
|
68675
|
-
});
|
|
68676
|
-
const rd = sim.value.returnData;
|
|
68677
|
-
if (process.env.ROLL_DEBUG) {
|
|
68678
|
-
console.error("[roll trade quote] err:", JSON.stringify(sim.value.err), "returnData?", !!rd);
|
|
68679
|
-
}
|
|
68680
|
-
if (!rd?.data || rd.programId !== EXPONENT_CLMM_PROGRAM_ID.toBase58()) {
|
|
68681
|
-
throw new Error(
|
|
68682
|
-
`roll-pt: CLMM trade quote produced no return data (err=${JSON.stringify(sim.value.err)})`
|
|
68683
|
-
);
|
|
68684
|
-
}
|
|
68685
|
-
const data = Buffer.from(rd.data[0], rd.data[1]);
|
|
68686
|
-
return readReturnU64(data, TRADE_PT_EVENT_AMOUNT_OUT_OFFSET, "trade_pt amount_out");
|
|
68687
|
-
}
|
|
68688
|
-
|
|
68689
|
-
// src/models/balance.ts
|
|
68690
|
-
var Balance = class _Balance {
|
|
68691
|
-
constructor(active, bankPk, assetShares, liabilityShares, emissionsOutstanding, lastUpdate) {
|
|
68692
|
-
this.active = active;
|
|
68693
|
-
this.bankPk = bankPk;
|
|
68694
|
-
this.assetShares = assetShares;
|
|
68695
|
-
this.liabilityShares = liabilityShares;
|
|
68696
|
-
this.emissionsOutstanding = emissionsOutstanding;
|
|
68697
|
-
this.lastUpdate = lastUpdate;
|
|
68698
|
-
}
|
|
68699
|
-
static from(balanceRaw) {
|
|
68700
|
-
const props = parseBalanceRaw(balanceRaw);
|
|
68701
|
-
return new _Balance(
|
|
68702
|
-
props.active,
|
|
68703
|
-
props.bankPk,
|
|
68704
|
-
props.assetShares,
|
|
68705
|
-
props.liabilityShares,
|
|
68706
|
-
props.emissionsOutstanding,
|
|
68707
|
-
props.lastUpdate
|
|
68708
|
-
);
|
|
68709
|
-
}
|
|
68710
|
-
static fromBalanceType(balance) {
|
|
68711
|
-
return new _Balance(
|
|
68712
|
-
balance.active,
|
|
68713
|
-
balance.bankPk,
|
|
68714
|
-
balance.assetShares,
|
|
68715
|
-
balance.liabilityShares,
|
|
68716
|
-
balance.emissionsOutstanding,
|
|
68717
|
-
balance.lastUpdate
|
|
68718
|
-
);
|
|
68719
|
-
}
|
|
68720
|
-
static createEmpty(bankPk) {
|
|
68721
|
-
const balance = createEmptyBalance(bankPk);
|
|
68722
|
-
return this.fromBalanceType(balance);
|
|
68723
|
-
}
|
|
68724
|
-
computeUsdValue(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
|
|
68725
|
-
return computeBalanceUsdValue({
|
|
68726
|
-
balance: this,
|
|
68727
|
-
bank,
|
|
68728
|
-
oraclePrice,
|
|
68729
|
-
marginRequirement,
|
|
68730
|
-
assetShareValueMultiplier,
|
|
68731
|
-
activeEmodeWeights
|
|
68732
|
-
});
|
|
68733
|
-
}
|
|
68734
|
-
getUsdValueWithPriceBias(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
|
|
68735
|
-
return getBalanceUsdValueWithPriceBias({
|
|
68736
|
-
balance: this,
|
|
68737
|
-
bank,
|
|
68738
|
-
oraclePrice,
|
|
68739
|
-
marginRequirement,
|
|
68740
|
-
assetShareValueMultiplier,
|
|
68741
|
-
activeEmodeWeights
|
|
68742
|
-
});
|
|
68743
|
-
}
|
|
68744
|
-
computeQuantity(bank) {
|
|
68745
|
-
return computeQuantity(this, bank);
|
|
68746
|
-
}
|
|
68747
|
-
computeQuantityUi(bank, assetShareValueMultiplier) {
|
|
68748
|
-
return computeQuantityUi(this, bank, assetShareValueMultiplier);
|
|
68749
|
-
}
|
|
68750
|
-
computeTotalOutstandingEmissions(bank) {
|
|
68751
|
-
return computeTotalOutstandingEmissions(this, bank);
|
|
68752
|
-
}
|
|
68753
|
-
computeClaimedEmissions(bank, currentTimestamp) {
|
|
68754
|
-
return computeClaimedEmissions(this, bank, currentTimestamp);
|
|
68755
|
-
}
|
|
68756
|
-
};
|
|
68757
|
-
|
|
68758
|
-
// src/models/health-cache.ts
|
|
68759
|
-
var HealthCache = class _HealthCache {
|
|
68760
|
-
constructor(assetValue, liabilityValue, assetValueMaint, liabilityValueMaint, assetValueEquity, liabilityValueEquity, timestamp, flags, prices, simulationStatus) {
|
|
68761
|
-
this.assetValue = assetValue;
|
|
68762
|
-
this.liabilityValue = liabilityValue;
|
|
68763
|
-
this.assetValueMaint = assetValueMaint;
|
|
68764
|
-
this.liabilityValueMaint = liabilityValueMaint;
|
|
68765
|
-
this.assetValueEquity = assetValueEquity;
|
|
68766
|
-
this.liabilityValueEquity = liabilityValueEquity;
|
|
68767
|
-
this.timestamp = timestamp;
|
|
68768
|
-
this.flags = flags;
|
|
68769
|
-
this.prices = prices;
|
|
68770
|
-
this.simulationStatus = simulationStatus;
|
|
68771
|
-
}
|
|
68772
|
-
static fromHealthCacheType(healthCacheType) {
|
|
68773
|
-
return new _HealthCache(
|
|
68774
|
-
healthCacheType.assetValue,
|
|
68775
|
-
healthCacheType.liabilityValue,
|
|
68776
|
-
healthCacheType.assetValueMaint,
|
|
68777
|
-
healthCacheType.liabilityValueMaint,
|
|
68778
|
-
healthCacheType.assetValueEquity,
|
|
68779
|
-
healthCacheType.liabilityValueEquity,
|
|
68780
|
-
healthCacheType.timestamp,
|
|
68781
|
-
healthCacheType.flags,
|
|
68782
|
-
healthCacheType.prices,
|
|
68783
|
-
healthCacheType.simulationStatus
|
|
68784
|
-
);
|
|
68785
|
-
}
|
|
68786
|
-
static from(healthCacheRaw) {
|
|
68787
|
-
return this.fromHealthCacheType(parseHealthCacheRaw(healthCacheRaw));
|
|
68788
|
-
}
|
|
68789
|
-
};
|
|
68790
|
-
|
|
68791
|
-
// src/models/account.ts
|
|
68792
|
-
var MarginfiAccount = class _MarginfiAccount {
|
|
68793
|
-
constructor(address, group, authority, balances, accountFlags, emissionsDestinationAccount, healthCache) {
|
|
68794
|
-
this.address = address;
|
|
68795
|
-
this.group = group;
|
|
68796
|
-
this.authority = authority;
|
|
68797
|
-
this.balances = balances;
|
|
68798
|
-
this.accountFlags = accountFlags;
|
|
68799
|
-
this.emissionsDestinationAccount = emissionsDestinationAccount;
|
|
68800
|
-
this.healthCache = healthCache;
|
|
68801
|
-
}
|
|
68802
|
-
/**
|
|
68803
|
-
* Fetches a marginfi account from on-chain data.
|
|
68804
|
-
*
|
|
68805
|
-
* @param address - The public key of the marginfi account
|
|
68806
|
-
* @param program - The Marginfi program instance
|
|
68807
|
-
*
|
|
68808
|
-
* @returns Promise resolving to a MarginfiAccount instance
|
|
68809
|
-
*/
|
|
68810
|
-
static async fetch(address, program) {
|
|
68811
|
-
const data = await program.account.marginfiAccount.fetch(address);
|
|
68812
|
-
return _MarginfiAccount.fromAccountParsed(address, data);
|
|
68813
|
-
}
|
|
68814
|
-
static decodeAccountRaw(encoded, idl) {
|
|
68815
|
-
return decodeAccountRaw(encoded, idl);
|
|
68816
|
-
}
|
|
68817
|
-
static fromAccountType(account) {
|
|
68818
|
-
return new _MarginfiAccount(
|
|
68819
|
-
account.address,
|
|
68820
|
-
account.group,
|
|
68821
|
-
account.authority,
|
|
68822
|
-
account.balances.map((b) => Balance.fromBalanceType(b)),
|
|
68823
|
-
account.accountFlags,
|
|
68824
|
-
account.emissionsDestinationAccount,
|
|
68825
|
-
account.healthCache
|
|
68826
|
-
);
|
|
68827
|
-
}
|
|
68828
|
-
/**
|
|
68829
|
-
* Creates a MarginfiAccount instance from parsed account data.
|
|
68830
|
-
*
|
|
68831
|
-
* @param marginfiAccountPk - The public key of the marginfi account
|
|
68832
|
-
* @param accountData - The raw account data from the program
|
|
68833
|
-
*
|
|
68834
|
-
* @returns A new MarginfiAccount instance
|
|
68835
|
-
*/
|
|
68836
|
-
static fromAccountParsed(marginfiAccountPk, accountData) {
|
|
68837
|
-
const props = parseMarginfiAccountRaw(marginfiAccountPk, accountData);
|
|
68838
|
-
return new _MarginfiAccount(
|
|
68839
|
-
props.address,
|
|
68840
|
-
props.group,
|
|
68841
|
-
props.authority,
|
|
68842
|
-
props.balances.map((b) => Balance.fromBalanceType(b)),
|
|
68843
|
-
props.accountFlags,
|
|
68844
|
-
props.emissionsDestinationAccount,
|
|
68845
|
-
HealthCache.fromHealthCacheType(props.healthCache)
|
|
68846
|
-
);
|
|
68847
|
-
}
|
|
68848
|
-
/**
|
|
68849
|
-
* Simulates and updates the health cache for this account.
|
|
68850
|
-
*
|
|
68851
|
-
* Fetches current oracle prices and computes fresh health values. Returns a new
|
|
68852
|
-
* account instance with updated health cache (does not mutate this instance).
|
|
68853
|
-
*
|
|
68854
|
-
* @param params - Configuration for health cache simulation (excluding marginfiAccount)
|
|
68855
|
-
* @returns Object containing the updated account and any errors
|
|
68856
|
-
*/
|
|
68857
|
-
async simulateHealthCache(params) {
|
|
68858
|
-
const accountWithHealthCache = await simulateAccountHealthCacheWithFallback({
|
|
68859
|
-
marginfiAccount: this,
|
|
68860
|
-
...params
|
|
68861
|
-
});
|
|
68862
|
-
return {
|
|
68863
|
-
account: _MarginfiAccount.fromAccountType(accountWithHealthCache.marginfiAccount),
|
|
68864
|
-
error: accountWithHealthCache.error
|
|
68865
|
-
};
|
|
68866
|
-
}
|
|
68867
|
-
static fromAccountDataRaw(marginfiAccountPk, rawData, idl) {
|
|
68868
|
-
const marginfiAccountData = _MarginfiAccount.decodeAccountRaw(rawData, idl);
|
|
68869
|
-
return _MarginfiAccount.fromAccountParsed(marginfiAccountPk, marginfiAccountData);
|
|
68870
|
-
}
|
|
68871
|
-
// ----------------------------------------------------------------------------
|
|
68872
|
-
// Attributes
|
|
68873
|
-
// ----------------------------------------------------------------------------
|
|
68874
|
-
/**
|
|
68875
|
-
* Gets all balances that are currently active (non-zero).
|
|
68876
|
-
*
|
|
68877
|
-
* @returns Array of active Balance instances
|
|
68878
|
-
*/
|
|
68879
|
-
get activeBalances() {
|
|
68880
|
-
return this.balances.filter((b) => b.active);
|
|
68881
|
-
}
|
|
68882
|
-
/**
|
|
68883
|
-
* Gets the balance for a specific bank.
|
|
68884
|
-
*
|
|
68885
|
-
* @param bankPk - The public key of the bank
|
|
68886
|
-
*
|
|
68887
|
-
* @returns The Balance instance for the bank (may be empty)
|
|
68888
|
-
*/
|
|
68889
|
-
getBalance(bankPk) {
|
|
68890
|
-
return Balance.fromBalanceType(getBalance(bankPk, this.balances));
|
|
68891
|
-
}
|
|
68892
|
-
/**
|
|
68893
|
-
* Checks if the account is disabled.
|
|
68894
|
-
*
|
|
68895
|
-
* @returns True if the account is disabled, false otherwise
|
|
68896
|
-
*/
|
|
68897
|
-
get isDisabled() {
|
|
68898
|
-
return this.accountFlags.includes(1 /* ACCOUNT_DISABLED */);
|
|
68899
|
-
}
|
|
68900
|
-
/**
|
|
68901
|
-
* Checks if the account is currently in a flash loan.
|
|
68902
|
-
*
|
|
68903
|
-
* @returns True if a flash loan is active, false otherwise
|
|
68904
|
-
*/
|
|
68905
|
-
get isFlashLoanEnabled() {
|
|
68906
|
-
return this.accountFlags.includes(2 /* ACCOUNT_IN_FLASHLOAN */);
|
|
68907
|
-
}
|
|
68908
|
-
/**
|
|
68909
|
-
* Checks if account authority transfer is enabled.
|
|
68910
|
-
*
|
|
68911
|
-
* @returns True if authority transfer is allowed, false otherwise
|
|
68912
|
-
*/
|
|
68913
|
-
get isTransferAccountAuthorityEnabled() {
|
|
68914
|
-
return this.accountFlags.includes(8 /* ACCOUNT_TRANSFER_AUTHORITY_ALLOWED */);
|
|
68915
|
-
}
|
|
68916
|
-
/**
|
|
68917
|
-
* Sets the health cache for this account.
|
|
68918
|
-
*
|
|
68919
|
-
* Note: This mutates the account instance. Consider using simulateHealthCache()
|
|
68920
|
-
* for a pure functional approach that returns a new account instance.
|
|
68921
|
-
*
|
|
68922
|
-
* @param value - The new health cache to set
|
|
68923
|
-
*/
|
|
68924
|
-
setHealthCache(value) {
|
|
68925
|
-
this.healthCache = value;
|
|
68926
|
-
}
|
|
68927
|
-
/**
|
|
68928
|
-
* Computes free collateral using cached health values.
|
|
68929
|
-
*
|
|
68930
|
-
* Free collateral represents the amount of collateral that is not backing any liabilities.
|
|
68931
|
-
*
|
|
68932
|
-
* @param opts - Optional configuration
|
|
68933
|
-
* @param opts.clamped - If true, clamps negative values to zero
|
|
68934
|
-
*
|
|
68935
|
-
* @returns The free collateral amount in USD
|
|
68936
|
-
*/
|
|
68937
|
-
computeFreeCollateralFromCache(opts) {
|
|
68938
|
-
return computeFreeCollateralFromCache(this, opts);
|
|
68939
|
-
}
|
|
68940
|
-
/**
|
|
68941
|
-
* Computes free collateral from balances using Initial margin requirements.
|
|
68942
|
-
*
|
|
68943
|
-
* Free collateral represents the amount of value available for new borrows or withdrawals.
|
|
68944
|
-
* By default, negative values are clamped to zero.
|
|
68945
|
-
*
|
|
68946
|
-
* @param params - Configuration for free collateral computation (excluding activeBalances)
|
|
68947
|
-
* @returns Free collateral value in USD (clamped to zero by default)
|
|
68948
|
-
*/
|
|
68949
|
-
computeFreeCollateralFromBalances(params) {
|
|
68950
|
-
return computeFreeCollateralFromBalances({
|
|
68951
|
-
activeBalances: this.activeBalances,
|
|
68952
|
-
...params
|
|
68953
|
-
});
|
|
68954
|
-
}
|
|
68955
|
-
/**
|
|
68956
|
-
* Computes health components using cached health values.
|
|
68957
|
-
*
|
|
68958
|
-
* Returns weighted asset and liability values based on the margin requirement type.
|
|
68959
|
-
*
|
|
68960
|
-
* @param marginReqType - The margin requirement type (Initial, Maintenance, or Equity)
|
|
68961
|
-
*
|
|
68962
|
-
* @returns Object containing assets and liabilities values in USD
|
|
68963
|
-
*/
|
|
68964
|
-
computeHealthComponentsFromCache(marginRequirement) {
|
|
68965
|
-
return computeHealthComponentsFromCache(this, marginRequirement);
|
|
68966
|
-
}
|
|
68967
|
-
/**
|
|
68968
|
-
* Computes health components from balances with price bias.
|
|
68969
|
-
*
|
|
68970
|
-
* Returns weighted asset and liability values using conservative pricing
|
|
68971
|
-
* (Lowest for assets, Highest for liabilities).
|
|
68972
|
-
*
|
|
68973
|
-
* @param params - Configuration for health computation (excluding activeBalances)
|
|
68974
|
-
* @returns Object containing assets and liabilities values in USD
|
|
68975
|
-
*/
|
|
68976
|
-
computeHealthComponentsFromBalances(params) {
|
|
68977
|
-
return computeHealthComponentsFromBalances({
|
|
68978
|
-
activeBalances: this.activeBalances,
|
|
68979
|
-
...params
|
|
68980
|
-
});
|
|
67508
|
+
/**
|
|
67509
|
+
* Computes health components from balances with price bias.
|
|
67510
|
+
*
|
|
67511
|
+
* Returns weighted asset and liability values using conservative pricing
|
|
67512
|
+
* (Lowest for assets, Highest for liabilities).
|
|
67513
|
+
*
|
|
67514
|
+
* @param params - Configuration for health computation (excluding activeBalances)
|
|
67515
|
+
* @returns Object containing assets and liabilities values in USD
|
|
67516
|
+
*/
|
|
67517
|
+
computeHealthComponentsFromBalances(params) {
|
|
67518
|
+
return computeHealthComponentsFromBalances({
|
|
67519
|
+
activeBalances: this.activeBalances,
|
|
67520
|
+
...params
|
|
67521
|
+
});
|
|
68981
67522
|
}
|
|
68982
67523
|
/**
|
|
68983
67524
|
* Computes the total account value (equity).
|
|
@@ -69382,6 +67923,86 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
69382
67923
|
}
|
|
69383
67924
|
});
|
|
69384
67925
|
}
|
|
67926
|
+
/**
|
|
67927
|
+
* Creates a loop transaction with a transparent bridged (double-hop) fallback.
|
|
67928
|
+
*
|
|
67929
|
+
* One call: tries the direct {@link makeLoopTx} first; if its borrow→deposit swap can't fit one
|
|
67930
|
+
* transaction (size / account-locks) or has no route, it loops the deposit asset against a
|
|
67931
|
+
* value-equivalent borrow of a high-liquidity bridge token, then debt-swaps the bridge debt to
|
|
67932
|
+
* the requested borrow asset — both legs composed into ONE atomic Jito bundle.
|
|
67933
|
+
*
|
|
67934
|
+
* Bridge candidates default to USDC → wSOL → USDT and can be reordered/overridden via
|
|
67935
|
+
* `params.bridgeOpts.bridgeCandidateMints`; `bridgeOpts` also accepts known token programs (skips RPC
|
|
67936
|
+
* lookups), a bundle-size ceiling, and an abort signal. `result.bridgeMint` is set only when the
|
|
67937
|
+
* bridged path was used.
|
|
67938
|
+
*
|
|
67939
|
+
* Intended for existing accounts — a fresh account's loop fits the direct path, so flows that
|
|
67940
|
+
* create the account in the same action should call {@link makeLoopTx} directly.
|
|
67941
|
+
*
|
|
67942
|
+
* @param params - Loop transaction parameters plus optional `bridgeOpts`
|
|
67943
|
+
* @returns Object containing transactions, action index, merged swap quote, and the bridge mint
|
|
67944
|
+
*
|
|
67945
|
+
* @see {@link makeBridgedLoopTx} for detailed implementation
|
|
67946
|
+
*/
|
|
67947
|
+
async makeBridgedLoopTx(params) {
|
|
67948
|
+
return makeBridgedLoopTx({
|
|
67949
|
+
...params,
|
|
67950
|
+
marginfiAccount: this,
|
|
67951
|
+
overrideInferAccounts: {
|
|
67952
|
+
authority: this.authority,
|
|
67953
|
+
group: this.group,
|
|
67954
|
+
...params.overrideInferAccounts
|
|
67955
|
+
}
|
|
67956
|
+
});
|
|
67957
|
+
}
|
|
67958
|
+
/**
|
|
67959
|
+
* Creates a collateral-swap transaction with a transparent bridged (double-hop) fallback.
|
|
67960
|
+
*
|
|
67961
|
+
* One call: tries the direct {@link makeSwapCollateralTx} first; if the swap `A → C` can't fit
|
|
67962
|
+
* one transaction or has no route, it decomposes into `A → bridge` + `bridge → C` through a
|
|
67963
|
+
* high-liquidity bridge collateral, both legs composed into ONE atomic Jito bundle. See
|
|
67964
|
+
* {@link makeBridgedLoopTx} for the `bridgeOpts` knobs.
|
|
67965
|
+
*
|
|
67966
|
+
* @param params - Swap collateral transaction parameters plus optional `bridgeOpts`
|
|
67967
|
+
* @returns Object containing transactions, action index, merged swap quote, and the bridge mint
|
|
67968
|
+
*
|
|
67969
|
+
* @see {@link makeBridgedSwapCollateralTx} for detailed implementation
|
|
67970
|
+
*/
|
|
67971
|
+
async makeBridgedSwapCollateralTx(params) {
|
|
67972
|
+
return makeBridgedSwapCollateralTx({
|
|
67973
|
+
...params,
|
|
67974
|
+
marginfiAccount: this,
|
|
67975
|
+
overrideInferAccounts: {
|
|
67976
|
+
authority: this.authority,
|
|
67977
|
+
group: this.group,
|
|
67978
|
+
...params.overrideInferAccounts
|
|
67979
|
+
}
|
|
67980
|
+
});
|
|
67981
|
+
}
|
|
67982
|
+
/**
|
|
67983
|
+
* Creates a debt-swap transaction with a transparent bridged (double-hop) fallback.
|
|
67984
|
+
*
|
|
67985
|
+
* One call: tries the direct {@link makeSwapDebtTx} first; if the swap `A → C` can't fit one
|
|
67986
|
+
* transaction or has no route, the first leg repays A by borrowing a bridge token and the second
|
|
67987
|
+
* leg repays exactly that bridge debt while borrowing C — both legs composed into ONE atomic
|
|
67988
|
+
* Jito bundle. See {@link makeBridgedLoopTx} for the `bridgeOpts` knobs.
|
|
67989
|
+
*
|
|
67990
|
+
* @param params - Swap debt transaction parameters plus optional `bridgeOpts`
|
|
67991
|
+
* @returns Object containing transactions, action index, merged swap quote, and the bridge mint
|
|
67992
|
+
*
|
|
67993
|
+
* @see {@link makeBridgedSwapDebtTx} for detailed implementation
|
|
67994
|
+
*/
|
|
67995
|
+
async makeBridgedSwapDebtTx(params) {
|
|
67996
|
+
return makeBridgedSwapDebtTx({
|
|
67997
|
+
...params,
|
|
67998
|
+
marginfiAccount: this,
|
|
67999
|
+
overrideInferAccounts: {
|
|
68000
|
+
authority: this.authority,
|
|
68001
|
+
group: this.group,
|
|
68002
|
+
...params.overrideInferAccounts
|
|
68003
|
+
}
|
|
68004
|
+
});
|
|
68005
|
+
}
|
|
69385
68006
|
/**
|
|
69386
68007
|
* Creates a transaction to repay debt using collateral.
|
|
69387
68008
|
*
|
|
@@ -69421,425 +68042,2168 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
69421
68042
|
}
|
|
69422
68043
|
});
|
|
69423
68044
|
}
|
|
69424
|
-
/**
|
|
69425
|
-
* Creates a transaction to swap one collateral position to another using a flash loan.
|
|
69426
|
-
*
|
|
69427
|
-
* A swap collateral transaction:
|
|
69428
|
-
* 1. Withdraws existing collateral via flash loan
|
|
69429
|
-
* 2. Swaps collateral to new asset (via Jupiter)
|
|
69430
|
-
* 3. Deposits swapped assets as new collateral
|
|
69431
|
-
*
|
|
69432
|
-
* This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
|
|
69433
|
-
* withdrawing and affecting their health during the swap.
|
|
69434
|
-
*
|
|
69435
|
-
* @param params - Swap collateral transaction parameters
|
|
69436
|
-
* @param params.connection - Solana connection instance
|
|
69437
|
-
* @param params.oraclePrices - Map of current oracle prices
|
|
69438
|
-
* @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
|
|
69439
|
-
* @param params.depositOpts - Deposit configuration (bank, tokenProgram)
|
|
69440
|
-
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
69441
|
-
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
69442
|
-
* @param params.overrideInferAccounts - Optional account overrides
|
|
69443
|
-
* @param params.additionalIxs - Additional instructions to include
|
|
69444
|
-
* @param params.crossbarUrl - Crossbar URL for oracle updates
|
|
69445
|
-
*
|
|
69446
|
-
* @returns Object containing transactions array, action index, and swap quote
|
|
69447
|
-
*
|
|
69448
|
-
* @throws {TransactionBuildingError} If swap exceeds transaction size limits
|
|
69449
|
-
* @throws {TransactionBuildingError} If Kamino reserve not found
|
|
69450
|
-
*
|
|
69451
|
-
* @see {@link makeSwapCollateralTx} for detailed implementation
|
|
69452
|
-
*/
|
|
69453
|
-
async makeSwapCollateralTx(params) {
|
|
69454
|
-
return makeSwapCollateralTx({
|
|
69455
|
-
...params,
|
|
69456
|
-
marginfiAccount: this,
|
|
69457
|
-
overrideInferAccounts: {
|
|
69458
|
-
authority: this.authority,
|
|
69459
|
-
group: this.group,
|
|
69460
|
-
...params.overrideInferAccounts
|
|
69461
|
-
}
|
|
68045
|
+
/**
|
|
68046
|
+
* Creates a transaction to swap one collateral position to another using a flash loan.
|
|
68047
|
+
*
|
|
68048
|
+
* A swap collateral transaction:
|
|
68049
|
+
* 1. Withdraws existing collateral via flash loan
|
|
68050
|
+
* 2. Swaps collateral to new asset (via Jupiter)
|
|
68051
|
+
* 3. Deposits swapped assets as new collateral
|
|
68052
|
+
*
|
|
68053
|
+
* This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
|
|
68054
|
+
* withdrawing and affecting their health during the swap.
|
|
68055
|
+
*
|
|
68056
|
+
* @param params - Swap collateral transaction parameters
|
|
68057
|
+
* @param params.connection - Solana connection instance
|
|
68058
|
+
* @param params.oraclePrices - Map of current oracle prices
|
|
68059
|
+
* @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
|
|
68060
|
+
* @param params.depositOpts - Deposit configuration (bank, tokenProgram)
|
|
68061
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
68062
|
+
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
68063
|
+
* @param params.overrideInferAccounts - Optional account overrides
|
|
68064
|
+
* @param params.additionalIxs - Additional instructions to include
|
|
68065
|
+
* @param params.crossbarUrl - Crossbar URL for oracle updates
|
|
68066
|
+
*
|
|
68067
|
+
* @returns Object containing transactions array, action index, and swap quote
|
|
68068
|
+
*
|
|
68069
|
+
* @throws {TransactionBuildingError} If swap exceeds transaction size limits
|
|
68070
|
+
* @throws {TransactionBuildingError} If Kamino reserve not found
|
|
68071
|
+
*
|
|
68072
|
+
* @see {@link makeSwapCollateralTx} for detailed implementation
|
|
68073
|
+
*/
|
|
68074
|
+
async makeSwapCollateralTx(params) {
|
|
68075
|
+
return makeSwapCollateralTx({
|
|
68076
|
+
...params,
|
|
68077
|
+
marginfiAccount: this,
|
|
68078
|
+
overrideInferAccounts: {
|
|
68079
|
+
authority: this.authority,
|
|
68080
|
+
group: this.group,
|
|
68081
|
+
...params.overrideInferAccounts
|
|
68082
|
+
}
|
|
68083
|
+
});
|
|
68084
|
+
}
|
|
68085
|
+
/**
|
|
68086
|
+
* Creates a transaction to roll a matured Exponent PT collateral position into its
|
|
68087
|
+
* next-maturity PT, in one flash-loan-wrapped bundle
|
|
68088
|
+
* (withdraw PT_old → `wrapper_merge` to base → swap-engine buy PT_new → deposit).
|
|
68089
|
+
* See {@link makeRollPtTx}.
|
|
68090
|
+
*
|
|
68091
|
+
* @param params - Roll-PT parameters (`withdrawOpts`/`depositOpts`/`swapOpts`/`rollOpts`).
|
|
68092
|
+
*/
|
|
68093
|
+
async makeRollPtTx(params) {
|
|
68094
|
+
return makeRollPtTx({
|
|
68095
|
+
...params,
|
|
68096
|
+
marginfiAccount: this,
|
|
68097
|
+
overrideInferAccounts: {
|
|
68098
|
+
authority: this.authority,
|
|
68099
|
+
group: this.group,
|
|
68100
|
+
...params.overrideInferAccounts
|
|
68101
|
+
}
|
|
68102
|
+
});
|
|
68103
|
+
}
|
|
68104
|
+
/**
|
|
68105
|
+
* Creates a transaction to swap one debt position to another using a flash loan.
|
|
68106
|
+
*
|
|
68107
|
+
* A swap debt transaction:
|
|
68108
|
+
* 1. Borrows new asset via flash loan (new debt)
|
|
68109
|
+
* 2. Swaps new asset to old debt asset (via Jupiter)
|
|
68110
|
+
* 3. Repays old debt with swapped assets
|
|
68111
|
+
*
|
|
68112
|
+
* This allows users to change their debt type (e.g., USDC debt -> SOL debt) without
|
|
68113
|
+
* repaying and affecting their health during the swap.
|
|
68114
|
+
*
|
|
68115
|
+
* @param params - Swap debt transaction parameters
|
|
68116
|
+
* @param params.connection - Solana connection instance
|
|
68117
|
+
* @param params.oraclePrices - Map of current oracle prices
|
|
68118
|
+
* @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
|
|
68119
|
+
* @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
|
|
68120
|
+
* @param params.swapOpts - Swap configuration (venue, slippage, fees)
|
|
68121
|
+
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
68122
|
+
* @param params.overrideInferAccounts - Optional account overrides
|
|
68123
|
+
* @param params.additionalIxs - Additional instructions to include
|
|
68124
|
+
* @param params.crossbarUrl - Crossbar URL for oracle updates
|
|
68125
|
+
*
|
|
68126
|
+
* @returns Object containing transactions array, action index, and swap quote
|
|
68127
|
+
*
|
|
68128
|
+
* @throws {TransactionBuildingError} If swap exceeds transaction size limits
|
|
68129
|
+
*
|
|
68130
|
+
* @see {@link makeSwapDebtTx} for detailed implementation
|
|
68131
|
+
*/
|
|
68132
|
+
async makeSwapDebtTx(params) {
|
|
68133
|
+
return makeSwapDebtTx({
|
|
68134
|
+
...params,
|
|
68135
|
+
marginfiAccount: this,
|
|
68136
|
+
overrideInferAccounts: {
|
|
68137
|
+
authority: this.authority,
|
|
68138
|
+
group: this.group,
|
|
68139
|
+
...params.overrideInferAccounts
|
|
68140
|
+
}
|
|
68141
|
+
});
|
|
68142
|
+
}
|
|
68143
|
+
/**
|
|
68144
|
+
* Creates a deposit transaction.
|
|
68145
|
+
*
|
|
68146
|
+
* @param params - Parameters for the deposit transaction
|
|
68147
|
+
* @returns Promise resolving to an ExtendedTransaction
|
|
68148
|
+
*
|
|
68149
|
+
* @see {@link makeDepositTx} for detailed implementation
|
|
68150
|
+
*/
|
|
68151
|
+
async makeDepositTx(params) {
|
|
68152
|
+
return makeDepositTx({
|
|
68153
|
+
...params,
|
|
68154
|
+
accountAddress: this.address,
|
|
68155
|
+
authority: this.authority,
|
|
68156
|
+
group: this.group
|
|
68157
|
+
});
|
|
68158
|
+
}
|
|
68159
|
+
/**
|
|
68160
|
+
* Creates a Drift deposit transaction.
|
|
68161
|
+
*
|
|
68162
|
+
* @param params - Parameters for the Drift deposit transaction
|
|
68163
|
+
* @returns Promise resolving to an ExtendedV0Transaction
|
|
68164
|
+
*
|
|
68165
|
+
* @see {@link makeDriftDepositTx} for detailed implementation
|
|
68166
|
+
*/
|
|
68167
|
+
async makeDriftDepositTx(params) {
|
|
68168
|
+
return makeDriftDepositTx({
|
|
68169
|
+
...params,
|
|
68170
|
+
accountAddress: this.address,
|
|
68171
|
+
authority: this.authority,
|
|
68172
|
+
group: this.group
|
|
68173
|
+
});
|
|
68174
|
+
}
|
|
68175
|
+
/**
|
|
68176
|
+
* Creates a Kamino deposit transaction.
|
|
68177
|
+
*
|
|
68178
|
+
* @param params - Parameters for the Kamino deposit transaction
|
|
68179
|
+
* @returns Promise resolving to an ExtendedV0Transaction
|
|
68180
|
+
*
|
|
68181
|
+
* @see {@link makeKaminoDepositTx} for detailed implementation
|
|
68182
|
+
*/
|
|
68183
|
+
async makeKaminoDepositTx(params) {
|
|
68184
|
+
return makeKaminoDepositTx({
|
|
68185
|
+
...params,
|
|
68186
|
+
accountAddress: this.address,
|
|
68187
|
+
authority: this.authority,
|
|
68188
|
+
group: this.group
|
|
68189
|
+
});
|
|
68190
|
+
}
|
|
68191
|
+
/**
|
|
68192
|
+
* Creates a borrow transaction.
|
|
68193
|
+
*
|
|
68194
|
+
* @param params - Parameters for the borrow transaction
|
|
68195
|
+
* @returns Promise resolving to a TransactionBuilderResult
|
|
68196
|
+
*
|
|
68197
|
+
* @see {@link makeBorrowTx} for detailed implementation
|
|
68198
|
+
*/
|
|
68199
|
+
async makeBorrowTx(params) {
|
|
68200
|
+
return makeBorrowTx({
|
|
68201
|
+
...params,
|
|
68202
|
+
marginfiAccount: this,
|
|
68203
|
+
opts: {
|
|
68204
|
+
...params.opts,
|
|
68205
|
+
overrideInferAccounts: {
|
|
68206
|
+
authority: this.authority,
|
|
68207
|
+
...params.opts?.overrideInferAccounts
|
|
68208
|
+
}
|
|
68209
|
+
}
|
|
68210
|
+
});
|
|
68211
|
+
}
|
|
68212
|
+
/**
|
|
68213
|
+
* Creates a repay transaction.
|
|
68214
|
+
*
|
|
68215
|
+
* @param params - Parameters for the repay transaction
|
|
68216
|
+
* @returns Promise resolving to an ExtendedTransaction
|
|
68217
|
+
*
|
|
68218
|
+
* @see {@link makeRepayTx} for detailed implementation
|
|
68219
|
+
*/
|
|
68220
|
+
async makeRepayTx(params) {
|
|
68221
|
+
return makeRepayTx({
|
|
68222
|
+
...params,
|
|
68223
|
+
accountAddress: this.address,
|
|
68224
|
+
authority: this.authority
|
|
68225
|
+
});
|
|
68226
|
+
}
|
|
68227
|
+
/**
|
|
68228
|
+
* Creates a withdraw transaction.
|
|
68229
|
+
*
|
|
68230
|
+
* @param params - Parameters for the withdraw transaction
|
|
68231
|
+
* @returns Promise resolving to a TransactionBuilderResult
|
|
68232
|
+
*
|
|
68233
|
+
* @see {@link makeWithdrawTx} for detailed implementation
|
|
68234
|
+
*/
|
|
68235
|
+
async makeWithdrawTx(params) {
|
|
68236
|
+
return makeWithdrawTx({
|
|
68237
|
+
...params,
|
|
68238
|
+
marginfiAccount: this,
|
|
68239
|
+
opts: {
|
|
68240
|
+
...params.opts,
|
|
68241
|
+
overrideInferAccounts: {
|
|
68242
|
+
authority: this.authority,
|
|
68243
|
+
group: this.group,
|
|
68244
|
+
...params.opts?.overrideInferAccounts
|
|
68245
|
+
}
|
|
68246
|
+
}
|
|
68247
|
+
});
|
|
68248
|
+
}
|
|
68249
|
+
/**
|
|
68250
|
+
* Creates a Drift withdraw transaction.
|
|
68251
|
+
*
|
|
68252
|
+
* @param params - Parameters for the Drift withdraw transaction
|
|
68253
|
+
* @returns Promise resolving to an ExtendedV0Transaction
|
|
68254
|
+
*
|
|
68255
|
+
* @see {@link makeDriftWithdrawTx} for detailed implementation
|
|
68256
|
+
*/
|
|
68257
|
+
async makeDriftWithdrawTx(params) {
|
|
68258
|
+
return makeDriftWithdrawTx({
|
|
68259
|
+
...params,
|
|
68260
|
+
marginfiAccount: this,
|
|
68261
|
+
opts: {
|
|
68262
|
+
...params.opts,
|
|
68263
|
+
overrideInferAccounts: {
|
|
68264
|
+
authority: this.authority,
|
|
68265
|
+
group: this.group,
|
|
68266
|
+
...params.opts?.overrideInferAccounts
|
|
68267
|
+
}
|
|
68268
|
+
}
|
|
68269
|
+
});
|
|
68270
|
+
}
|
|
68271
|
+
/**
|
|
68272
|
+
* Creates a Kamino withdraw transaction.
|
|
68273
|
+
*
|
|
68274
|
+
* @param params - Parameters for the Kamino withdraw transaction
|
|
68275
|
+
* @returns Promise resolving to a TransactionBuilderResult
|
|
68276
|
+
*
|
|
68277
|
+
* @see {@link makeKaminoWithdrawTx} for detailed implementation
|
|
68278
|
+
*/
|
|
68279
|
+
async makeKaminoWithdrawTx(params) {
|
|
68280
|
+
return makeKaminoWithdrawTx({
|
|
68281
|
+
...params,
|
|
68282
|
+
marginfiAccount: this,
|
|
68283
|
+
opts: {
|
|
68284
|
+
...params.opts,
|
|
68285
|
+
overrideInferAccounts: {
|
|
68286
|
+
authority: this.authority,
|
|
68287
|
+
group: this.group,
|
|
68288
|
+
...params.opts?.overrideInferAccounts
|
|
68289
|
+
}
|
|
68290
|
+
}
|
|
68291
|
+
});
|
|
68292
|
+
}
|
|
68293
|
+
/**
|
|
68294
|
+
* Creates a flash loan transaction.
|
|
68295
|
+
*
|
|
68296
|
+
* @param params - Parameters for the flash loan transaction
|
|
68297
|
+
* @returns Promise resolving to flash loan transaction details
|
|
68298
|
+
*
|
|
68299
|
+
* @see {@link makeFlashLoanTx} for detailed implementation
|
|
68300
|
+
*/
|
|
68301
|
+
async makeFlashLoanTx(params) {
|
|
68302
|
+
return makeFlashLoanTx({
|
|
68303
|
+
...params,
|
|
68304
|
+
marginfiAccount: this
|
|
68305
|
+
});
|
|
68306
|
+
}
|
|
68307
|
+
};
|
|
68308
|
+
|
|
68309
|
+
// src/services/account/actions/bridge-swap.ts
|
|
68310
|
+
var MAX_BRIDGED_BUNDLE_TXS = 5;
|
|
68311
|
+
function classifyTxs(txs) {
|
|
68312
|
+
const out = { setups: [], cranks: [], flashloans: [] };
|
|
68313
|
+
for (const tx of txs) {
|
|
68314
|
+
if (tx.type === "CREATE_ATA" /* CREATE_ATA */) out.setups.push(tx);
|
|
68315
|
+
else if (tx.type === "CRANK" /* CRANK */) out.cranks.push(tx);
|
|
68316
|
+
else out.flashloans.push(tx);
|
|
68317
|
+
}
|
|
68318
|
+
return out;
|
|
68319
|
+
}
|
|
68320
|
+
function ixIdentity(ix) {
|
|
68321
|
+
const keys = ix.keys.map((k) => k.pubkey.toBase58()).join(",");
|
|
68322
|
+
return `${ix.programId.toBase58()}|${keys}|${Buffer.from(ix.data).toString("base64")}`;
|
|
68323
|
+
}
|
|
68324
|
+
function mergeSetupTxs(txs, payer, blockhash) {
|
|
68325
|
+
if (txs.length === 0) return null;
|
|
68326
|
+
if (txs.length === 1) return txs[0];
|
|
68327
|
+
const lutMap = /* @__PURE__ */ new Map();
|
|
68328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68329
|
+
const ixs = [];
|
|
68330
|
+
for (const tx of txs) {
|
|
68331
|
+
const luts2 = tx.addressLookupTables ?? [];
|
|
68332
|
+
luts2.forEach((l) => lutMap.set(l.key.toBase58(), l));
|
|
68333
|
+
const msg = decompileV0Transaction(tx, luts2);
|
|
68334
|
+
for (const ix of msg.instructions) {
|
|
68335
|
+
const id = ixIdentity(ix);
|
|
68336
|
+
if (seen.has(id)) continue;
|
|
68337
|
+
seen.add(id);
|
|
68338
|
+
ixs.push(ix);
|
|
68339
|
+
}
|
|
68340
|
+
}
|
|
68341
|
+
const luts = [...lutMap.values()];
|
|
68342
|
+
const split = splitInstructionsToFitTransactions([], ixs, { blockhash, payerKey: payer, luts });
|
|
68343
|
+
if (split.length !== 1) return null;
|
|
68344
|
+
return addTransactionMetadata(split[0], {
|
|
68345
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
68346
|
+
addressLookupTables: luts
|
|
68347
|
+
});
|
|
68348
|
+
}
|
|
68349
|
+
function projectAccountAfterFirstLeg(account, firstLegFlashloanTxs, program, banksMap, multipliers) {
|
|
68350
|
+
const ixs = [];
|
|
68351
|
+
for (const tx of firstLegFlashloanTxs) {
|
|
68352
|
+
const luts = tx.addressLookupTables ?? [];
|
|
68353
|
+
ixs.push(...decompileV0Transaction(tx, luts).instructions);
|
|
68354
|
+
}
|
|
68355
|
+
const { projectedBalances } = computeProjectedActiveBalancesNoCpi({
|
|
68356
|
+
account,
|
|
68357
|
+
instructions: ixs,
|
|
68358
|
+
program,
|
|
68359
|
+
banksMap,
|
|
68360
|
+
assetShareValueMultiplierByBank: multipliers
|
|
68361
|
+
});
|
|
68362
|
+
return new MarginfiAccount(
|
|
68363
|
+
account.address,
|
|
68364
|
+
account.group,
|
|
68365
|
+
account.authority,
|
|
68366
|
+
projectedBalances.map((b) => Balance.fromBalanceType(b)),
|
|
68367
|
+
account.accountFlags,
|
|
68368
|
+
account.emissionsDestinationAccount,
|
|
68369
|
+
account.healthCache
|
|
68370
|
+
);
|
|
68371
|
+
}
|
|
68372
|
+
function composeBundle(firstLegTxs, secondLegTxs, payer, blockhash, maxBundleTxs) {
|
|
68373
|
+
const c1 = classifyTxs(firstLegTxs);
|
|
68374
|
+
const c2 = classifyTxs(secondLegTxs);
|
|
68375
|
+
const mergedSetup = mergeSetupTxs([...c1.setups, ...c2.setups], payer, blockhash);
|
|
68376
|
+
if ([...c1.setups, ...c2.setups].length > 0 && !mergedSetup) return null;
|
|
68377
|
+
const result = [
|
|
68378
|
+
...mergedSetup ? [mergedSetup] : [],
|
|
68379
|
+
...c1.cranks,
|
|
68380
|
+
...c1.flashloans,
|
|
68381
|
+
// firstLegFL(s)
|
|
68382
|
+
...c2.cranks,
|
|
68383
|
+
...c2.flashloans
|
|
68384
|
+
// secondLegFL(s)
|
|
68385
|
+
];
|
|
68386
|
+
if (result.length > maxBundleTxs) return null;
|
|
68387
|
+
return result;
|
|
68388
|
+
}
|
|
68389
|
+
function compoundQuoteRisk(firstLeg, secondLeg) {
|
|
68390
|
+
const compound = (a, b) => {
|
|
68391
|
+
if (a == null && b == null) return void 0;
|
|
68392
|
+
const x = Number(a ?? 0);
|
|
68393
|
+
const y = Number(b ?? 0);
|
|
68394
|
+
return String(1 - (1 - x) * (1 - y));
|
|
68395
|
+
};
|
|
68396
|
+
return {
|
|
68397
|
+
slippageBps: Math.round(
|
|
68398
|
+
(1 - (1 - firstLeg.slippageBps / 1e4) * (1 - secondLeg.slippageBps / 1e4)) * 1e4
|
|
68399
|
+
),
|
|
68400
|
+
priceImpactPct: compound(firstLeg.priceImpactPct, secondLeg.priceImpactPct)
|
|
68401
|
+
};
|
|
68402
|
+
}
|
|
68403
|
+
function mergeBridgeQuotes(firstLeg, secondLeg) {
|
|
68404
|
+
return {
|
|
68405
|
+
inAmount: firstLeg.inAmount,
|
|
68406
|
+
outAmount: secondLeg.outAmount,
|
|
68407
|
+
otherAmountThreshold: secondLeg.otherAmountThreshold,
|
|
68408
|
+
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
68409
|
+
provider: firstLeg.provider
|
|
68410
|
+
};
|
|
68411
|
+
}
|
|
68412
|
+
function mergeBridgeQuotesDebt(firstLeg, secondLeg) {
|
|
68413
|
+
return {
|
|
68414
|
+
inAmount: firstLeg.outAmount,
|
|
68415
|
+
outAmount: secondLeg.inAmount,
|
|
68416
|
+
otherAmountThreshold: secondLeg.inAmount,
|
|
68417
|
+
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
68418
|
+
provider: firstLeg.provider
|
|
68419
|
+
};
|
|
68420
|
+
}
|
|
68421
|
+
function mergeBridgeQuotesLoop(firstLeg, secondLeg) {
|
|
68422
|
+
return {
|
|
68423
|
+
inAmount: secondLeg.inAmount,
|
|
68424
|
+
outAmount: firstLeg.outAmount,
|
|
68425
|
+
otherAmountThreshold: firstLeg.otherAmountThreshold,
|
|
68426
|
+
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
68427
|
+
provider: firstLeg.provider
|
|
68428
|
+
};
|
|
68429
|
+
}
|
|
68430
|
+
function blockhashOf(leg) {
|
|
68431
|
+
const tx = leg.transactions[0];
|
|
68432
|
+
return tx ? tx.message.recentBlockhash : PublicKey.default.toBase58();
|
|
68433
|
+
}
|
|
68434
|
+
async function composeBridgedSwap(params) {
|
|
68435
|
+
const {
|
|
68436
|
+
firstLeg,
|
|
68437
|
+
buildSecondLeg,
|
|
68438
|
+
marginfiAccount,
|
|
68439
|
+
program,
|
|
68440
|
+
banksMap,
|
|
68441
|
+
assetShareValueMultiplierByBank,
|
|
68442
|
+
feePayer,
|
|
68443
|
+
maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
|
|
68444
|
+
} = params;
|
|
68445
|
+
if (!firstLeg.quoteResponse) return null;
|
|
68446
|
+
const projectedAccount = projectAccountAfterFirstLeg(
|
|
68447
|
+
marginfiAccount,
|
|
68448
|
+
classifyTxs(firstLeg.transactions).flashloans,
|
|
68449
|
+
program,
|
|
68450
|
+
banksMap,
|
|
68451
|
+
assetShareValueMultiplierByBank
|
|
68452
|
+
);
|
|
68453
|
+
const secondLeg = await buildSecondLeg(projectedAccount);
|
|
68454
|
+
if (!secondLeg.quoteResponse) return null;
|
|
68455
|
+
const transactions = composeBundle(
|
|
68456
|
+
firstLeg.transactions,
|
|
68457
|
+
secondLeg.transactions,
|
|
68458
|
+
feePayer,
|
|
68459
|
+
blockhashOf(firstLeg),
|
|
68460
|
+
maxBundleTxs
|
|
68461
|
+
);
|
|
68462
|
+
if (!transactions) return null;
|
|
68463
|
+
return { transactions, firstLegQuote: firstLeg.quoteResponse, secondLegQuote: secondLeg.quoteResponse };
|
|
68464
|
+
}
|
|
68465
|
+
async function makeSwapDebtTx(params) {
|
|
68466
|
+
const {
|
|
68467
|
+
program,
|
|
68468
|
+
marginfiAccount,
|
|
68469
|
+
connection,
|
|
68470
|
+
bankMap,
|
|
68471
|
+
oraclePrices,
|
|
68472
|
+
repayOpts,
|
|
68473
|
+
borrowOpts,
|
|
68474
|
+
bankMetadataMap,
|
|
68475
|
+
assetShareValueMultiplierByBank,
|
|
68476
|
+
addressLookupTableAccounts,
|
|
68477
|
+
crossbarUrl,
|
|
68478
|
+
additionalIxs = []
|
|
68479
|
+
} = params;
|
|
68480
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
68481
|
+
const setupIxs = await makeSetupIx({
|
|
68482
|
+
connection,
|
|
68483
|
+
authority: marginfiAccount.authority,
|
|
68484
|
+
tokens: [
|
|
68485
|
+
{ mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
|
|
68486
|
+
{ mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
|
|
68487
|
+
]
|
|
68488
|
+
});
|
|
68489
|
+
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
68490
|
+
marginfiAccount,
|
|
68491
|
+
bankMap,
|
|
68492
|
+
[],
|
|
68493
|
+
bankMetadataMap,
|
|
68494
|
+
[repayOpts.repayBank.address, borrowOpts.borrowBank.address]
|
|
68495
|
+
);
|
|
68496
|
+
const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
|
|
68497
|
+
...params,
|
|
68498
|
+
blockhash
|
|
68499
|
+
});
|
|
68500
|
+
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
68501
|
+
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
68502
|
+
return false;
|
|
68503
|
+
}
|
|
68504
|
+
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
68505
|
+
const mintKey = ix.keys[3]?.pubkey;
|
|
68506
|
+
if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
68507
|
+
return false;
|
|
68508
|
+
}
|
|
68509
|
+
}
|
|
68510
|
+
return true;
|
|
68511
|
+
});
|
|
68512
|
+
setupIxs.push(...jupiterSetupInstructions);
|
|
68513
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
68514
|
+
marginfiAccount,
|
|
68515
|
+
bankMap,
|
|
68516
|
+
oraclePrices,
|
|
68517
|
+
assetShareValueMultiplierByBank,
|
|
68518
|
+
instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
|
|
68519
|
+
program,
|
|
68520
|
+
connection,
|
|
68521
|
+
crossbarUrl
|
|
68522
|
+
});
|
|
68523
|
+
let additionalTxs = [];
|
|
68524
|
+
if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
|
|
68525
|
+
const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
|
|
68526
|
+
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
68527
|
+
blockhash,
|
|
68528
|
+
payerKey: marginfiAccount.authority,
|
|
68529
|
+
luts: addressLookupTableAccounts ?? []
|
|
68530
|
+
});
|
|
68531
|
+
additionalTxs.push(
|
|
68532
|
+
...txs.map(
|
|
68533
|
+
(tx) => addTransactionMetadata(tx, {
|
|
68534
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
68535
|
+
addressLookupTables: addressLookupTableAccounts
|
|
68536
|
+
})
|
|
68537
|
+
)
|
|
68538
|
+
);
|
|
68539
|
+
}
|
|
68540
|
+
if (updateFeedIxs.length > 0) {
|
|
68541
|
+
const message = new TransactionMessage({
|
|
68542
|
+
payerKey: marginfiAccount.authority,
|
|
68543
|
+
recentBlockhash: blockhash,
|
|
68544
|
+
instructions: updateFeedIxs
|
|
68545
|
+
}).compileToV0Message(feedLuts);
|
|
68546
|
+
additionalTxs.push(
|
|
68547
|
+
addTransactionMetadata(new VersionedTransaction(message), {
|
|
68548
|
+
addressLookupTables: feedLuts,
|
|
68549
|
+
type: "CRANK" /* CRANK */
|
|
68550
|
+
})
|
|
68551
|
+
);
|
|
68552
|
+
}
|
|
68553
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
68554
|
+
return {
|
|
68555
|
+
transactions,
|
|
68556
|
+
actionTxIndex: transactions.length - 1,
|
|
68557
|
+
quoteResponse: swapQuote
|
|
68558
|
+
};
|
|
68559
|
+
}
|
|
68560
|
+
async function buildSwapDebtFlashloanTx({
|
|
68561
|
+
program,
|
|
68562
|
+
marginfiAccount,
|
|
68563
|
+
bankMap,
|
|
68564
|
+
repayOpts,
|
|
68565
|
+
borrowOpts,
|
|
68566
|
+
swapOpts,
|
|
68567
|
+
bankMetadataMap,
|
|
68568
|
+
addressLookupTableAccounts,
|
|
68569
|
+
connection,
|
|
68570
|
+
overrideInferAccounts,
|
|
68571
|
+
blockhash,
|
|
68572
|
+
swapEngineRunner
|
|
68573
|
+
}) {
|
|
68574
|
+
const {
|
|
68575
|
+
repayBank,
|
|
68576
|
+
tokenProgram: repayTokenProgram,
|
|
68577
|
+
totalPositionAmount,
|
|
68578
|
+
repayAmount
|
|
68579
|
+
} = repayOpts;
|
|
68580
|
+
const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
|
|
68581
|
+
if (repayAmount !== void 0 && repayAmount <= 0) {
|
|
68582
|
+
throw new Error("repayAmount must be greater than 0");
|
|
68583
|
+
}
|
|
68584
|
+
const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
|
|
68585
|
+
const cuRequestIxs = [
|
|
68586
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
68587
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
68588
|
+
];
|
|
68589
|
+
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
68590
|
+
repayBank.mint,
|
|
68591
|
+
marginfiAccount.authority,
|
|
68592
|
+
true,
|
|
68593
|
+
repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
68594
|
+
);
|
|
68595
|
+
const estimatedBorrowAmount = computeBorrowEstimateForRepay({
|
|
68596
|
+
repayTargetUi: actualRepayAmount,
|
|
68597
|
+
repayMarketPrice: repayOpts.marketPrice,
|
|
68598
|
+
borrowMarketPrice: borrowOpts.marketPrice,
|
|
68599
|
+
slippageBps: swapOpts.swapConfig?.slippageBps,
|
|
68600
|
+
isRepayAll: actualRepayAmount >= totalPositionAmount
|
|
68601
|
+
});
|
|
68602
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
68603
|
+
program,
|
|
68604
|
+
marginfiAccount,
|
|
68605
|
+
bankMap,
|
|
68606
|
+
bankMetadataMap,
|
|
68607
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
68608
|
+
primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
|
|
68609
|
+
secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
|
|
68610
|
+
overrideInferAccounts
|
|
68611
|
+
});
|
|
68612
|
+
const footprintBorrowIxs = await makeBorrowIx3({
|
|
68613
|
+
program,
|
|
68614
|
+
bank: borrowBank,
|
|
68615
|
+
bankMap,
|
|
68616
|
+
tokenProgram: borrowTokenProgram,
|
|
68617
|
+
amount: estimatedBorrowAmount,
|
|
68618
|
+
marginfiAccount,
|
|
68619
|
+
authority: marginfiAccount.authority,
|
|
68620
|
+
isSync: true,
|
|
68621
|
+
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68622
|
+
});
|
|
68623
|
+
const footprintRepayIxs = await makeRepayIx3({
|
|
68624
|
+
program,
|
|
68625
|
+
bank: repayBank,
|
|
68626
|
+
tokenProgram: repayTokenProgram,
|
|
68627
|
+
amount: actualRepayAmount,
|
|
68628
|
+
accountAddress: marginfiAccount.address,
|
|
68629
|
+
authority: marginfiAccount.authority,
|
|
68630
|
+
isSync: true,
|
|
68631
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
68632
|
+
});
|
|
68633
|
+
const runEngine = swapEngineRunner ?? runSwapEngine;
|
|
68634
|
+
const engineResult = await runEngine({
|
|
68635
|
+
inputMint: borrowBank.mint.toBase58(),
|
|
68636
|
+
outputMint: repayBank.mint.toBase58(),
|
|
68637
|
+
amountNative: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
|
|
68638
|
+
inputDecimals: borrowBank.mintDecimals,
|
|
68639
|
+
outputDecimals: repayBank.mintDecimals,
|
|
68640
|
+
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
68641
|
+
taker: marginfiAccount.authority,
|
|
68642
|
+
destinationTokenAccount,
|
|
68643
|
+
connection,
|
|
68644
|
+
footprint: {
|
|
68645
|
+
instructions: [
|
|
68646
|
+
...cuRequestIxs,
|
|
68647
|
+
...footprintBorrowIxs.instructions,
|
|
68648
|
+
...footprintRepayIxs.instructions
|
|
68649
|
+
],
|
|
68650
|
+
luts: addressLookupTableAccounts ?? [],
|
|
68651
|
+
payer: marginfiAccount.authority,
|
|
68652
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
68653
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
68654
|
+
},
|
|
68655
|
+
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
68656
|
+
});
|
|
68657
|
+
const quoteResponse = engineResult.quoteResponse;
|
|
68658
|
+
const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
|
|
68659
|
+
const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
|
|
68660
|
+
const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
|
|
68661
|
+
const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
|
|
68662
|
+
const borrowIxs = await makeBorrowIx3({
|
|
68663
|
+
program,
|
|
68664
|
+
bank: borrowBank,
|
|
68665
|
+
bankMap,
|
|
68666
|
+
tokenProgram: borrowTokenProgram,
|
|
68667
|
+
amount: borrowAmount,
|
|
68668
|
+
marginfiAccount,
|
|
68669
|
+
authority: marginfiAccount.authority,
|
|
68670
|
+
isSync: true,
|
|
68671
|
+
opts: {
|
|
68672
|
+
createAtas: false,
|
|
68673
|
+
wrapAndUnwrapSol: false,
|
|
68674
|
+
overrideInferAccounts
|
|
68675
|
+
}
|
|
68676
|
+
});
|
|
68677
|
+
const repayIxs = await makeRepayIx3({
|
|
68678
|
+
program,
|
|
68679
|
+
bank: repayBank,
|
|
68680
|
+
tokenProgram: repayTokenProgram,
|
|
68681
|
+
amount: amountToRepay,
|
|
68682
|
+
accountAddress: marginfiAccount.address,
|
|
68683
|
+
authority: marginfiAccount.authority,
|
|
68684
|
+
repayAll: isWholePosition(
|
|
68685
|
+
{
|
|
68686
|
+
amount: totalPositionAmount,
|
|
68687
|
+
isLending: false
|
|
68688
|
+
},
|
|
68689
|
+
amountToRepay,
|
|
68690
|
+
repayBank.mintDecimals
|
|
68691
|
+
),
|
|
68692
|
+
isSync: true,
|
|
68693
|
+
opts: {
|
|
68694
|
+
wrapAndUnwrapSol: false,
|
|
68695
|
+
overrideInferAccounts
|
|
68696
|
+
}
|
|
68697
|
+
});
|
|
68698
|
+
const luts = [...addressLookupTableAccounts ?? [], ...engineResult.swapLuts];
|
|
68699
|
+
const allNonFlIxs = [
|
|
68700
|
+
...cuRequestIxs,
|
|
68701
|
+
...borrowIxs.instructions,
|
|
68702
|
+
...engineResult.swapInstructions,
|
|
68703
|
+
...repayIxs.instructions
|
|
68704
|
+
];
|
|
68705
|
+
compileFlashloanPrecheck({
|
|
68706
|
+
allIxs: allNonFlIxs,
|
|
68707
|
+
payer: marginfiAccount.authority,
|
|
68708
|
+
luts,
|
|
68709
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
68710
|
+
swapIxCount: engineResult.swapInstructions.length,
|
|
68711
|
+
swapLutCount: engineResult.swapLuts.length
|
|
68712
|
+
});
|
|
68713
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
68714
|
+
program,
|
|
68715
|
+
marginfiAccount,
|
|
68716
|
+
bankMap,
|
|
68717
|
+
addressLookupTableAccounts: luts,
|
|
68718
|
+
blockhash,
|
|
68719
|
+
ixs: allNonFlIxs,
|
|
68720
|
+
isSync: true
|
|
68721
|
+
});
|
|
68722
|
+
const txSize = getTxSize(flashloanTx);
|
|
68723
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
68724
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
68725
|
+
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
68726
|
+
txSize,
|
|
68727
|
+
totalKeys,
|
|
68728
|
+
swapOpts.swapConfig?.provider
|
|
68729
|
+
);
|
|
68730
|
+
}
|
|
68731
|
+
return {
|
|
68732
|
+
flashloanTx,
|
|
68733
|
+
setupInstructions: engineResult.setupInstructions,
|
|
68734
|
+
swapQuote: quoteResponse,
|
|
68735
|
+
borrowIxs,
|
|
68736
|
+
repayIxs
|
|
68737
|
+
};
|
|
68738
|
+
}
|
|
68739
|
+
async function makeBridgedSwapDebtTx(params) {
|
|
68740
|
+
const { bridgeOpts, ...directParams } = params;
|
|
68741
|
+
try {
|
|
68742
|
+
return await makeSwapDebtTx(directParams);
|
|
68743
|
+
} catch (directError) {
|
|
68744
|
+
if (!isDecomposableSwapError(directError)) throw directError;
|
|
68745
|
+
const bridged = await tryBridgedDebtSwap(directParams, bridgeOpts);
|
|
68746
|
+
if (bridged) return bridged;
|
|
68747
|
+
throw directError;
|
|
68748
|
+
}
|
|
68749
|
+
}
|
|
68750
|
+
async function tryBridgedDebtSwap(params, bridgeOpts) {
|
|
68751
|
+
const sourceBank = params.repayOpts.repayBank;
|
|
68752
|
+
const destinationBank = params.borrowOpts.borrowBank;
|
|
68753
|
+
const repayAmount = params.repayOpts.repayAmount ?? params.repayOpts.totalPositionAmount;
|
|
68754
|
+
const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
|
|
68755
|
+
const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
|
|
68756
|
+
sourceMint: sourceBank.mint,
|
|
68757
|
+
destinationMint: destinationBank.mint,
|
|
68758
|
+
bankMap: params.bankMap,
|
|
68759
|
+
marginfiAccount: params.marginfiAccount,
|
|
68760
|
+
bridgeTokenSide: "borrow",
|
|
68761
|
+
bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
|
|
68762
|
+
});
|
|
68763
|
+
const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
|
|
68764
|
+
return tryBridgeCandidates({
|
|
68765
|
+
usableBridgeBanks,
|
|
68766
|
+
conflictingBridgeBanks,
|
|
68767
|
+
bridgeTokenSide: "borrow",
|
|
68768
|
+
abortSignal: bridgeOpts?.abortSignal,
|
|
68769
|
+
buildBundleThroughBridge: async (bridgeBank) => {
|
|
68770
|
+
const bridgeTokenProgram = await resolveTokenProgramForMint(
|
|
68771
|
+
bridgeBank.mint,
|
|
68772
|
+
params.connection,
|
|
68773
|
+
tokenProgramCache
|
|
68774
|
+
);
|
|
68775
|
+
const firstLeg = await makeSwapDebtTx({
|
|
68776
|
+
...sharedBridgeLegContext(params),
|
|
68777
|
+
repayOpts: {
|
|
68778
|
+
totalPositionAmount: params.repayOpts.totalPositionAmount,
|
|
68779
|
+
repayAmount,
|
|
68780
|
+
repayBank: sourceBank,
|
|
68781
|
+
tokenProgram: params.repayOpts.tokenProgram,
|
|
68782
|
+
marketPrice: oraclePriceOf(sourceBank)
|
|
68783
|
+
},
|
|
68784
|
+
borrowOpts: {
|
|
68785
|
+
borrowBank: bridgeBank,
|
|
68786
|
+
tokenProgram: bridgeTokenProgram,
|
|
68787
|
+
marketPrice: oraclePriceOf(bridgeBank)
|
|
68788
|
+
}
|
|
68789
|
+
});
|
|
68790
|
+
if (!firstLeg.quoteResponse) return null;
|
|
68791
|
+
const bridgeBorrowedUi = nativeToUi(firstLeg.quoteResponse.inAmount, bridgeBank.mintDecimals);
|
|
68792
|
+
if (bridgeBorrowedUi <= 0) return null;
|
|
68793
|
+
const result = await composeBridgedSwap({
|
|
68794
|
+
firstLeg,
|
|
68795
|
+
buildSecondLeg: (projectedAccount) => makeSwapDebtTx({
|
|
68796
|
+
...sharedBridgeLegContext(params),
|
|
68797
|
+
marginfiAccount: projectedAccount,
|
|
68798
|
+
repayOpts: {
|
|
68799
|
+
totalPositionAmount: bridgeBorrowedUi,
|
|
68800
|
+
repayAmount: bridgeBorrowedUi,
|
|
68801
|
+
repayBank: bridgeBank,
|
|
68802
|
+
tokenProgram: bridgeTokenProgram,
|
|
68803
|
+
marketPrice: oraclePriceOf(bridgeBank)
|
|
68804
|
+
},
|
|
68805
|
+
borrowOpts: {
|
|
68806
|
+
borrowBank: destinationBank,
|
|
68807
|
+
tokenProgram: params.borrowOpts.tokenProgram,
|
|
68808
|
+
marketPrice: oraclePriceOf(destinationBank)
|
|
68809
|
+
}
|
|
68810
|
+
}),
|
|
68811
|
+
marginfiAccount: params.marginfiAccount,
|
|
68812
|
+
program: params.program,
|
|
68813
|
+
banksMap: params.bankMap,
|
|
68814
|
+
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
68815
|
+
feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
|
|
68816
|
+
maxBundleTxs: bridgeOpts?.maxBundleTxs
|
|
68817
|
+
});
|
|
68818
|
+
if (!result) return null;
|
|
68819
|
+
return {
|
|
68820
|
+
transactions: result.transactions,
|
|
68821
|
+
actionTxIndex: result.transactions.length - 1,
|
|
68822
|
+
quoteResponse: mergeBridgeQuotesDebt(result.firstLegQuote, result.secondLegQuote),
|
|
68823
|
+
bridgeMint: bridgeBank.mint
|
|
68824
|
+
};
|
|
68825
|
+
}
|
|
68826
|
+
});
|
|
68827
|
+
}
|
|
68828
|
+
|
|
68829
|
+
// src/services/account/actions/loop.ts
|
|
68830
|
+
async function makeLoopTx(params) {
|
|
68831
|
+
const {
|
|
68832
|
+
program,
|
|
68833
|
+
marginfiAccount,
|
|
68834
|
+
bankMap,
|
|
68835
|
+
depositOpts,
|
|
68836
|
+
borrowOpts,
|
|
68837
|
+
bankMetadataMap,
|
|
68838
|
+
addressLookupTableAccounts,
|
|
68839
|
+
connection,
|
|
68840
|
+
oraclePrices,
|
|
68841
|
+
crossbarUrl,
|
|
68842
|
+
additionalIxs = []
|
|
68843
|
+
} = params;
|
|
68844
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
68845
|
+
const setupIxs = await makeSetupIx({
|
|
68846
|
+
connection,
|
|
68847
|
+
authority: marginfiAccount.authority,
|
|
68848
|
+
tokens: [
|
|
68849
|
+
{
|
|
68850
|
+
mint: borrowOpts.borrowBank.mint,
|
|
68851
|
+
tokenProgram: borrowOpts.tokenProgram
|
|
68852
|
+
},
|
|
68853
|
+
{
|
|
68854
|
+
mint: depositOpts.depositBank.mint,
|
|
68855
|
+
tokenProgram: depositOpts.tokenProgram
|
|
68856
|
+
}
|
|
68857
|
+
]
|
|
68858
|
+
});
|
|
68859
|
+
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
68860
|
+
params.marginfiAccount,
|
|
68861
|
+
params.bankMap,
|
|
68862
|
+
[depositOpts.depositBank.address],
|
|
68863
|
+
params.bankMetadataMap,
|
|
68864
|
+
[borrowOpts.borrowBank.address, depositOpts.depositBank.address]
|
|
68865
|
+
);
|
|
68866
|
+
const { flashloanTx, setupInstructions, swapQuote, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
|
|
68867
|
+
...params,
|
|
68868
|
+
blockhash
|
|
68869
|
+
});
|
|
68870
|
+
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
68871
|
+
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
68872
|
+
return false;
|
|
68873
|
+
}
|
|
68874
|
+
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
68875
|
+
const mintKey = ix.keys[3]?.pubkey;
|
|
68876
|
+
if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
68877
|
+
return false;
|
|
68878
|
+
}
|
|
68879
|
+
}
|
|
68880
|
+
return true;
|
|
68881
|
+
});
|
|
68882
|
+
setupIxs.push(...jupiterSetupInstructions);
|
|
68883
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
68884
|
+
marginfiAccount,
|
|
68885
|
+
bankMap,
|
|
68886
|
+
oraclePrices,
|
|
68887
|
+
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
68888
|
+
instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
|
|
68889
|
+
program,
|
|
68890
|
+
connection,
|
|
68891
|
+
crossbarUrl
|
|
68892
|
+
});
|
|
68893
|
+
let additionalTxs = [];
|
|
68894
|
+
if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
|
|
68895
|
+
setupIxs.push(
|
|
68896
|
+
...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
|
|
68897
|
+
);
|
|
68898
|
+
}
|
|
68899
|
+
if (setupIxs.length > 0 || additionalIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
|
|
68900
|
+
const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
|
|
68901
|
+
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
68902
|
+
blockhash,
|
|
68903
|
+
payerKey: marginfiAccount.authority,
|
|
68904
|
+
luts: addressLookupTableAccounts ?? []
|
|
68905
|
+
});
|
|
68906
|
+
additionalTxs.push(
|
|
68907
|
+
...txs.map(
|
|
68908
|
+
(tx) => addTransactionMetadata(tx, {
|
|
68909
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
68910
|
+
addressLookupTables: addressLookupTableAccounts
|
|
68911
|
+
})
|
|
68912
|
+
)
|
|
68913
|
+
);
|
|
68914
|
+
}
|
|
68915
|
+
if (updateFeedIxs.length > 0) {
|
|
68916
|
+
const message = new TransactionMessage({
|
|
68917
|
+
payerKey: marginfiAccount.authority,
|
|
68918
|
+
recentBlockhash: blockhash,
|
|
68919
|
+
instructions: updateFeedIxs
|
|
68920
|
+
}).compileToV0Message(feedLuts);
|
|
68921
|
+
additionalTxs.push(
|
|
68922
|
+
addTransactionMetadata(new VersionedTransaction(message), {
|
|
68923
|
+
addressLookupTables: feedLuts,
|
|
68924
|
+
type: "CRANK" /* CRANK */
|
|
68925
|
+
})
|
|
68926
|
+
);
|
|
68927
|
+
}
|
|
68928
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
68929
|
+
return {
|
|
68930
|
+
transactions,
|
|
68931
|
+
actionTxIndex: transactions.length - 1,
|
|
68932
|
+
quoteResponse: swapQuote
|
|
68933
|
+
};
|
|
68934
|
+
}
|
|
68935
|
+
async function buildLoopFlashloanTx(params) {
|
|
68936
|
+
const { depositOpts } = params;
|
|
68937
|
+
const { descriptor, swapNeeded, borrowIxs, depositIxs } = await buildLoopNonSwapIxs(params);
|
|
68938
|
+
if (!swapNeeded) {
|
|
68939
|
+
const flashloanTx2 = await finalizeLoopFlashloanTx({
|
|
68940
|
+
params,
|
|
68941
|
+
innerIxs: descriptor.innerIxs,
|
|
68942
|
+
luts: descriptor.luts,
|
|
68943
|
+
swapIxCount: 0,
|
|
68944
|
+
swapLutCount: 0,
|
|
68945
|
+
sizeConstraint: descriptor.sizeConstraint
|
|
69462
68946
|
});
|
|
68947
|
+
return {
|
|
68948
|
+
flashloanTx: flashloanTx2,
|
|
68949
|
+
setupInstructions: [],
|
|
68950
|
+
swapQuote: void 0,
|
|
68951
|
+
borrowIxs,
|
|
68952
|
+
depositIxs
|
|
68953
|
+
};
|
|
69463
68954
|
}
|
|
69464
|
-
|
|
69465
|
-
|
|
69466
|
-
|
|
69467
|
-
|
|
69468
|
-
|
|
69469
|
-
|
|
69470
|
-
|
|
69471
|
-
|
|
69472
|
-
|
|
69473
|
-
|
|
69474
|
-
|
|
69475
|
-
|
|
69476
|
-
|
|
69477
|
-
|
|
69478
|
-
|
|
69479
|
-
|
|
69480
|
-
|
|
68955
|
+
const engineResult = await runLoopSwapEngine(descriptor, params);
|
|
68956
|
+
const finalIxs = [...descriptor.innerIxs];
|
|
68957
|
+
finalIxs.splice(descriptor.swapSlotIndex, 0, ...engineResult.swapInstructions);
|
|
68958
|
+
const principalNative = depositOpts.loopMode === "DEPOSIT" ? uiToNative(depositOpts.inputDepositAmount, depositOpts.depositBank.mintDecimals) : new BN9(0);
|
|
68959
|
+
const finalDepositNative = engineResult.outputAmountNative.add(principalNative);
|
|
68960
|
+
const depositIxPosition = descriptor.depositIxIndex + engineResult.swapInstructions.length;
|
|
68961
|
+
patchDepositAmount(finalIxs[depositIxPosition], finalDepositNative);
|
|
68962
|
+
const luts = [...descriptor.luts, ...engineResult.swapLuts];
|
|
68963
|
+
const flashloanTx = await finalizeLoopFlashloanTx({
|
|
68964
|
+
params,
|
|
68965
|
+
innerIxs: finalIxs,
|
|
68966
|
+
luts,
|
|
68967
|
+
swapIxCount: engineResult.swapInstructions.length,
|
|
68968
|
+
swapLutCount: engineResult.swapLuts.length,
|
|
68969
|
+
sizeConstraint: descriptor.sizeConstraint
|
|
68970
|
+
});
|
|
68971
|
+
return {
|
|
68972
|
+
flashloanTx,
|
|
68973
|
+
setupInstructions: engineResult.setupInstructions,
|
|
68974
|
+
swapQuote: engineResult.quoteResponse,
|
|
68975
|
+
borrowIxs,
|
|
68976
|
+
depositIxs
|
|
68977
|
+
};
|
|
68978
|
+
}
|
|
68979
|
+
async function buildLoopNonSwapIxs(params) {
|
|
68980
|
+
const {
|
|
68981
|
+
program,
|
|
68982
|
+
marginfiAccount,
|
|
68983
|
+
bankMap,
|
|
68984
|
+
borrowOpts,
|
|
68985
|
+
depositOpts,
|
|
68986
|
+
bankMetadataMap,
|
|
68987
|
+
addressLookupTableAccounts,
|
|
68988
|
+
overrideInferAccounts
|
|
68989
|
+
} = params;
|
|
68990
|
+
const cuRequestIxs = [
|
|
68991
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
68992
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
68993
|
+
];
|
|
68994
|
+
const swapNeeded = !depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint);
|
|
68995
|
+
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
68996
|
+
new PublicKey(depositOpts.depositBank.mint),
|
|
68997
|
+
marginfiAccount.authority,
|
|
68998
|
+
true,
|
|
68999
|
+
depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
69000
|
+
);
|
|
69001
|
+
const principalUi = depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0;
|
|
69002
|
+
let depositAmountUi;
|
|
69003
|
+
let sizeConstraint = 0;
|
|
69004
|
+
let maxSwapTotalAccounts = 0;
|
|
69005
|
+
if (!swapNeeded) {
|
|
69006
|
+
depositAmountUi = borrowOpts.borrowAmount + principalUi;
|
|
69007
|
+
} else {
|
|
69008
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
69009
|
+
program,
|
|
69010
|
+
marginfiAccount,
|
|
69011
|
+
bankMap,
|
|
69012
|
+
bankMetadataMap,
|
|
69013
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
69014
|
+
primaryIx: {
|
|
69015
|
+
type: "borrow",
|
|
69016
|
+
bank: borrowOpts.borrowBank,
|
|
69017
|
+
tokenProgram: borrowOpts.tokenProgram
|
|
69018
|
+
},
|
|
69019
|
+
secondaryIx: {
|
|
69020
|
+
type: "deposit",
|
|
69021
|
+
bank: depositOpts.depositBank,
|
|
69022
|
+
tokenProgram: depositOpts.tokenProgram
|
|
69023
|
+
},
|
|
69024
|
+
overrideInferAccounts
|
|
69481
69025
|
});
|
|
69026
|
+
sizeConstraint = swapConstraints.sizeConstraint;
|
|
69027
|
+
maxSwapTotalAccounts = swapConstraints.maxSwapTotalAccounts;
|
|
69028
|
+
const estimateUi = borrowOpts.borrowAmount * borrowOpts.marketPrice / depositOpts.marketPrice;
|
|
69029
|
+
depositAmountUi = estimateUi + principalUi;
|
|
69482
69030
|
}
|
|
69483
|
-
|
|
69484
|
-
|
|
69485
|
-
|
|
69486
|
-
|
|
69487
|
-
|
|
69488
|
-
|
|
69489
|
-
|
|
69490
|
-
|
|
69491
|
-
|
|
69492
|
-
|
|
69493
|
-
|
|
69494
|
-
|
|
69495
|
-
|
|
69496
|
-
|
|
69497
|
-
|
|
69498
|
-
|
|
69499
|
-
|
|
69500
|
-
|
|
69501
|
-
|
|
69502
|
-
|
|
69503
|
-
|
|
69504
|
-
|
|
69505
|
-
|
|
69506
|
-
|
|
69507
|
-
|
|
69508
|
-
|
|
69509
|
-
|
|
69510
|
-
|
|
69511
|
-
|
|
69512
|
-
|
|
69513
|
-
|
|
69514
|
-
|
|
69515
|
-
|
|
69516
|
-
|
|
69517
|
-
|
|
69518
|
-
|
|
69031
|
+
const borrowIxs = await makeBorrowIx3({
|
|
69032
|
+
program,
|
|
69033
|
+
bank: borrowOpts.borrowBank,
|
|
69034
|
+
bankMap,
|
|
69035
|
+
tokenProgram: borrowOpts.tokenProgram,
|
|
69036
|
+
amount: borrowOpts.borrowAmount,
|
|
69037
|
+
marginfiAccount,
|
|
69038
|
+
authority: marginfiAccount.authority,
|
|
69039
|
+
isSync: false,
|
|
69040
|
+
opts: {
|
|
69041
|
+
createAtas: false,
|
|
69042
|
+
wrapAndUnwrapSol: false,
|
|
69043
|
+
overrideInferAccounts
|
|
69044
|
+
}
|
|
69045
|
+
});
|
|
69046
|
+
const depositIxs = await buildDepositIxs(params, depositAmountUi);
|
|
69047
|
+
const innerIxsBeforeSwap = [...cuRequestIxs, ...borrowIxs.instructions];
|
|
69048
|
+
const swapSlotIndex = innerIxsBeforeSwap.length;
|
|
69049
|
+
const innerIxs = [...innerIxsBeforeSwap, ...depositIxs.instructions];
|
|
69050
|
+
const depositIxIndex = innerIxs.findIndex(isDepositIx);
|
|
69051
|
+
if (depositIxIndex < 0) {
|
|
69052
|
+
throw new Error(
|
|
69053
|
+
"buildLoopNonSwapIxs: could not locate deposit instruction for amount patching"
|
|
69054
|
+
);
|
|
69055
|
+
}
|
|
69056
|
+
const descriptor = {
|
|
69057
|
+
innerIxs,
|
|
69058
|
+
swapSlotIndex,
|
|
69059
|
+
depositIxIndex,
|
|
69060
|
+
inputMint: borrowOpts.borrowBank.mint.toBase58(),
|
|
69061
|
+
outputMint: depositOpts.depositBank.mint.toBase58(),
|
|
69062
|
+
inputDecimals: borrowOpts.borrowBank.mintDecimals,
|
|
69063
|
+
outputDecimals: depositOpts.depositBank.mintDecimals,
|
|
69064
|
+
inAmountNative: uiToNative(
|
|
69065
|
+
borrowOpts.borrowAmount,
|
|
69066
|
+
borrowOpts.borrowBank.mintDecimals
|
|
69067
|
+
).toNumber(),
|
|
69068
|
+
destinationTokenAccount,
|
|
69069
|
+
sizeConstraint,
|
|
69070
|
+
maxSwapTotalAccounts,
|
|
69071
|
+
luts: addressLookupTableAccounts ?? []
|
|
69072
|
+
};
|
|
69073
|
+
return { descriptor, swapNeeded, borrowIxs, depositIxs };
|
|
69074
|
+
}
|
|
69075
|
+
async function buildDepositIxs(params, amountUi) {
|
|
69076
|
+
const { program, marginfiAccount, depositOpts, bankMetadataMap, overrideInferAccounts } = params;
|
|
69077
|
+
switch (depositOpts.depositBank.config.assetTag) {
|
|
69078
|
+
case 3 /* KAMINO */: {
|
|
69079
|
+
const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
69080
|
+
if (!reserve) {
|
|
69081
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
69082
|
+
depositOpts.depositBank.address.toBase58(),
|
|
69083
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
69084
|
+
depositOpts.depositBank.tokenSymbol
|
|
69085
|
+
);
|
|
69519
69086
|
}
|
|
69520
|
-
|
|
69087
|
+
return makeKaminoDepositIx3({
|
|
69088
|
+
program,
|
|
69089
|
+
bank: depositOpts.depositBank,
|
|
69090
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
69091
|
+
amount: amountUi,
|
|
69092
|
+
accountAddress: marginfiAccount.address,
|
|
69093
|
+
authority: marginfiAccount.authority,
|
|
69094
|
+
group: marginfiAccount.group,
|
|
69095
|
+
reserve,
|
|
69096
|
+
opts: {
|
|
69097
|
+
wrapAndUnwrapSol: false,
|
|
69098
|
+
overrideInferAccounts
|
|
69099
|
+
}
|
|
69100
|
+
});
|
|
69101
|
+
}
|
|
69102
|
+
case 4 /* DRIFT */: {
|
|
69103
|
+
const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
|
|
69104
|
+
if (!driftState) {
|
|
69105
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
69106
|
+
depositOpts.depositBank.address.toBase58(),
|
|
69107
|
+
depositOpts.depositBank.mint.toBase58(),
|
|
69108
|
+
depositOpts.depositBank.tokenSymbol
|
|
69109
|
+
);
|
|
69110
|
+
}
|
|
69111
|
+
return makeDriftDepositIx3({
|
|
69112
|
+
program,
|
|
69113
|
+
bank: depositOpts.depositBank,
|
|
69114
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
69115
|
+
amount: amountUi,
|
|
69116
|
+
accountAddress: marginfiAccount.address,
|
|
69117
|
+
authority: marginfiAccount.authority,
|
|
69118
|
+
group: marginfiAccount.group,
|
|
69119
|
+
driftMarketIndex: driftState.spotMarketState.marketIndex,
|
|
69120
|
+
driftOracle: driftState.spotMarketState.oracle,
|
|
69121
|
+
opts: {
|
|
69122
|
+
wrapAndUnwrapSol: false,
|
|
69123
|
+
overrideInferAccounts
|
|
69124
|
+
}
|
|
69125
|
+
});
|
|
69126
|
+
}
|
|
69127
|
+
case 6 /* JUPLEND */: {
|
|
69128
|
+
return makeJuplendDepositIx2({
|
|
69129
|
+
program,
|
|
69130
|
+
bank: depositOpts.depositBank,
|
|
69131
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
69132
|
+
amount: amountUi,
|
|
69133
|
+
accountAddress: marginfiAccount.address,
|
|
69134
|
+
authority: marginfiAccount.authority,
|
|
69135
|
+
group: marginfiAccount.group,
|
|
69136
|
+
opts: {
|
|
69137
|
+
wrapAndUnwrapSol: false,
|
|
69138
|
+
overrideInferAccounts
|
|
69139
|
+
}
|
|
69140
|
+
});
|
|
69141
|
+
}
|
|
69142
|
+
default: {
|
|
69143
|
+
return makeDepositIx3({
|
|
69144
|
+
program,
|
|
69145
|
+
bank: depositOpts.depositBank,
|
|
69146
|
+
tokenProgram: depositOpts.tokenProgram,
|
|
69147
|
+
amount: amountUi,
|
|
69148
|
+
accountAddress: marginfiAccount.address,
|
|
69149
|
+
authority: marginfiAccount.authority,
|
|
69150
|
+
group: marginfiAccount.group,
|
|
69151
|
+
opts: {
|
|
69152
|
+
wrapAndUnwrapSol: false,
|
|
69153
|
+
overrideInferAccounts
|
|
69154
|
+
}
|
|
69155
|
+
});
|
|
69156
|
+
}
|
|
69521
69157
|
}
|
|
69522
|
-
|
|
69523
|
-
|
|
69524
|
-
|
|
69525
|
-
|
|
69526
|
-
|
|
69527
|
-
|
|
69528
|
-
|
|
69529
|
-
|
|
69530
|
-
|
|
69531
|
-
|
|
69532
|
-
|
|
69533
|
-
|
|
69534
|
-
|
|
69535
|
-
|
|
69536
|
-
|
|
69158
|
+
}
|
|
69159
|
+
async function runLoopSwapEngine(descriptor, params) {
|
|
69160
|
+
const { connection, swapOpts, marginfiAccount, swapEngineRunner } = params;
|
|
69161
|
+
if (swapOpts.swapIxs) {
|
|
69162
|
+
return {
|
|
69163
|
+
swapInstructions: swapOpts.swapIxs.instructions,
|
|
69164
|
+
setupInstructions: [],
|
|
69165
|
+
swapLuts: swapOpts.swapIxs.lookupTables,
|
|
69166
|
+
quoteResponse: {
|
|
69167
|
+
inAmount: String(descriptor.inAmountNative),
|
|
69168
|
+
outAmount: "0",
|
|
69169
|
+
otherAmountThreshold: "0",
|
|
69170
|
+
slippageBps: 0
|
|
69171
|
+
},
|
|
69172
|
+
outputAmountNative: new BN9(0)
|
|
69173
|
+
};
|
|
69537
69174
|
}
|
|
69538
|
-
|
|
69539
|
-
|
|
69540
|
-
|
|
69541
|
-
|
|
69542
|
-
|
|
69543
|
-
|
|
69544
|
-
|
|
69545
|
-
|
|
69546
|
-
|
|
69547
|
-
|
|
69548
|
-
|
|
69549
|
-
|
|
69550
|
-
|
|
69551
|
-
|
|
69175
|
+
const runEngine = swapEngineRunner ?? runSwapEngine;
|
|
69176
|
+
const engineResult = await runEngine({
|
|
69177
|
+
inputMint: descriptor.inputMint,
|
|
69178
|
+
outputMint: descriptor.outputMint,
|
|
69179
|
+
amountNative: descriptor.inAmountNative,
|
|
69180
|
+
inputDecimals: descriptor.inputDecimals,
|
|
69181
|
+
outputDecimals: descriptor.outputDecimals,
|
|
69182
|
+
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
69183
|
+
taker: marginfiAccount.authority,
|
|
69184
|
+
destinationTokenAccount: descriptor.destinationTokenAccount,
|
|
69185
|
+
connection,
|
|
69186
|
+
footprint: {
|
|
69187
|
+
instructions: descriptor.innerIxs,
|
|
69188
|
+
luts: descriptor.luts,
|
|
69189
|
+
payer: marginfiAccount.authority,
|
|
69190
|
+
sizeConstraint: descriptor.sizeConstraint,
|
|
69191
|
+
maxSwapTotalAccounts: descriptor.maxSwapTotalAccounts
|
|
69192
|
+
},
|
|
69193
|
+
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
69194
|
+
});
|
|
69195
|
+
return {
|
|
69196
|
+
swapInstructions: engineResult.swapInstructions,
|
|
69197
|
+
setupInstructions: engineResult.setupInstructions,
|
|
69198
|
+
swapLuts: engineResult.swapLuts,
|
|
69199
|
+
quoteResponse: engineResult.quoteResponse,
|
|
69200
|
+
outputAmountNative: engineResult.outputAmountNative
|
|
69201
|
+
};
|
|
69202
|
+
}
|
|
69203
|
+
async function finalizeLoopFlashloanTx({
|
|
69204
|
+
params,
|
|
69205
|
+
innerIxs,
|
|
69206
|
+
luts,
|
|
69207
|
+
swapIxCount,
|
|
69208
|
+
swapLutCount,
|
|
69209
|
+
sizeConstraint
|
|
69210
|
+
}) {
|
|
69211
|
+
const { program, marginfiAccount, bankMap, swapOpts, blockhash } = params;
|
|
69212
|
+
if (swapIxCount > 0) {
|
|
69213
|
+
compileFlashloanPrecheck({
|
|
69214
|
+
allIxs: innerIxs,
|
|
69215
|
+
payer: marginfiAccount.authority,
|
|
69216
|
+
luts,
|
|
69217
|
+
sizeConstraint,
|
|
69218
|
+
swapIxCount,
|
|
69219
|
+
swapLutCount
|
|
69552
69220
|
});
|
|
69553
69221
|
}
|
|
69554
|
-
|
|
69555
|
-
|
|
69556
|
-
|
|
69557
|
-
|
|
69558
|
-
|
|
69559
|
-
|
|
69560
|
-
|
|
69561
|
-
|
|
69562
|
-
|
|
69563
|
-
|
|
69564
|
-
|
|
69565
|
-
|
|
69566
|
-
|
|
69567
|
-
|
|
69568
|
-
|
|
69222
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
69223
|
+
program,
|
|
69224
|
+
marginfiAccount,
|
|
69225
|
+
bankMap,
|
|
69226
|
+
addressLookupTableAccounts: luts,
|
|
69227
|
+
blockhash,
|
|
69228
|
+
ixs: innerIxs
|
|
69229
|
+
});
|
|
69230
|
+
const txSize = getTxSize(flashloanTx);
|
|
69231
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
69232
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
69233
|
+
throw TransactionBuildingError.swapSizeExceededLoop(
|
|
69234
|
+
txSize,
|
|
69235
|
+
totalKeys,
|
|
69236
|
+
swapOpts.swapConfig?.provider
|
|
69237
|
+
);
|
|
69569
69238
|
}
|
|
69570
|
-
|
|
69571
|
-
|
|
69572
|
-
|
|
69573
|
-
|
|
69574
|
-
|
|
69575
|
-
|
|
69576
|
-
|
|
69577
|
-
|
|
69578
|
-
|
|
69579
|
-
return
|
|
69580
|
-
|
|
69581
|
-
|
|
69582
|
-
|
|
69583
|
-
|
|
69584
|
-
|
|
69585
|
-
|
|
69586
|
-
|
|
69239
|
+
return flashloanTx;
|
|
69240
|
+
}
|
|
69241
|
+
async function makeBridgedLoopTx(params) {
|
|
69242
|
+
const { bridgeOpts, ...loopParams } = params;
|
|
69243
|
+
try {
|
|
69244
|
+
return await makeLoopTx(loopParams);
|
|
69245
|
+
} catch (directError) {
|
|
69246
|
+
if (!isDecomposableSwapError(directError)) throw directError;
|
|
69247
|
+
const bridged = await tryBridgedLoop(loopParams, bridgeOpts);
|
|
69248
|
+
if (bridged) return bridged;
|
|
69249
|
+
throw directError;
|
|
69250
|
+
}
|
|
69251
|
+
}
|
|
69252
|
+
async function tryBridgedLoop(params, bridgeOpts) {
|
|
69253
|
+
const { depositBank } = params.depositOpts;
|
|
69254
|
+
const { borrowBank } = params.borrowOpts;
|
|
69255
|
+
const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
|
|
69256
|
+
sourceMint: depositBank.mint,
|
|
69257
|
+
destinationMint: borrowBank.mint,
|
|
69258
|
+
bankMap: params.bankMap,
|
|
69259
|
+
marginfiAccount: params.marginfiAccount,
|
|
69260
|
+
bridgeTokenSide: "borrow",
|
|
69261
|
+
bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
|
|
69262
|
+
});
|
|
69263
|
+
const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
|
|
69264
|
+
const borrowBankPrice = oraclePriceOf(borrowBank);
|
|
69265
|
+
if (borrowBankPrice) return null;
|
|
69266
|
+
const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
|
|
69267
|
+
return tryBridgeCandidates({
|
|
69268
|
+
usableBridgeBanks,
|
|
69269
|
+
conflictingBridgeBanks,
|
|
69270
|
+
bridgeTokenSide: "borrow",
|
|
69271
|
+
abortSignal: bridgeOpts?.abortSignal,
|
|
69272
|
+
buildBundleThroughBridge: async (bridgeBank) => {
|
|
69273
|
+
const birdgeBankPrice = oraclePriceOf(bridgeBank);
|
|
69274
|
+
if (birdgeBankPrice <= 0) return null;
|
|
69275
|
+
const bridgeBorrowUi = params.borrowOpts.borrowAmount * borrowBankPrice / birdgeBankPrice;
|
|
69276
|
+
if (bridgeBorrowUi <= 0) return null;
|
|
69277
|
+
const bridgeTokenProgram = await resolveTokenProgramForMint(
|
|
69278
|
+
bridgeBank.mint,
|
|
69279
|
+
params.connection,
|
|
69280
|
+
tokenProgramCache
|
|
69281
|
+
);
|
|
69282
|
+
const firstLeg = await makeLoopTx({
|
|
69283
|
+
...params,
|
|
69284
|
+
depositOpts: {
|
|
69285
|
+
...params.depositOpts,
|
|
69286
|
+
marketPrice: oraclePriceOf(depositBank)
|
|
69287
|
+
},
|
|
69288
|
+
borrowOpts: {
|
|
69289
|
+
borrowAmount: bridgeBorrowUi,
|
|
69290
|
+
borrowBank: bridgeBank,
|
|
69291
|
+
tokenProgram: bridgeTokenProgram,
|
|
69292
|
+
marketPrice: birdgeBankPrice
|
|
69587
69293
|
}
|
|
69294
|
+
});
|
|
69295
|
+
if (!firstLeg.quoteResponse) return null;
|
|
69296
|
+
const result = await composeBridgedSwap({
|
|
69297
|
+
firstLeg,
|
|
69298
|
+
// Second leg: debt-swap the bridge debt → X (repay exactly the bridge the first leg
|
|
69299
|
+
// borrowed — exact, so no slippage residual; repay-all clears it — and borrow X).
|
|
69300
|
+
buildSecondLeg: (projectedAccount) => makeSwapDebtTx({
|
|
69301
|
+
...sharedBridgeLegContext(params),
|
|
69302
|
+
marginfiAccount: projectedAccount,
|
|
69303
|
+
repayOpts: {
|
|
69304
|
+
totalPositionAmount: bridgeBorrowUi,
|
|
69305
|
+
repayAmount: bridgeBorrowUi,
|
|
69306
|
+
repayBank: bridgeBank,
|
|
69307
|
+
tokenProgram: bridgeTokenProgram,
|
|
69308
|
+
marketPrice: birdgeBankPrice
|
|
69309
|
+
},
|
|
69310
|
+
borrowOpts: {
|
|
69311
|
+
borrowBank,
|
|
69312
|
+
tokenProgram: params.borrowOpts.tokenProgram,
|
|
69313
|
+
marketPrice: borrowBankPrice
|
|
69314
|
+
}
|
|
69315
|
+
}),
|
|
69316
|
+
marginfiAccount: params.marginfiAccount,
|
|
69317
|
+
program: params.program,
|
|
69318
|
+
banksMap: params.bankMap,
|
|
69319
|
+
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
69320
|
+
feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
|
|
69321
|
+
maxBundleTxs: bridgeOpts?.maxBundleTxs
|
|
69322
|
+
});
|
|
69323
|
+
if (!result) return null;
|
|
69324
|
+
return {
|
|
69325
|
+
transactions: result.transactions,
|
|
69326
|
+
actionTxIndex: result.transactions.length - 1,
|
|
69327
|
+
quoteResponse: mergeBridgeQuotesLoop(result.firstLegQuote, result.secondLegQuote),
|
|
69328
|
+
bridgeMint: bridgeBank.mint
|
|
69329
|
+
};
|
|
69330
|
+
}
|
|
69331
|
+
});
|
|
69332
|
+
}
|
|
69333
|
+
async function makeSwapCollateralTx(params) {
|
|
69334
|
+
const {
|
|
69335
|
+
program,
|
|
69336
|
+
marginfiAccount,
|
|
69337
|
+
connection,
|
|
69338
|
+
bankMap,
|
|
69339
|
+
oraclePrices,
|
|
69340
|
+
withdrawOpts,
|
|
69341
|
+
depositOpts,
|
|
69342
|
+
bankMetadataMap,
|
|
69343
|
+
assetShareValueMultiplierByBank,
|
|
69344
|
+
addressLookupTableAccounts,
|
|
69345
|
+
crossbarUrl,
|
|
69346
|
+
additionalIxs = []
|
|
69347
|
+
} = params;
|
|
69348
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
69349
|
+
const setupIxs = await makeSetupIx({
|
|
69350
|
+
connection,
|
|
69351
|
+
authority: marginfiAccount.authority,
|
|
69352
|
+
tokens: [
|
|
69353
|
+
{ mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
|
|
69354
|
+
{ mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
|
|
69355
|
+
]
|
|
69356
|
+
});
|
|
69357
|
+
const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
|
|
69358
|
+
marginfiAccount,
|
|
69359
|
+
bankMap,
|
|
69360
|
+
[withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
|
|
69361
|
+
bankMetadataMap
|
|
69362
|
+
);
|
|
69363
|
+
const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
|
|
69364
|
+
...params,
|
|
69365
|
+
blockhash
|
|
69366
|
+
});
|
|
69367
|
+
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
69368
|
+
if (ix.programId.equals(ComputeBudgetProgram.programId)) {
|
|
69369
|
+
return false;
|
|
69370
|
+
}
|
|
69371
|
+
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
69372
|
+
const mintKey = ix.keys[3]?.pubkey;
|
|
69373
|
+
if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
|
|
69374
|
+
return false;
|
|
69588
69375
|
}
|
|
69376
|
+
}
|
|
69377
|
+
return true;
|
|
69378
|
+
});
|
|
69379
|
+
setupIxs.push(...jupiterSetupInstructions);
|
|
69380
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
69381
|
+
marginfiAccount,
|
|
69382
|
+
bankMap,
|
|
69383
|
+
oraclePrices,
|
|
69384
|
+
assetShareValueMultiplierByBank,
|
|
69385
|
+
instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
69386
|
+
program,
|
|
69387
|
+
connection,
|
|
69388
|
+
crossbarUrl
|
|
69389
|
+
});
|
|
69390
|
+
let additionalTxs = [];
|
|
69391
|
+
if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
|
|
69392
|
+
const ixs = [...setupIxs, ...refreshIntegrationIxs.instructions];
|
|
69393
|
+
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
69394
|
+
blockhash,
|
|
69395
|
+
payerKey: marginfiAccount.authority,
|
|
69396
|
+
luts: addressLookupTableAccounts ?? []
|
|
69589
69397
|
});
|
|
69398
|
+
additionalTxs.push(
|
|
69399
|
+
...txs.map(
|
|
69400
|
+
(tx) => addTransactionMetadata(tx, {
|
|
69401
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
69402
|
+
addressLookupTables: addressLookupTableAccounts
|
|
69403
|
+
})
|
|
69404
|
+
)
|
|
69405
|
+
);
|
|
69590
69406
|
}
|
|
69591
|
-
|
|
69592
|
-
|
|
69593
|
-
|
|
69594
|
-
|
|
69595
|
-
|
|
69596
|
-
|
|
69597
|
-
|
|
69598
|
-
|
|
69599
|
-
|
|
69600
|
-
|
|
69601
|
-
|
|
69602
|
-
|
|
69603
|
-
authority: this.authority
|
|
69604
|
-
});
|
|
69407
|
+
if (updateFeedIxs.length > 0) {
|
|
69408
|
+
const message = new TransactionMessage({
|
|
69409
|
+
payerKey: marginfiAccount.authority,
|
|
69410
|
+
recentBlockhash: blockhash,
|
|
69411
|
+
instructions: updateFeedIxs
|
|
69412
|
+
}).compileToV0Message(feedLuts);
|
|
69413
|
+
additionalTxs.push(
|
|
69414
|
+
addTransactionMetadata(new VersionedTransaction(message), {
|
|
69415
|
+
addressLookupTables: feedLuts,
|
|
69416
|
+
type: "CRANK" /* CRANK */
|
|
69417
|
+
})
|
|
69418
|
+
);
|
|
69605
69419
|
}
|
|
69606
|
-
|
|
69607
|
-
|
|
69608
|
-
|
|
69609
|
-
|
|
69610
|
-
|
|
69611
|
-
|
|
69612
|
-
|
|
69613
|
-
|
|
69614
|
-
|
|
69615
|
-
|
|
69616
|
-
|
|
69617
|
-
|
|
69618
|
-
|
|
69619
|
-
|
|
69620
|
-
|
|
69621
|
-
|
|
69622
|
-
|
|
69623
|
-
|
|
69420
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
69421
|
+
return {
|
|
69422
|
+
transactions,
|
|
69423
|
+
actionTxIndex: transactions.length - 1,
|
|
69424
|
+
quoteResponse: swapQuote
|
|
69425
|
+
};
|
|
69426
|
+
}
|
|
69427
|
+
async function buildSwapCollateralFlashloanTx({
|
|
69428
|
+
program,
|
|
69429
|
+
marginfiAccount,
|
|
69430
|
+
bankMap,
|
|
69431
|
+
withdrawOpts,
|
|
69432
|
+
depositOpts,
|
|
69433
|
+
swapOpts,
|
|
69434
|
+
bankMetadataMap,
|
|
69435
|
+
assetShareValueMultiplierByBank,
|
|
69436
|
+
addressLookupTableAccounts,
|
|
69437
|
+
connection,
|
|
69438
|
+
overrideInferAccounts,
|
|
69439
|
+
blockhash,
|
|
69440
|
+
swapEngineRunner
|
|
69441
|
+
}) {
|
|
69442
|
+
const {
|
|
69443
|
+
withdrawBank,
|
|
69444
|
+
tokenProgram: withdrawTokenProgram,
|
|
69445
|
+
totalPositionAmount,
|
|
69446
|
+
withdrawAmount
|
|
69447
|
+
} = withdrawOpts;
|
|
69448
|
+
const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
|
|
69449
|
+
if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
|
|
69450
|
+
throw new Error("withdrawAmount must be greater than 0");
|
|
69451
|
+
}
|
|
69452
|
+
const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
|
|
69453
|
+
const isFullWithdraw = isWholePosition(
|
|
69454
|
+
{ amount: totalPositionAmount, isLending: true },
|
|
69455
|
+
actualWithdrawAmount,
|
|
69456
|
+
withdrawBank.mintDecimals
|
|
69457
|
+
);
|
|
69458
|
+
const cuRequestIxs = [
|
|
69459
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
69460
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
69461
|
+
];
|
|
69462
|
+
let amountToDeposit;
|
|
69463
|
+
let swapInstructions = [];
|
|
69464
|
+
let setupInstructions = [];
|
|
69465
|
+
let swapLookupTables = [];
|
|
69466
|
+
let swapQuote;
|
|
69467
|
+
let sizeConstraintUsed = 0;
|
|
69468
|
+
let withdrawIxs;
|
|
69469
|
+
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
69470
|
+
case 3 /* KAMINO */: {
|
|
69471
|
+
const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
69472
|
+
if (!reserve) {
|
|
69473
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
69474
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
69475
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
69476
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
69477
|
+
);
|
|
69478
|
+
}
|
|
69479
|
+
const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
|
|
69480
|
+
const adjustedAmount = new BigNumber(actualWithdrawAmount).div(multiplier).times(1.0001).toNumber();
|
|
69481
|
+
withdrawIxs = await makeKaminoWithdrawIx3({
|
|
69482
|
+
program,
|
|
69483
|
+
bank: withdrawBank,
|
|
69484
|
+
bankMap,
|
|
69485
|
+
tokenProgram: withdrawTokenProgram,
|
|
69486
|
+
cTokenAmount: adjustedAmount,
|
|
69487
|
+
marginfiAccount,
|
|
69488
|
+
authority: marginfiAccount.authority,
|
|
69489
|
+
reserve,
|
|
69490
|
+
withdrawAll: isFullWithdraw,
|
|
69491
|
+
isSync: false,
|
|
69492
|
+
opts: {
|
|
69493
|
+
createAtas: false,
|
|
69494
|
+
wrapAndUnwrapSol: false,
|
|
69495
|
+
overrideInferAccounts
|
|
69624
69496
|
}
|
|
69497
|
+
});
|
|
69498
|
+
break;
|
|
69499
|
+
}
|
|
69500
|
+
case 4 /* DRIFT */: {
|
|
69501
|
+
const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
|
|
69502
|
+
if (!driftState) {
|
|
69503
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
69504
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
69505
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
69506
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
69507
|
+
);
|
|
69625
69508
|
}
|
|
69626
|
-
|
|
69627
|
-
|
|
69628
|
-
|
|
69629
|
-
|
|
69630
|
-
|
|
69631
|
-
|
|
69632
|
-
|
|
69633
|
-
|
|
69634
|
-
|
|
69635
|
-
|
|
69636
|
-
|
|
69637
|
-
|
|
69638
|
-
|
|
69639
|
-
|
|
69640
|
-
|
|
69641
|
-
|
|
69642
|
-
overrideInferAccounts: {
|
|
69643
|
-
authority: this.authority,
|
|
69644
|
-
group: this.group,
|
|
69645
|
-
...params.opts?.overrideInferAccounts
|
|
69509
|
+
withdrawIxs = await makeDriftWithdrawIx3({
|
|
69510
|
+
program,
|
|
69511
|
+
bank: withdrawOpts.withdrawBank,
|
|
69512
|
+
bankMap,
|
|
69513
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
69514
|
+
amount: actualWithdrawAmount,
|
|
69515
|
+
marginfiAccount,
|
|
69516
|
+
authority: marginfiAccount.authority,
|
|
69517
|
+
driftSpotMarket: driftState.spotMarketState,
|
|
69518
|
+
userRewards: driftState.userRewards,
|
|
69519
|
+
withdrawAll: isFullWithdraw,
|
|
69520
|
+
isSync: false,
|
|
69521
|
+
opts: {
|
|
69522
|
+
createAtas: false,
|
|
69523
|
+
wrapAndUnwrapSol: false,
|
|
69524
|
+
overrideInferAccounts
|
|
69646
69525
|
}
|
|
69526
|
+
});
|
|
69527
|
+
break;
|
|
69528
|
+
}
|
|
69529
|
+
case 6 /* JUPLEND */: {
|
|
69530
|
+
const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
|
|
69531
|
+
if (!jupLendState) {
|
|
69532
|
+
throw TransactionBuildingError.jupLendStateNotFound(
|
|
69533
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
69534
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
69535
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
69536
|
+
);
|
|
69647
69537
|
}
|
|
69648
|
-
|
|
69538
|
+
withdrawIxs = await makeJuplendWithdrawIx2({
|
|
69539
|
+
program,
|
|
69540
|
+
bank: withdrawBank,
|
|
69541
|
+
bankMap,
|
|
69542
|
+
tokenProgram: withdrawTokenProgram,
|
|
69543
|
+
amount: actualWithdrawAmount,
|
|
69544
|
+
marginfiAccount,
|
|
69545
|
+
authority: marginfiAccount.authority,
|
|
69546
|
+
jupLendingState: jupLendState.jupLendingState,
|
|
69547
|
+
withdrawAll: isFullWithdraw,
|
|
69548
|
+
opts: {
|
|
69549
|
+
createAtas: false,
|
|
69550
|
+
wrapAndUnwrapSol: false,
|
|
69551
|
+
overrideInferAccounts
|
|
69552
|
+
}
|
|
69553
|
+
});
|
|
69554
|
+
break;
|
|
69555
|
+
}
|
|
69556
|
+
default: {
|
|
69557
|
+
withdrawIxs = await makeWithdrawIx3({
|
|
69558
|
+
program,
|
|
69559
|
+
bank: withdrawBank,
|
|
69560
|
+
bankMap,
|
|
69561
|
+
tokenProgram: withdrawTokenProgram,
|
|
69562
|
+
amount: actualWithdrawAmount,
|
|
69563
|
+
marginfiAccount,
|
|
69564
|
+
authority: marginfiAccount.authority,
|
|
69565
|
+
withdrawAll: isFullWithdraw,
|
|
69566
|
+
isSync: false,
|
|
69567
|
+
opts: {
|
|
69568
|
+
createAtas: false,
|
|
69569
|
+
wrapAndUnwrapSol: false,
|
|
69570
|
+
overrideInferAccounts
|
|
69571
|
+
}
|
|
69572
|
+
});
|
|
69573
|
+
break;
|
|
69574
|
+
}
|
|
69649
69575
|
}
|
|
69650
|
-
|
|
69651
|
-
|
|
69652
|
-
|
|
69653
|
-
|
|
69654
|
-
|
|
69655
|
-
|
|
69656
|
-
|
|
69657
|
-
|
|
69658
|
-
|
|
69659
|
-
|
|
69660
|
-
|
|
69661
|
-
|
|
69662
|
-
|
|
69663
|
-
|
|
69664
|
-
|
|
69665
|
-
|
|
69666
|
-
|
|
69667
|
-
|
|
69576
|
+
const swapNeeded = !depositBank.mint.equals(withdrawBank.mint);
|
|
69577
|
+
amountToDeposit = swapNeeded ? 0 : actualWithdrawAmount;
|
|
69578
|
+
let depositIxs;
|
|
69579
|
+
switch (depositBank.config.assetTag) {
|
|
69580
|
+
case 3 /* KAMINO */: {
|
|
69581
|
+
const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
69582
|
+
if (!reserve) {
|
|
69583
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
69584
|
+
depositBank.address.toBase58(),
|
|
69585
|
+
depositBank.mint.toBase58(),
|
|
69586
|
+
depositBank.tokenSymbol
|
|
69587
|
+
);
|
|
69588
|
+
}
|
|
69589
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
69590
|
+
program,
|
|
69591
|
+
bank: depositBank,
|
|
69592
|
+
tokenProgram: depositTokenProgram,
|
|
69593
|
+
amount: amountToDeposit,
|
|
69594
|
+
accountAddress: marginfiAccount.address,
|
|
69595
|
+
authority: marginfiAccount.authority,
|
|
69596
|
+
group: marginfiAccount.group,
|
|
69597
|
+
reserve,
|
|
69598
|
+
opts: {
|
|
69599
|
+
wrapAndUnwrapSol: false,
|
|
69600
|
+
overrideInferAccounts
|
|
69668
69601
|
}
|
|
69602
|
+
});
|
|
69603
|
+
break;
|
|
69604
|
+
}
|
|
69605
|
+
case 4 /* DRIFT */: {
|
|
69606
|
+
const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
|
|
69607
|
+
if (!driftState) {
|
|
69608
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
69609
|
+
depositBank.address.toBase58(),
|
|
69610
|
+
depositBank.mint.toBase58(),
|
|
69611
|
+
depositBank.tokenSymbol
|
|
69612
|
+
);
|
|
69669
69613
|
}
|
|
69614
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
69615
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
69616
|
+
depositIxs = await makeDriftDepositIx3({
|
|
69617
|
+
program,
|
|
69618
|
+
bank: depositBank,
|
|
69619
|
+
tokenProgram: depositTokenProgram,
|
|
69620
|
+
amount: amountToDeposit,
|
|
69621
|
+
accountAddress: marginfiAccount.address,
|
|
69622
|
+
authority: marginfiAccount.authority,
|
|
69623
|
+
group: marginfiAccount.group,
|
|
69624
|
+
driftMarketIndex,
|
|
69625
|
+
driftOracle,
|
|
69626
|
+
opts: {
|
|
69627
|
+
wrapAndUnwrapSol: false,
|
|
69628
|
+
overrideInferAccounts
|
|
69629
|
+
}
|
|
69630
|
+
});
|
|
69631
|
+
break;
|
|
69632
|
+
}
|
|
69633
|
+
case 6 /* JUPLEND */: {
|
|
69634
|
+
depositIxs = await makeJuplendDepositIx2({
|
|
69635
|
+
program,
|
|
69636
|
+
bank: depositBank,
|
|
69637
|
+
tokenProgram: depositTokenProgram,
|
|
69638
|
+
amount: amountToDeposit,
|
|
69639
|
+
accountAddress: marginfiAccount.address,
|
|
69640
|
+
authority: marginfiAccount.authority,
|
|
69641
|
+
group: marginfiAccount.group,
|
|
69642
|
+
opts: {
|
|
69643
|
+
wrapAndUnwrapSol: false,
|
|
69644
|
+
overrideInferAccounts
|
|
69645
|
+
}
|
|
69646
|
+
});
|
|
69647
|
+
break;
|
|
69648
|
+
}
|
|
69649
|
+
default: {
|
|
69650
|
+
depositIxs = await makeDepositIx3({
|
|
69651
|
+
program,
|
|
69652
|
+
bank: depositBank,
|
|
69653
|
+
tokenProgram: depositTokenProgram,
|
|
69654
|
+
amount: amountToDeposit,
|
|
69655
|
+
accountAddress: marginfiAccount.address,
|
|
69656
|
+
authority: marginfiAccount.authority,
|
|
69657
|
+
group: marginfiAccount.group,
|
|
69658
|
+
opts: {
|
|
69659
|
+
wrapAndUnwrapSol: false,
|
|
69660
|
+
overrideInferAccounts
|
|
69661
|
+
}
|
|
69662
|
+
});
|
|
69663
|
+
break;
|
|
69664
|
+
}
|
|
69665
|
+
}
|
|
69666
|
+
if (swapNeeded) {
|
|
69667
|
+
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
69668
|
+
depositBank.mint,
|
|
69669
|
+
marginfiAccount.authority,
|
|
69670
|
+
true,
|
|
69671
|
+
depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
69672
|
+
);
|
|
69673
|
+
const swapConstraints = await computeFlashloanSwapConstraints({
|
|
69674
|
+
program,
|
|
69675
|
+
marginfiAccount,
|
|
69676
|
+
bankMap,
|
|
69677
|
+
bankMetadataMap,
|
|
69678
|
+
addressLookupTableAccounts: addressLookupTableAccounts ?? [],
|
|
69679
|
+
primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
|
|
69680
|
+
secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
|
|
69681
|
+
overrideInferAccounts
|
|
69682
|
+
});
|
|
69683
|
+
sizeConstraintUsed = swapConstraints.sizeConstraint;
|
|
69684
|
+
const runEngine = swapEngineRunner ?? runSwapEngine;
|
|
69685
|
+
const engineResult = await runEngine({
|
|
69686
|
+
inputMint: withdrawBank.mint.toBase58(),
|
|
69687
|
+
outputMint: depositBank.mint.toBase58(),
|
|
69688
|
+
amountNative: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
|
|
69689
|
+
inputDecimals: withdrawBank.mintDecimals,
|
|
69690
|
+
outputDecimals: depositBank.mintDecimals,
|
|
69691
|
+
...swapEngineQuoteFieldsFromOpts(swapOpts),
|
|
69692
|
+
taker: marginfiAccount.authority,
|
|
69693
|
+
destinationTokenAccount,
|
|
69694
|
+
connection,
|
|
69695
|
+
footprint: {
|
|
69696
|
+
instructions: [...cuRequestIxs, ...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
69697
|
+
luts: addressLookupTableAccounts ?? [],
|
|
69698
|
+
payer: marginfiAccount.authority,
|
|
69699
|
+
sizeConstraint: swapConstraints.sizeConstraint,
|
|
69700
|
+
maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
|
|
69701
|
+
},
|
|
69702
|
+
providers: swapEngineProvidersFromOpts(swapOpts)
|
|
69670
69703
|
});
|
|
69704
|
+
const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
|
|
69705
|
+
if (!depositIxToPatch) {
|
|
69706
|
+
throw new Error("swap-collateral: could not locate deposit instruction for amount patching");
|
|
69707
|
+
}
|
|
69708
|
+
patchDepositAmount(depositIxToPatch, engineResult.outputAmountNative);
|
|
69709
|
+
swapInstructions = engineResult.swapInstructions;
|
|
69710
|
+
setupInstructions = engineResult.setupInstructions;
|
|
69711
|
+
swapLookupTables = engineResult.swapLuts;
|
|
69712
|
+
swapQuote = engineResult.quoteResponse;
|
|
69671
69713
|
}
|
|
69672
|
-
|
|
69673
|
-
|
|
69674
|
-
|
|
69675
|
-
|
|
69676
|
-
|
|
69677
|
-
|
|
69678
|
-
|
|
69679
|
-
|
|
69680
|
-
|
|
69681
|
-
|
|
69682
|
-
|
|
69683
|
-
|
|
69714
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
69715
|
+
const allNonFlIxs = [
|
|
69716
|
+
...cuRequestIxs,
|
|
69717
|
+
...withdrawIxs.instructions,
|
|
69718
|
+
...swapInstructions,
|
|
69719
|
+
...depositIxs.instructions
|
|
69720
|
+
];
|
|
69721
|
+
if (swapInstructions.length > 0) {
|
|
69722
|
+
compileFlashloanPrecheck({
|
|
69723
|
+
allIxs: allNonFlIxs,
|
|
69724
|
+
payer: marginfiAccount.authority,
|
|
69725
|
+
luts,
|
|
69726
|
+
sizeConstraint: sizeConstraintUsed,
|
|
69727
|
+
swapIxCount: swapInstructions.length,
|
|
69728
|
+
swapLutCount: swapLookupTables.length
|
|
69729
|
+
});
|
|
69730
|
+
}
|
|
69731
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
69732
|
+
program,
|
|
69733
|
+
marginfiAccount,
|
|
69734
|
+
bankMap,
|
|
69735
|
+
addressLookupTableAccounts: luts,
|
|
69736
|
+
blockhash,
|
|
69737
|
+
ixs: allNonFlIxs,
|
|
69738
|
+
isSync: false
|
|
69739
|
+
});
|
|
69740
|
+
const txSize = getTxSize(flashloanTx);
|
|
69741
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
69742
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
69743
|
+
throw TransactionBuildingError.swapSizeExceededPositionSwap(
|
|
69744
|
+
txSize,
|
|
69745
|
+
totalKeys,
|
|
69746
|
+
swapOpts.swapConfig?.provider
|
|
69747
|
+
);
|
|
69748
|
+
}
|
|
69749
|
+
return {
|
|
69750
|
+
flashloanTx,
|
|
69751
|
+
setupInstructions,
|
|
69752
|
+
swapQuote,
|
|
69753
|
+
withdrawIxs,
|
|
69754
|
+
depositIxs
|
|
69755
|
+
};
|
|
69756
|
+
}
|
|
69757
|
+
var SECOND_LEG_ROUNDING_HEADROOM_NATIVE = 10;
|
|
69758
|
+
async function makeBridgedSwapCollateralTx(params) {
|
|
69759
|
+
const { bridgeOpts, ...directParams } = params;
|
|
69760
|
+
try {
|
|
69761
|
+
return await makeSwapCollateralTx(directParams);
|
|
69762
|
+
} catch (directError) {
|
|
69763
|
+
if (!isDecomposableSwapError(directError)) throw directError;
|
|
69764
|
+
const bridged = await tryBridgedCollateralSwap(directParams, bridgeOpts);
|
|
69765
|
+
if (bridged) return bridged;
|
|
69766
|
+
throw directError;
|
|
69767
|
+
}
|
|
69768
|
+
}
|
|
69769
|
+
async function tryBridgedCollateralSwap(params, bridgeOpts) {
|
|
69770
|
+
const sourceBank = params.withdrawOpts.withdrawBank;
|
|
69771
|
+
const destinationBank = params.depositOpts.depositBank;
|
|
69772
|
+
const withdrawAmount = params.withdrawOpts.withdrawAmount ?? params.withdrawOpts.totalPositionAmount;
|
|
69773
|
+
const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
|
|
69774
|
+
sourceMint: sourceBank.mint,
|
|
69775
|
+
destinationMint: destinationBank.mint,
|
|
69776
|
+
bankMap: params.bankMap,
|
|
69777
|
+
marginfiAccount: params.marginfiAccount,
|
|
69778
|
+
bridgeTokenSide: "deposit",
|
|
69779
|
+
bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
|
|
69780
|
+
});
|
|
69781
|
+
const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
|
|
69782
|
+
return tryBridgeCandidates({
|
|
69783
|
+
usableBridgeBanks,
|
|
69784
|
+
conflictingBridgeBanks,
|
|
69785
|
+
bridgeTokenSide: "deposit",
|
|
69786
|
+
abortSignal: bridgeOpts?.abortSignal,
|
|
69787
|
+
buildBundleThroughBridge: async (bridgeBank) => {
|
|
69788
|
+
const bridgeTokenProgram = await resolveTokenProgramForMint(
|
|
69789
|
+
bridgeBank.mint,
|
|
69790
|
+
params.connection,
|
|
69791
|
+
tokenProgramCache
|
|
69792
|
+
);
|
|
69793
|
+
const firstLeg = await makeSwapCollateralTx({
|
|
69794
|
+
...sharedBridgeLegContext(params),
|
|
69795
|
+
withdrawOpts: {
|
|
69796
|
+
totalPositionAmount: params.withdrawOpts.totalPositionAmount,
|
|
69797
|
+
withdrawAmount,
|
|
69798
|
+
withdrawBank: sourceBank,
|
|
69799
|
+
tokenProgram: params.withdrawOpts.tokenProgram
|
|
69800
|
+
},
|
|
69801
|
+
depositOpts: { depositBank: bridgeBank, tokenProgram: bridgeTokenProgram }
|
|
69802
|
+
});
|
|
69803
|
+
if (!firstLeg.quoteResponse) return null;
|
|
69804
|
+
const bridgeMinOutNative = Number(firstLeg.quoteResponse.otherAmountThreshold);
|
|
69805
|
+
const secondLegAmountNative = bridgeMinOutNative - SECOND_LEG_ROUNDING_HEADROOM_NATIVE;
|
|
69806
|
+
if (secondLegAmountNative <= 0) return null;
|
|
69807
|
+
const secondLegAmountUi = nativeToUi(secondLegAmountNative, bridgeBank.mintDecimals);
|
|
69808
|
+
const hasBridgeDeposit = params.marginfiAccount.balances.some(
|
|
69809
|
+
(b) => b.active && b.bankPk.equals(bridgeBank.address) && b.assetShares.gt(0)
|
|
69810
|
+
);
|
|
69811
|
+
const result = await composeBridgedSwap({
|
|
69812
|
+
firstLeg,
|
|
69813
|
+
// The second leg builds against the first leg's projected effect.
|
|
69814
|
+
buildSecondLeg: (projectedAccount) => makeSwapCollateralTx({
|
|
69815
|
+
...sharedBridgeLegContext(params),
|
|
69816
|
+
marginfiAccount: projectedAccount,
|
|
69817
|
+
withdrawOpts: {
|
|
69818
|
+
totalPositionAmount: hasBridgeDeposit ? nativeToUi(bridgeMinOutNative, bridgeBank.mintDecimals) : secondLegAmountUi,
|
|
69819
|
+
withdrawAmount: secondLegAmountUi,
|
|
69820
|
+
withdrawBank: bridgeBank,
|
|
69821
|
+
tokenProgram: bridgeTokenProgram
|
|
69822
|
+
},
|
|
69823
|
+
depositOpts: params.depositOpts
|
|
69824
|
+
}),
|
|
69825
|
+
marginfiAccount: params.marginfiAccount,
|
|
69826
|
+
program: params.program,
|
|
69827
|
+
banksMap: params.bankMap,
|
|
69828
|
+
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
69829
|
+
feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
|
|
69830
|
+
maxBundleTxs: bridgeOpts?.maxBundleTxs
|
|
69831
|
+
});
|
|
69832
|
+
if (!result) return null;
|
|
69833
|
+
return {
|
|
69834
|
+
transactions: result.transactions,
|
|
69835
|
+
actionTxIndex: result.transactions.length - 1,
|
|
69836
|
+
quoteResponse: mergeBridgeQuotes(result.firstLegQuote, result.secondLegQuote),
|
|
69837
|
+
bridgeMint: bridgeBank.mint
|
|
69838
|
+
};
|
|
69839
|
+
}
|
|
69840
|
+
});
|
|
69841
|
+
}
|
|
69842
|
+
var DEFAULT_ROLL_SLIPPAGE_BPS = 50;
|
|
69843
|
+
var TRADE_PT_EVENT_AMOUNT_OUT_OFFSET = 138;
|
|
69844
|
+
var MERGE_EVENT_AMOUNT_SY_OUT_OFFSET = 296;
|
|
69845
|
+
async function makeRollPtTx(params) {
|
|
69846
|
+
const {
|
|
69847
|
+
program,
|
|
69848
|
+
marginfiAccount,
|
|
69849
|
+
connection,
|
|
69850
|
+
bankMap,
|
|
69851
|
+
oraclePrices,
|
|
69852
|
+
withdrawOpts,
|
|
69853
|
+
depositOpts,
|
|
69854
|
+
rollOpts,
|
|
69855
|
+
assetShareValueMultiplierByBank,
|
|
69856
|
+
addressLookupTableAccounts,
|
|
69857
|
+
crossbarUrl
|
|
69858
|
+
} = params;
|
|
69859
|
+
if (!rollOpts.maturedMarket && !rollOpts.maturedVault) {
|
|
69860
|
+
throw new Error("roll-pt: rollOpts.maturedMarket or maturedVault is required");
|
|
69861
|
+
}
|
|
69862
|
+
const merge = await resolveExponentMergeContext({
|
|
69863
|
+
connection,
|
|
69864
|
+
owner: marginfiAccount.authority,
|
|
69865
|
+
market: rollOpts.maturedMarket,
|
|
69866
|
+
vault: rollOpts.maturedVault,
|
|
69867
|
+
ptYtTokenProgram: withdrawOpts.tokenProgram,
|
|
69868
|
+
syTokenProgram: rollOpts.syTokenProgram
|
|
69869
|
+
});
|
|
69870
|
+
const clmm = await resolveExponentClmmTradePtContext({
|
|
69871
|
+
connection,
|
|
69872
|
+
owner: marginfiAccount.authority,
|
|
69873
|
+
market: rollOpts.successorMarket,
|
|
69874
|
+
ptTokenProgram: depositOpts.tokenProgram,
|
|
69875
|
+
syTokenProgram: rollOpts.syTokenProgram
|
|
69876
|
+
});
|
|
69877
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
69878
|
+
const setupIxs = await makeSetupIx({
|
|
69879
|
+
connection,
|
|
69880
|
+
authority: marginfiAccount.authority,
|
|
69881
|
+
tokens: [
|
|
69882
|
+
{ mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
|
|
69883
|
+
{ mint: merge.mergeAccounts.mintYt, tokenProgram: withdrawOpts.tokenProgram },
|
|
69884
|
+
{ mint: merge.underlying.mint, tokenProgram: merge.underlying.tokenProgram },
|
|
69885
|
+
{ mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
|
|
69886
|
+
]
|
|
69887
|
+
});
|
|
69888
|
+
const { flashloanTx, swapQuote, withdrawIxs, depositIxs } = await buildRollPtFlashloanTx({
|
|
69889
|
+
params,
|
|
69890
|
+
merge,
|
|
69891
|
+
clmm,
|
|
69892
|
+
setupIxs,
|
|
69893
|
+
blockhash
|
|
69894
|
+
});
|
|
69895
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
69896
|
+
marginfiAccount,
|
|
69897
|
+
bankMap,
|
|
69898
|
+
oraclePrices,
|
|
69899
|
+
assetShareValueMultiplierByBank,
|
|
69900
|
+
instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
69901
|
+
program,
|
|
69902
|
+
connection,
|
|
69903
|
+
crossbarUrl
|
|
69904
|
+
});
|
|
69905
|
+
const additionalTxs = [];
|
|
69906
|
+
if (setupIxs.length > 0) {
|
|
69907
|
+
const txs = splitInstructionsToFitTransactions([], setupIxs, {
|
|
69908
|
+
blockhash,
|
|
69909
|
+
payerKey: marginfiAccount.authority,
|
|
69910
|
+
luts: addressLookupTableAccounts ?? []
|
|
69684
69911
|
});
|
|
69912
|
+
additionalTxs.push(
|
|
69913
|
+
...txs.map(
|
|
69914
|
+
(tx) => addTransactionMetadata(tx, {
|
|
69915
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
69916
|
+
addressLookupTables: addressLookupTableAccounts
|
|
69917
|
+
})
|
|
69918
|
+
)
|
|
69919
|
+
);
|
|
69685
69920
|
}
|
|
69686
|
-
|
|
69687
|
-
|
|
69688
|
-
|
|
69689
|
-
|
|
69690
|
-
|
|
69691
|
-
|
|
69692
|
-
|
|
69693
|
-
|
|
69694
|
-
|
|
69695
|
-
|
|
69921
|
+
if (updateFeedIxs.length > 0) {
|
|
69922
|
+
const message = new TransactionMessage({
|
|
69923
|
+
payerKey: marginfiAccount.authority,
|
|
69924
|
+
recentBlockhash: blockhash,
|
|
69925
|
+
instructions: updateFeedIxs
|
|
69926
|
+
}).compileToV0Message(feedLuts);
|
|
69927
|
+
additionalTxs.push(
|
|
69928
|
+
addTransactionMetadata(new VersionedTransaction(message), {
|
|
69929
|
+
addressLookupTables: feedLuts,
|
|
69930
|
+
type: "CRANK" /* CRANK */
|
|
69931
|
+
})
|
|
69932
|
+
);
|
|
69696
69933
|
}
|
|
69697
|
-
|
|
69698
|
-
|
|
69699
|
-
|
|
69700
|
-
|
|
69701
|
-
|
|
69934
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
69935
|
+
return {
|
|
69936
|
+
transactions,
|
|
69937
|
+
actionTxIndex: transactions.length - 1,
|
|
69938
|
+
quoteResponse: swapQuote
|
|
69939
|
+
};
|
|
69702
69940
|
}
|
|
69703
|
-
function
|
|
69704
|
-
|
|
69705
|
-
|
|
69706
|
-
|
|
69707
|
-
|
|
69708
|
-
|
|
69709
|
-
|
|
69710
|
-
|
|
69711
|
-
|
|
69712
|
-
|
|
69713
|
-
|
|
69714
|
-
|
|
69715
|
-
|
|
69716
|
-
|
|
69717
|
-
|
|
69718
|
-
|
|
69941
|
+
async function buildRollPtFlashloanTx({
|
|
69942
|
+
params,
|
|
69943
|
+
merge,
|
|
69944
|
+
clmm,
|
|
69945
|
+
setupIxs,
|
|
69946
|
+
blockhash
|
|
69947
|
+
}) {
|
|
69948
|
+
const {
|
|
69949
|
+
program,
|
|
69950
|
+
marginfiAccount,
|
|
69951
|
+
bankMap,
|
|
69952
|
+
withdrawOpts,
|
|
69953
|
+
depositOpts,
|
|
69954
|
+
bankMetadataMap,
|
|
69955
|
+
connection,
|
|
69956
|
+
addressLookupTableAccounts,
|
|
69957
|
+
overrideInferAccounts,
|
|
69958
|
+
rollOpts
|
|
69959
|
+
} = params;
|
|
69960
|
+
const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount, withdrawAmount } = withdrawOpts;
|
|
69961
|
+
const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
|
|
69962
|
+
const authority = marginfiAccount.authority;
|
|
69963
|
+
if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
|
|
69964
|
+
throw new Error("withdrawAmount must be greater than 0");
|
|
69719
69965
|
}
|
|
69720
|
-
const
|
|
69721
|
-
const
|
|
69722
|
-
|
|
69723
|
-
|
|
69724
|
-
|
|
69725
|
-
|
|
69966
|
+
const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
|
|
69967
|
+
const isFullWithdraw = isWholePosition(
|
|
69968
|
+
{ amount: totalPositionAmount, isLending: true },
|
|
69969
|
+
actualWithdrawAmount,
|
|
69970
|
+
withdrawBank.mintDecimals
|
|
69971
|
+
);
|
|
69972
|
+
const withdrawNative = BigInt(
|
|
69973
|
+
uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toString()
|
|
69974
|
+
);
|
|
69975
|
+
const cuRequestIxs = [
|
|
69976
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
69977
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
69978
|
+
];
|
|
69979
|
+
const withdrawIxs = await makeWithdrawIx3({
|
|
69980
|
+
program,
|
|
69981
|
+
bank: withdrawBank,
|
|
69982
|
+
bankMap,
|
|
69983
|
+
tokenProgram: withdrawTokenProgram,
|
|
69984
|
+
amount: actualWithdrawAmount,
|
|
69985
|
+
marginfiAccount,
|
|
69986
|
+
authority,
|
|
69987
|
+
withdrawAll: isFullWithdraw,
|
|
69988
|
+
isSync: false,
|
|
69989
|
+
opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
69726
69990
|
});
|
|
69727
|
-
|
|
69728
|
-
|
|
69729
|
-
|
|
69730
|
-
|
|
69731
|
-
|
|
69732
|
-
|
|
69991
|
+
const mergeIx = makeExponentMergeIx(merge.mergeAccounts, withdrawNative);
|
|
69992
|
+
const depositIxs = await makeDepositIx3({
|
|
69993
|
+
program,
|
|
69994
|
+
bank: depositBank,
|
|
69995
|
+
tokenProgram: depositTokenProgram,
|
|
69996
|
+
amount: 0,
|
|
69997
|
+
accountAddress: marginfiAccount.address,
|
|
69998
|
+
authority,
|
|
69999
|
+
group: marginfiAccount.group,
|
|
70000
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
|
|
70001
|
+
});
|
|
70002
|
+
let luts;
|
|
70003
|
+
if (rollOpts.lookupTable) {
|
|
70004
|
+
const fetched = (await connection.getAddressLookupTable(rollOpts.lookupTable)).value;
|
|
70005
|
+
if (!fetched) {
|
|
70006
|
+
throw new Error(`roll-pt: PT-roll lookup table not found: ${rollOpts.lookupTable.toBase58()}`);
|
|
70007
|
+
}
|
|
70008
|
+
luts = [fetched, merge.addressLookupTable, clmm.addressLookupTable];
|
|
70009
|
+
} else {
|
|
70010
|
+
luts = [
|
|
70011
|
+
...addressLookupTableAccounts ?? [],
|
|
70012
|
+
merge.addressLookupTable,
|
|
70013
|
+
clmm.addressLookupTable
|
|
70014
|
+
];
|
|
69733
70015
|
}
|
|
69734
|
-
const
|
|
69735
|
-
|
|
69736
|
-
instructions: ixs,
|
|
70016
|
+
const redeemIxs = [...setupIxs, ...cuRequestIxs, ...withdrawIxs.instructions, mergeIx];
|
|
70017
|
+
const mergeReturn = await simulateRollReturn({
|
|
69737
70018
|
program,
|
|
69738
|
-
|
|
69739
|
-
|
|
70019
|
+
marginfiAccount,
|
|
70020
|
+
bankMap,
|
|
70021
|
+
connection,
|
|
70022
|
+
blockhash,
|
|
70023
|
+
luts,
|
|
70024
|
+
ixs: redeemIxs,
|
|
70025
|
+
programId: EXPONENT_CORE_PROGRAM_ID,
|
|
70026
|
+
label: "merge"
|
|
69740
70027
|
});
|
|
69741
|
-
|
|
69742
|
-
|
|
69743
|
-
|
|
69744
|
-
|
|
69745
|
-
|
|
69746
|
-
|
|
69747
|
-
|
|
69748
|
-
|
|
70028
|
+
const syExact = readReturnU64(mergeReturn, MERGE_EVENT_AMOUNT_SY_OUT_OFFSET, "merge amount_sy_out");
|
|
70029
|
+
if (syExact <= 0n) {
|
|
70030
|
+
throw new Error("roll-pt: merge would redeem 0 SY (empty/invalid matured vault state)");
|
|
70031
|
+
}
|
|
70032
|
+
const exactPtOut = await quoteClmmTradeOut({
|
|
70033
|
+
connection,
|
|
70034
|
+
clmm,
|
|
70035
|
+
amountInSyNative: syExact,
|
|
70036
|
+
payer: authority
|
|
70037
|
+
});
|
|
70038
|
+
const slippageBps = rollOpts.slippageBps ?? DEFAULT_ROLL_SLIPPAGE_BPS;
|
|
70039
|
+
const minPtOut = exactPtOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
70040
|
+
if (minPtOut <= 0n) {
|
|
70041
|
+
throw new Error("roll-pt: quoted PT out is 0 (insufficient CLMM liquidity for this size)");
|
|
70042
|
+
}
|
|
70043
|
+
const tradeIx = makeExponentClmmTradePtIx(
|
|
70044
|
+
clmm.tradePtAccounts,
|
|
70045
|
+
exponentClmmBuyPtArgs({ amountInSyNative: syExact, minPtOutNative: minPtOut })
|
|
69749
70046
|
);
|
|
69750
|
-
|
|
69751
|
-
|
|
69752
|
-
|
|
69753
|
-
|
|
69754
|
-
|
|
69755
|
-
|
|
69756
|
-
|
|
69757
|
-
...
|
|
69758
|
-
|
|
69759
|
-
|
|
69760
|
-
|
|
69761
|
-
...c2.cranks,
|
|
69762
|
-
...c2.flashloans
|
|
69763
|
-
// secondLegFL(s)
|
|
70047
|
+
const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
|
|
70048
|
+
if (!depositIxToPatch) {
|
|
70049
|
+
throw new Error("roll-pt: could not locate deposit instruction for amount patching");
|
|
70050
|
+
}
|
|
70051
|
+
patchDepositAmount(depositIxToPatch, new BN9(minPtOut.toString()));
|
|
70052
|
+
const allNonFlIxs = [
|
|
70053
|
+
...cuRequestIxs,
|
|
70054
|
+
...withdrawIxs.instructions,
|
|
70055
|
+
mergeIx,
|
|
70056
|
+
tradeIx,
|
|
70057
|
+
...depositIxs.instructions
|
|
69764
70058
|
];
|
|
69765
|
-
|
|
69766
|
-
|
|
69767
|
-
}
|
|
69768
|
-
function compoundQuoteRisk(firstLeg, secondLeg) {
|
|
69769
|
-
const compound = (a, b) => {
|
|
69770
|
-
if (a == null && b == null) return void 0;
|
|
69771
|
-
const x = Number(a ?? 0);
|
|
69772
|
-
const y = Number(b ?? 0);
|
|
69773
|
-
return String(1 - (1 - x) * (1 - y));
|
|
69774
|
-
};
|
|
69775
|
-
return {
|
|
69776
|
-
slippageBps: Math.round(
|
|
69777
|
-
(1 - (1 - firstLeg.slippageBps / 1e4) * (1 - secondLeg.slippageBps / 1e4)) * 1e4
|
|
69778
|
-
),
|
|
69779
|
-
priceImpactPct: compound(firstLeg.priceImpactPct, secondLeg.priceImpactPct)
|
|
69780
|
-
};
|
|
69781
|
-
}
|
|
69782
|
-
function mergeBridgeQuotes(firstLeg, secondLeg) {
|
|
69783
|
-
return {
|
|
69784
|
-
inAmount: firstLeg.inAmount,
|
|
69785
|
-
outAmount: secondLeg.outAmount,
|
|
69786
|
-
otherAmountThreshold: secondLeg.otherAmountThreshold,
|
|
69787
|
-
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
69788
|
-
provider: firstLeg.provider
|
|
69789
|
-
};
|
|
69790
|
-
}
|
|
69791
|
-
function mergeBridgeQuotesDebt(firstLeg, secondLeg) {
|
|
69792
|
-
return {
|
|
69793
|
-
inAmount: firstLeg.outAmount,
|
|
69794
|
-
outAmount: secondLeg.inAmount,
|
|
69795
|
-
otherAmountThreshold: secondLeg.inAmount,
|
|
69796
|
-
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
69797
|
-
provider: firstLeg.provider
|
|
69798
|
-
};
|
|
69799
|
-
}
|
|
69800
|
-
function mergeBridgeQuotesLoop(firstLeg, secondLeg) {
|
|
69801
|
-
return {
|
|
69802
|
-
inAmount: secondLeg.inAmount,
|
|
69803
|
-
outAmount: firstLeg.outAmount,
|
|
69804
|
-
otherAmountThreshold: firstLeg.otherAmountThreshold,
|
|
69805
|
-
...compoundQuoteRisk(firstLeg, secondLeg),
|
|
69806
|
-
provider: firstLeg.provider
|
|
69807
|
-
};
|
|
69808
|
-
}
|
|
69809
|
-
function blockhashOf(leg) {
|
|
69810
|
-
const tx = leg.transactions[0];
|
|
69811
|
-
return tx ? tx.message.recentBlockhash : PublicKey.default.toBase58();
|
|
69812
|
-
}
|
|
69813
|
-
async function composeBridgedSwap(params) {
|
|
69814
|
-
const {
|
|
69815
|
-
firstLeg,
|
|
69816
|
-
buildSecondLeg,
|
|
70059
|
+
const { sizeConstraint } = computeFlashLoanNonSwapBudget({
|
|
70060
|
+
program,
|
|
69817
70061
|
marginfiAccount,
|
|
70062
|
+
bankMap,
|
|
70063
|
+
addressLookupTableAccounts: luts,
|
|
70064
|
+
ixs: allNonFlIxs
|
|
70065
|
+
});
|
|
70066
|
+
compileFlashloanPrecheck({
|
|
70067
|
+
allIxs: allNonFlIxs,
|
|
70068
|
+
payer: authority,
|
|
70069
|
+
luts,
|
|
70070
|
+
sizeConstraint,
|
|
70071
|
+
swapIxCount: 0,
|
|
70072
|
+
swapLutCount: 0
|
|
70073
|
+
});
|
|
70074
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
69818
70075
|
program,
|
|
69819
|
-
banksMap,
|
|
69820
|
-
assetShareValueMultiplierByBank,
|
|
69821
|
-
feePayer,
|
|
69822
|
-
maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
|
|
69823
|
-
} = params;
|
|
69824
|
-
if (!firstLeg.quoteResponse) return null;
|
|
69825
|
-
const projectedAccount = projectAccountAfterFirstLeg(
|
|
69826
70076
|
marginfiAccount,
|
|
69827
|
-
|
|
70077
|
+
bankMap,
|
|
70078
|
+
addressLookupTableAccounts: luts,
|
|
70079
|
+
blockhash,
|
|
70080
|
+
ixs: allNonFlIxs,
|
|
70081
|
+
isSync: false
|
|
70082
|
+
});
|
|
70083
|
+
const txSize = getTxSize(flashloanTx);
|
|
70084
|
+
const totalKeys = getTotalAccountKeys(flashloanTx);
|
|
70085
|
+
if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
|
|
70086
|
+
throw TransactionBuildingError.swapSizeExceededPositionSwap(txSize, totalKeys, void 0);
|
|
70087
|
+
}
|
|
70088
|
+
const swapQuote = {
|
|
70089
|
+
inAmount: syExact.toString(),
|
|
70090
|
+
outAmount: exactPtOut.toString(),
|
|
70091
|
+
otherAmountThreshold: minPtOut.toString(),
|
|
70092
|
+
slippageBps
|
|
70093
|
+
};
|
|
70094
|
+
return { flashloanTx, swapQuote, withdrawIxs, depositIxs };
|
|
70095
|
+
}
|
|
70096
|
+
async function simulateRollReturn({
|
|
70097
|
+
program,
|
|
70098
|
+
marginfiAccount,
|
|
70099
|
+
bankMap,
|
|
70100
|
+
connection,
|
|
70101
|
+
blockhash,
|
|
70102
|
+
luts,
|
|
70103
|
+
ixs,
|
|
70104
|
+
programId,
|
|
70105
|
+
label
|
|
70106
|
+
}) {
|
|
70107
|
+
const quoteTx = await makeFlashLoanTx({
|
|
69828
70108
|
program,
|
|
69829
|
-
|
|
69830
|
-
|
|
70109
|
+
marginfiAccount,
|
|
70110
|
+
bankMap,
|
|
70111
|
+
addressLookupTableAccounts: luts,
|
|
70112
|
+
blockhash,
|
|
70113
|
+
ixs,
|
|
70114
|
+
isSync: false
|
|
70115
|
+
});
|
|
70116
|
+
const sim = await connection.simulateTransaction(quoteTx, {
|
|
70117
|
+
sigVerify: false,
|
|
70118
|
+
replaceRecentBlockhash: true
|
|
70119
|
+
});
|
|
70120
|
+
const logs = sim.value.logs ?? [];
|
|
70121
|
+
if (process.env.ROLL_DEBUG) {
|
|
70122
|
+
console.error(
|
|
70123
|
+
`[roll ${label} sim] err:`,
|
|
70124
|
+
JSON.stringify(sim.value.err),
|
|
70125
|
+
"returnData:",
|
|
70126
|
+
JSON.stringify(sim.value.returnData),
|
|
70127
|
+
"logsLen:",
|
|
70128
|
+
logs.length,
|
|
70129
|
+
"truncated:",
|
|
70130
|
+
logs.some((l) => l.includes("truncated"))
|
|
70131
|
+
);
|
|
70132
|
+
}
|
|
70133
|
+
const prefix = `Program return: ${programId.toBase58()} `;
|
|
70134
|
+
const line = [...logs].reverse().find((l) => l.startsWith(prefix));
|
|
70135
|
+
if (!line) {
|
|
70136
|
+
throw new Error(
|
|
70137
|
+
`roll-pt: could not read ${label} return data from quote simulation (err=${JSON.stringify(
|
|
70138
|
+
sim.value.err
|
|
70139
|
+
)})`
|
|
70140
|
+
);
|
|
70141
|
+
}
|
|
70142
|
+
return Buffer.from(line.slice(prefix.length), "base64");
|
|
70143
|
+
}
|
|
70144
|
+
function readReturnU64(data, offset, what) {
|
|
70145
|
+
if (data.length < offset + 8) {
|
|
70146
|
+
throw new Error(`roll-pt: ${what} return data too short (${data.length} bytes)`);
|
|
70147
|
+
}
|
|
70148
|
+
return data.readBigUInt64LE(offset);
|
|
70149
|
+
}
|
|
70150
|
+
async function quoteClmmTradeOut({
|
|
70151
|
+
connection,
|
|
70152
|
+
clmm,
|
|
70153
|
+
amountInSyNative,
|
|
70154
|
+
payer
|
|
70155
|
+
}) {
|
|
70156
|
+
const excluded = /* @__PURE__ */ new Set([
|
|
70157
|
+
clmm.tradePtAccounts.tokenSyEscrow.toBase58(),
|
|
70158
|
+
clmm.tradePtAccounts.tokenFeeTreasurySy.toBase58()
|
|
70159
|
+
]);
|
|
70160
|
+
const largest = await connection.getTokenLargestAccounts(clmm.sy.mint);
|
|
70161
|
+
const funded = largest.value.find(
|
|
70162
|
+
(a) => !excluded.has(a.address.toBase58()) && BigInt(a.amount) >= amountInSyNative
|
|
69831
70163
|
);
|
|
69832
|
-
|
|
69833
|
-
|
|
69834
|
-
|
|
69835
|
-
|
|
69836
|
-
|
|
69837
|
-
|
|
69838
|
-
|
|
69839
|
-
|
|
70164
|
+
if (!funded) {
|
|
70165
|
+
throw new Error(
|
|
70166
|
+
"roll-pt: no SY holder large enough to quote the buy \u2014 the roll size exceeds available CLMM liquidity for this pair"
|
|
70167
|
+
);
|
|
70168
|
+
}
|
|
70169
|
+
const parsed = await connection.getParsedAccountInfo(funded.address);
|
|
70170
|
+
const info = parsed.value?.data?.parsed?.info;
|
|
70171
|
+
if (!info?.owner) throw new Error("roll-pt: could not resolve the quote SY holder's owner");
|
|
70172
|
+
const trader = new PublicKey(info.owner);
|
|
70173
|
+
const ptTokenProgram = clmm.pt.tokenProgram ?? TOKEN_PROGRAM_ID;
|
|
70174
|
+
const tokenPtTrader = getAssociatedTokenAddressSync(clmm.pt.mint, trader, true, ptTokenProgram);
|
|
70175
|
+
const quoteIx = makeExponentClmmTradePtIx(
|
|
70176
|
+
{ ...clmm.tradePtAccounts, trader, tokenSyTrader: funded.address, tokenPtTrader },
|
|
70177
|
+
exponentClmmBuyPtArgs({ amountInSyNative, minPtOutNative: 1n })
|
|
69840
70178
|
);
|
|
69841
|
-
|
|
69842
|
-
|
|
70179
|
+
const createPtAta = createAssociatedTokenAccountIdempotentInstruction(
|
|
70180
|
+
payer,
|
|
70181
|
+
tokenPtTrader,
|
|
70182
|
+
trader,
|
|
70183
|
+
clmm.pt.mint,
|
|
70184
|
+
ptTokenProgram
|
|
70185
|
+
);
|
|
70186
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
70187
|
+
const message = new TransactionMessage({
|
|
70188
|
+
payerKey: payer,
|
|
70189
|
+
recentBlockhash: blockhash,
|
|
70190
|
+
instructions: [createPtAta, quoteIx]
|
|
70191
|
+
}).compileToV0Message([clmm.addressLookupTable]);
|
|
70192
|
+
const sim = await connection.simulateTransaction(new VersionedTransaction(message), {
|
|
70193
|
+
sigVerify: false,
|
|
70194
|
+
replaceRecentBlockhash: true
|
|
70195
|
+
});
|
|
70196
|
+
const rd = sim.value.returnData;
|
|
70197
|
+
if (process.env.ROLL_DEBUG) {
|
|
70198
|
+
console.error("[roll trade quote] err:", JSON.stringify(sim.value.err), "returnData?", !!rd);
|
|
70199
|
+
}
|
|
70200
|
+
if (!rd?.data || rd.programId !== EXPONENT_CLMM_PROGRAM_ID.toBase58()) {
|
|
70201
|
+
throw new Error(
|
|
70202
|
+
`roll-pt: CLMM trade quote produced no return data (err=${JSON.stringify(sim.value.err)})`
|
|
70203
|
+
);
|
|
70204
|
+
}
|
|
70205
|
+
const data = Buffer.from(rd.data[0], rd.data[1]);
|
|
70206
|
+
return readReturnU64(data, TRADE_PT_EVENT_AMOUNT_OUT_OFFSET, "trade_pt amount_out");
|
|
69843
70207
|
}
|
|
69844
70208
|
var MAX_BALANCES = 16;
|
|
69845
70209
|
var DEFAULT_MAX_TRANSFER_POSITIONS = 5;
|
|
@@ -71322,30 +71686,95 @@ function patchDepositAmount(ix, amountNative) {
|
|
|
71322
71686
|
}
|
|
71323
71687
|
|
|
71324
71688
|
// src/services/account/utils/bridge.utils.ts
|
|
71325
|
-
function
|
|
71326
|
-
const balance =
|
|
71689
|
+
function accountConflictsWithBridgeBank(marginfiAccount, bridgeBankPk, bridgeTokenSide) {
|
|
71690
|
+
const balance = marginfiAccount.balances.find((b) => b.active && b.bankPk.equals(bridgeBankPk));
|
|
71327
71691
|
if (!balance) return false;
|
|
71328
|
-
return
|
|
71692
|
+
return bridgeTokenSide === "deposit" ? balance.liabilityShares.gt(0) : balance.assetShares.gt(0);
|
|
71329
71693
|
}
|
|
71330
|
-
function
|
|
71331
|
-
const {
|
|
71332
|
-
const passesSideFilter =
|
|
71333
|
-
const
|
|
71334
|
-
const
|
|
71694
|
+
function resolveBridgeCandidateBanks(params) {
|
|
71695
|
+
const { prioritizedBridgeCandidateMints, groupBanks, marginfiAccount, bridgeTokenSide } = params;
|
|
71696
|
+
const passesSideFilter = bridgeTokenSide === "borrow" ? isStandardBorrowable : isStandardDepositable;
|
|
71697
|
+
const usableBridgeBanks = [];
|
|
71698
|
+
const conflictingBridgeBanks = [];
|
|
71335
71699
|
const seenMints = /* @__PURE__ */ new Set();
|
|
71336
|
-
for (const mint of
|
|
71700
|
+
for (const mint of prioritizedBridgeCandidateMints) {
|
|
71337
71701
|
const mintKey = mint.toBase58();
|
|
71338
71702
|
if (seenMints.has(mintKey)) continue;
|
|
71339
71703
|
seenMints.add(mintKey);
|
|
71340
|
-
const bank =
|
|
71704
|
+
const bank = groupBanks.find((b) => b.mint.equals(mint) && passesSideFilter(b));
|
|
71341
71705
|
if (!bank) continue;
|
|
71342
|
-
if (
|
|
71343
|
-
|
|
71706
|
+
if (accountConflictsWithBridgeBank(marginfiAccount, bank.address, bridgeTokenSide)) {
|
|
71707
|
+
conflictingBridgeBanks.push(bank);
|
|
71344
71708
|
} else {
|
|
71345
|
-
|
|
71709
|
+
usableBridgeBanks.push(bank);
|
|
71710
|
+
}
|
|
71711
|
+
}
|
|
71712
|
+
return { usableBridgeBanks, conflictingBridgeBanks };
|
|
71713
|
+
}
|
|
71714
|
+
|
|
71715
|
+
// src/services/account/utils/bridge-routing.utils.ts
|
|
71716
|
+
var DEFAULT_BRIDGE_MINTS = [USDC_MINT, WSOL_MINT, USDT_MINT];
|
|
71717
|
+
async function resolveTokenProgramForMint(mint, connection, tokenProgramCacheByMint) {
|
|
71718
|
+
const mintKey = mint.toBase58();
|
|
71719
|
+
const cached = tokenProgramCacheByMint.get(mintKey);
|
|
71720
|
+
if (cached) return cached;
|
|
71721
|
+
const owner = (await connection.getAccountInfo(mint))?.owner ?? TOKEN_PROGRAM_ID;
|
|
71722
|
+
tokenProgramCacheByMint.set(mintKey, owner);
|
|
71723
|
+
return owner;
|
|
71724
|
+
}
|
|
71725
|
+
function selectSwapBridges(args) {
|
|
71726
|
+
const prioritizedCandidateMints = (args.bridgeCandidateMints ?? DEFAULT_BRIDGE_MINTS).filter(
|
|
71727
|
+
(mint) => !mint.equals(args.sourceMint) && !mint.equals(args.destinationMint)
|
|
71728
|
+
);
|
|
71729
|
+
return resolveBridgeCandidateBanks({
|
|
71730
|
+
prioritizedBridgeCandidateMints: prioritizedCandidateMints,
|
|
71731
|
+
groupBanks: [...args.bankMap.values()],
|
|
71732
|
+
marginfiAccount: args.marginfiAccount,
|
|
71733
|
+
bridgeTokenSide: args.bridgeTokenSide
|
|
71734
|
+
});
|
|
71735
|
+
}
|
|
71736
|
+
function isAbortError(e) {
|
|
71737
|
+
return e instanceof DOMException && e.name === "AbortError";
|
|
71738
|
+
}
|
|
71739
|
+
async function tryBridgeCandidates(args) {
|
|
71740
|
+
for (const bridgeBank of args.usableBridgeBanks) {
|
|
71741
|
+
if (args.abortSignal?.aborted) {
|
|
71742
|
+
throw new DOMException("Operation was aborted", "AbortError");
|
|
71743
|
+
}
|
|
71744
|
+
try {
|
|
71745
|
+
const result = await args.buildBundleThroughBridge(bridgeBank);
|
|
71746
|
+
if (result) return result;
|
|
71747
|
+
} catch (e) {
|
|
71748
|
+
if (isAbortError(e)) throw e;
|
|
71346
71749
|
}
|
|
71347
71750
|
}
|
|
71348
|
-
|
|
71751
|
+
if (args.usableBridgeBanks.length === 0 && args.conflictingBridgeBanks.length > 0) {
|
|
71752
|
+
throw TransactionBuildingError.bridgeConflict(
|
|
71753
|
+
args.conflictingBridgeBanks.map((bank) => ({
|
|
71754
|
+
bankAddress: bank.address.toBase58(),
|
|
71755
|
+
mint: bank.mint.toBase58(),
|
|
71756
|
+
symbol: bank.tokenSymbol
|
|
71757
|
+
})),
|
|
71758
|
+
args.bridgeTokenSide
|
|
71759
|
+
);
|
|
71760
|
+
}
|
|
71761
|
+
return null;
|
|
71762
|
+
}
|
|
71763
|
+
function sharedBridgeLegContext(params) {
|
|
71764
|
+
return {
|
|
71765
|
+
program: params.program,
|
|
71766
|
+
marginfiAccount: params.marginfiAccount,
|
|
71767
|
+
connection: params.connection,
|
|
71768
|
+
bankMap: params.bankMap,
|
|
71769
|
+
oraclePrices: params.oraclePrices,
|
|
71770
|
+
bankMetadataMap: params.bankMetadataMap,
|
|
71771
|
+
assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
|
|
71772
|
+
swapOpts: params.swapOpts,
|
|
71773
|
+
addressLookupTableAccounts: params.addressLookupTableAccounts,
|
|
71774
|
+
overrideInferAccounts: params.overrideInferAccounts,
|
|
71775
|
+
crossbarUrl: params.crossbarUrl,
|
|
71776
|
+
swapEngineRunner: params.swapEngineRunner
|
|
71777
|
+
};
|
|
71349
71778
|
}
|
|
71350
71779
|
|
|
71351
71780
|
// src/services/price/utils/smart-crank.utils.ts
|
|
@@ -75228,6 +75657,82 @@ var MarginfiAccountWrapper = class {
|
|
|
75228
75657
|
};
|
|
75229
75658
|
return this.account.makeSwapDebtTx(fullParams);
|
|
75230
75659
|
}
|
|
75660
|
+
/**
|
|
75661
|
+
* Creates a loop (leverage) transaction with a transparent bridged (double-hop) fallback and
|
|
75662
|
+
* auto-injected client data.
|
|
75663
|
+
*
|
|
75664
|
+
* One call: tries the direct {@link makeLoopTx} first; if its borrow→deposit swap can't fit one
|
|
75665
|
+
* transaction or has no route, it loops the deposit asset against a value-equivalent borrow of a
|
|
75666
|
+
* bridge token (USDC/wSOL/USDT by default, override via `bridgeOpts.bridgeCandidateMints`) and
|
|
75667
|
+
* debt-swaps that bridge debt to the requested borrow asset — one atomic Jito bundle.
|
|
75668
|
+
* `result.bridgeMint` is set only when the bridged path was used.
|
|
75669
|
+
*
|
|
75670
|
+
* Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
|
|
75671
|
+
* addressLookupTables, assetShareValueMultiplierByBank
|
|
75672
|
+
*
|
|
75673
|
+
* @param params - Loop parameters (user provides: connection, depositOpts, borrowOpts, swapOpts, bridgeOpts?, etc.)
|
|
75674
|
+
*/
|
|
75675
|
+
async makeBridgedLoopTx(params) {
|
|
75676
|
+
return this.account.makeBridgedLoopTx({
|
|
75677
|
+
...params,
|
|
75678
|
+
program: this.client.program,
|
|
75679
|
+
bankMap: this.client.bankMap,
|
|
75680
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
75681
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
75682
|
+
addressLookupTableAccounts: this.client.addressLookupTables,
|
|
75683
|
+
assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
|
|
75684
|
+
});
|
|
75685
|
+
}
|
|
75686
|
+
/**
|
|
75687
|
+
* Creates a collateral-swap transaction with a transparent bridged (double-hop) fallback and
|
|
75688
|
+
* auto-injected client data.
|
|
75689
|
+
*
|
|
75690
|
+
* One call: tries the direct {@link makeSwapCollateralTx} first; if the swap `A → C` can't fit
|
|
75691
|
+
* one transaction or has no route, it decomposes into `A → bridge` + `bridge → C` through a
|
|
75692
|
+
* bridge token, composed as one atomic Jito bundle. `result.bridgeMint` is set only when the
|
|
75693
|
+
* bridged path was used.
|
|
75694
|
+
*
|
|
75695
|
+
* Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
|
|
75696
|
+
* addressLookupTables, assetShareValueMultiplierByBank
|
|
75697
|
+
*
|
|
75698
|
+
* @param params - Swap collateral parameters (user provides: connection, withdrawOpts, depositOpts, swapOpts, bridgeOpts?, etc.)
|
|
75699
|
+
*/
|
|
75700
|
+
async makeBridgedSwapCollateralTx(params) {
|
|
75701
|
+
return this.account.makeBridgedSwapCollateralTx({
|
|
75702
|
+
...params,
|
|
75703
|
+
program: this.client.program,
|
|
75704
|
+
bankMap: this.client.bankMap,
|
|
75705
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
75706
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
75707
|
+
addressLookupTableAccounts: this.client.addressLookupTables,
|
|
75708
|
+
assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
|
|
75709
|
+
});
|
|
75710
|
+
}
|
|
75711
|
+
/**
|
|
75712
|
+
* Creates a debt-swap transaction with a transparent bridged (double-hop) fallback and
|
|
75713
|
+
* auto-injected client data.
|
|
75714
|
+
*
|
|
75715
|
+
* One call: tries the direct {@link makeSwapDebtTx} first; if the swap `A → C` can't fit one
|
|
75716
|
+
* transaction or has no route, the first leg repays A by borrowing a bridge token and the second
|
|
75717
|
+
* leg repays exactly that bridge debt while borrowing C — one atomic Jito bundle.
|
|
75718
|
+
* `result.bridgeMint` is set only when the bridged path was used.
|
|
75719
|
+
*
|
|
75720
|
+
* Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
|
|
75721
|
+
* addressLookupTables, assetShareValueMultiplierByBank
|
|
75722
|
+
*
|
|
75723
|
+
* @param params - Swap debt parameters (user provides: connection, repayOpts, borrowOpts, swapOpts, bridgeOpts?, etc.)
|
|
75724
|
+
*/
|
|
75725
|
+
async makeBridgedSwapDebtTx(params) {
|
|
75726
|
+
return this.account.makeBridgedSwapDebtTx({
|
|
75727
|
+
...params,
|
|
75728
|
+
program: this.client.program,
|
|
75729
|
+
bankMap: this.client.bankMap,
|
|
75730
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
75731
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
75732
|
+
addressLookupTableAccounts: this.client.addressLookupTables,
|
|
75733
|
+
assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
|
|
75734
|
+
});
|
|
75735
|
+
}
|
|
75231
75736
|
/**
|
|
75232
75737
|
* Creates a deposit transaction with auto-injected client data.
|
|
75233
75738
|
*
|
|
@@ -75985,6 +76490,6 @@ var EmodeSettings = class _EmodeSettings {
|
|
|
75985
76490
|
}
|
|
75986
76491
|
};
|
|
75987
76492
|
|
|
75988
|
-
export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_GROUP_NATIVE_STAKE, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_CROSSBAR_URL, DEFAULT_FALLBACK_CROSSBAR_URL, DEFAULT_ORACLE_MAX_AGE, DEFAULT_REPAY_ALL_EXTRA_BUFFER_BPS, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_ACCOUNT_LOCKS, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKED_ORACLE_DISABLED_FLAG, STAKED_ORACLE_USES_ONRAMP_FLAG, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWAP_ADAPTERS, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, SwapProvider, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountConflictsWithBridge, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRateLimiterRawToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, buildCollateralLegIxs, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkJupiterFeeAccount, checkMultipleOraclesCrankability, checkTitanFeeAccount, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, classifyAndValidate, compileFlashloanPrecheck, composeBridgedSwap, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBankBorrowApy, computeBankBorrowCapRemaining, computeBankDepositCapRemaining, computeBankMetrics, computeBankPoolSize, computeBankSupplyApy, computeBankTotalBorrows, computeBankTotalBorrowsUsd, computeBankTotalDeposits, computeBankTotalDepositsUsd, computeBaseInterestRate, computeBorrowEstimateForRepay, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFlashLoanNonSwapBudget, computeFlashloanSwapConstraints, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeStakedBankMultipliers, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, computeV0TxSize, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, deserializeInstruction, deserializeLut, deserializeSwapEngineRequest, deserializeSwapEngineResult, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRateLimiter, dtoToBankRateLimiterRaw, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountActiveBalancesForBank, fetchMarginfiAccountAddresses, fetchMarginfiAccountAddressesHoldingBank, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, generateDummyAccount, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getExactOutEstimate, getFallbackPricesByFeedId, getFallbackPricesForMints, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterReferralFeeAccount, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getSwapAdapter, getSwapIxsForFlashloan, getTitanExactOutEstimate, getTitanSwapIxsForFlashloan, getTotalAccountKeys, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, getWritableAccountKeys, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isDecomposableSwapError, isDepositIx, isFlashloan, isGroupRateLimiterEnabled, isStandardBorrowable, isStandardDepositable, isV0Tx, isWeightedPrice, isWholePosition, makeAccountTransferToNewAccountTx, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBulkRepayTx, makeBulkWithdrawTx, makeBundleTipIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshIntegrationBanksIxs, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeRollPtTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSmartCrankSwbFeedIxForAccounts, makeSwapCollateralTx, makeSwapDebtTx, makeTransferPositionsTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapJupiterQuoteToSwapQuoteResult, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, mergeBridgeQuotes, mergeBridgeQuotesDebt, mergeBridgeQuotesLoop, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRateLimiterRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, patchDepositAmount, requireBank, requireTokenProgram, resolveAmount, resolveBridgeBanks, runSwapEngine, selectLutsForAccountAction, selectLutsForBanks, serializeBankConfigOpt, serializeInstruction, serializeInterestRateConfig, serializeLut, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, serializeSwapEngineRequest, serializeSwapEngineResult, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, swapEngineProvidersFromOpts, swapEngineQuoteFieldsFromOpts, toBankConfigDto, toBankDto, toBankRateLimiterDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toJupiterConfig, toNumber, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
|
|
76493
|
+
export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_GROUP_NATIVE_STAKE, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_BRIDGE_MINTS, DEFAULT_CROSSBAR_URL, DEFAULT_FALLBACK_CROSSBAR_URL, DEFAULT_ORACLE_MAX_AGE, DEFAULT_REPAY_ALL_EXTRA_BUFFER_BPS, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_ACCOUNT_LOCKS, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKED_ORACLE_DISABLED_FLAG, STAKED_ORACLE_USES_ONRAMP_FLAG, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWAP_ADAPTERS, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, SwapProvider, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, USDT_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountConflictsWithBridgeBank, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRateLimiterRawToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, buildCollateralLegIxs, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkJupiterFeeAccount, checkMultipleOraclesCrankability, checkTitanFeeAccount, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, classifyAndValidate, compileFlashloanPrecheck, composeBridgedSwap, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBankBorrowApy, computeBankBorrowCapRemaining, computeBankDepositCapRemaining, computeBankMetrics, computeBankPoolSize, computeBankSupplyApy, computeBankTotalBorrows, computeBankTotalBorrowsUsd, computeBankTotalDeposits, computeBankTotalDepositsUsd, computeBaseInterestRate, computeBorrowEstimateForRepay, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFlashLoanNonSwapBudget, computeFlashloanSwapConstraints, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeStakedBankMultipliers, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, computeV0TxSize, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, deserializeInstruction, deserializeLut, deserializeSwapEngineRequest, deserializeSwapEngineResult, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRateLimiter, dtoToBankRateLimiterRaw, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountActiveBalancesForBank, fetchMarginfiAccountAddresses, fetchMarginfiAccountAddressesHoldingBank, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, generateDummyAccount, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getExactOutEstimate, getFallbackPricesByFeedId, getFallbackPricesForMints, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterReferralFeeAccount, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getSwapAdapter, getSwapIxsForFlashloan, getTitanExactOutEstimate, getTitanSwapIxsForFlashloan, getTotalAccountKeys, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, getWritableAccountKeys, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isBridgeConflictError, isDecomposableSwapError, isDepositIx, isFlashloan, isGroupRateLimiterEnabled, isStandardBorrowable, isStandardDepositable, isV0Tx, isWeightedPrice, isWholePosition, makeAccountTransferToNewAccountTx, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBridgedLoopTx, makeBridgedSwapCollateralTx, makeBridgedSwapDebtTx, makeBulkRepayTx, makeBulkWithdrawTx, makeBundleTipIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshIntegrationBanksIxs, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeRollPtTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSmartCrankSwbFeedIxForAccounts, makeSwapCollateralTx, makeSwapDebtTx, makeTransferPositionsTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapJupiterQuoteToSwapQuoteResult, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, mergeBridgeQuotes, mergeBridgeQuotesDebt, mergeBridgeQuotesLoop, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRateLimiterRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, patchDepositAmount, requireBank, requireTokenProgram, resolveAmount, resolveBridgeCandidateBanks, resolveTokenProgramForMint, runSwapEngine, selectLutsForAccountAction, selectLutsForBanks, selectSwapBridges, serializeBankConfigOpt, serializeInstruction, serializeInterestRateConfig, serializeLut, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, serializeSwapEngineRequest, serializeSwapEngineResult, sharedBridgeLegContext, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, swapEngineProvidersFromOpts, swapEngineQuoteFieldsFromOpts, toBankConfigDto, toBankDto, toBankRateLimiterDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toJupiterConfig, toNumber, tryBridgeCandidates, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
|
|
75989
76494
|
//# sourceMappingURL=index.js.map
|
|
75990
76495
|
//# sourceMappingURL=index.js.map
|