@0dotxyz/p0-ts-sdk 1.1.1 → 1.2.0-alpha.2
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 +860 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -5
- package/dist/index.d.ts +184 -5
- package/dist/index.js +859 -121
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -33284,7 +33284,8 @@ async function makeSetupIx({ connection, authority, tokens }) {
|
|
|
33284
33284
|
}
|
|
33285
33285
|
}
|
|
33286
33286
|
return ixs;
|
|
33287
|
-
} catch {
|
|
33287
|
+
} catch (error) {
|
|
33288
|
+
console.error("[makeSetupIx] Failed to create setup instructions:", error);
|
|
33288
33289
|
return [];
|
|
33289
33290
|
}
|
|
33290
33291
|
}
|
|
@@ -43237,104 +43238,729 @@ async function makeWithdrawEmissionsIx(program, marginfiAccount, banks, mintData
|
|
|
43237
43238
|
ixs.push(withdrawEmissionsIx);
|
|
43238
43239
|
return { instructions: ixs, keys: [] };
|
|
43239
43240
|
}
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43248
|
-
|
|
43249
|
-
|
|
43241
|
+
async function makeSwapCollateralTx(params) {
|
|
43242
|
+
const {
|
|
43243
|
+
program,
|
|
43244
|
+
marginfiAccount,
|
|
43245
|
+
connection,
|
|
43246
|
+
bankMap,
|
|
43247
|
+
oraclePrices,
|
|
43248
|
+
withdrawOpts,
|
|
43249
|
+
depositOpts,
|
|
43250
|
+
bankMetadataMap,
|
|
43251
|
+
addressLookupTableAccounts,
|
|
43252
|
+
crossbarUrl,
|
|
43253
|
+
additionalIxs = []
|
|
43254
|
+
} = params;
|
|
43255
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
43256
|
+
const setupIxs = await makeSetupIx({
|
|
43257
|
+
connection,
|
|
43258
|
+
authority: marginfiAccount.authority,
|
|
43259
|
+
tokens: [
|
|
43260
|
+
{ mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
|
|
43261
|
+
{ mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
|
|
43262
|
+
]
|
|
43263
|
+
});
|
|
43264
|
+
const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
|
|
43265
|
+
marginfiAccount,
|
|
43266
|
+
bankMap,
|
|
43267
|
+
[withdrawOpts.withdrawBank.address],
|
|
43268
|
+
bankMetadataMap
|
|
43250
43269
|
);
|
|
43251
|
-
|
|
43252
|
-
|
|
43253
|
-
|
|
43254
|
-
|
|
43255
|
-
|
|
43256
|
-
|
|
43257
|
-
|
|
43270
|
+
const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
|
|
43271
|
+
marginfiAccount,
|
|
43272
|
+
bankMap,
|
|
43273
|
+
[withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
|
|
43274
|
+
bankMetadataMap
|
|
43275
|
+
);
|
|
43276
|
+
const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
|
|
43277
|
+
...params,
|
|
43278
|
+
blockhash
|
|
43279
|
+
});
|
|
43280
|
+
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
43281
|
+
if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
|
|
43282
|
+
return false;
|
|
43283
|
+
}
|
|
43284
|
+
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
43285
|
+
const mintKey = ix.keys[3]?.pubkey;
|
|
43286
|
+
if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
|
|
43287
|
+
return false;
|
|
43288
|
+
}
|
|
43289
|
+
}
|
|
43290
|
+
return true;
|
|
43291
|
+
});
|
|
43292
|
+
setupIxs.push(...jupiterSetupInstructions);
|
|
43293
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
43294
|
+
marginfiAccount,
|
|
43295
|
+
bankMap,
|
|
43296
|
+
oraclePrices,
|
|
43297
|
+
instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
|
|
43298
|
+
program,
|
|
43299
|
+
connection,
|
|
43300
|
+
crossbarUrl
|
|
43301
|
+
});
|
|
43302
|
+
let additionalTxs = [];
|
|
43303
|
+
if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0) {
|
|
43304
|
+
const ixs = [
|
|
43305
|
+
...setupIxs,
|
|
43306
|
+
...kaminoRefreshIxs.instructions,
|
|
43307
|
+
...updateDriftMarketIxs.instructions
|
|
43308
|
+
];
|
|
43309
|
+
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
43310
|
+
blockhash,
|
|
43311
|
+
payerKey: marginfiAccount.authority,
|
|
43312
|
+
luts: addressLookupTableAccounts ?? []
|
|
43258
43313
|
});
|
|
43259
|
-
|
|
43260
|
-
|
|
43261
|
-
|
|
43262
|
-
|
|
43263
|
-
|
|
43264
|
-
|
|
43265
|
-
|
|
43266
|
-
props.bankMap,
|
|
43267
|
-
props.oraclePrices,
|
|
43268
|
-
1 /* Maintenance */,
|
|
43269
|
-
[]
|
|
43314
|
+
additionalTxs.push(
|
|
43315
|
+
...txs.map(
|
|
43316
|
+
(tx) => addTransactionMetadata(tx, {
|
|
43317
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
43318
|
+
addressLookupTables: addressLookupTableAccounts
|
|
43319
|
+
})
|
|
43320
|
+
)
|
|
43270
43321
|
);
|
|
43271
|
-
|
|
43272
|
-
|
|
43273
|
-
|
|
43274
|
-
|
|
43275
|
-
|
|
43276
|
-
|
|
43322
|
+
}
|
|
43323
|
+
if (updateFeedIxs.length > 0) {
|
|
43324
|
+
const message = new web3_js.TransactionMessage({
|
|
43325
|
+
payerKey: marginfiAccount.authority,
|
|
43326
|
+
recentBlockhash: blockhash,
|
|
43327
|
+
instructions: updateFeedIxs
|
|
43328
|
+
}).compileToV0Message(feedLuts);
|
|
43329
|
+
additionalTxs.push(
|
|
43330
|
+
addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
43331
|
+
addressLookupTables: feedLuts,
|
|
43332
|
+
type: "CRANK" /* CRANK */
|
|
43333
|
+
})
|
|
43277
43334
|
);
|
|
43278
|
-
marginfiAccount.healthCache = {
|
|
43279
|
-
assetValue: assetValueInitial,
|
|
43280
|
-
liabilityValue: liabilityValueInitial,
|
|
43281
|
-
assetValueMaint,
|
|
43282
|
-
liabilityValueMaint,
|
|
43283
|
-
assetValueEquity,
|
|
43284
|
-
liabilityValueEquity,
|
|
43285
|
-
timestamp: new BigNumber10__default.default(0),
|
|
43286
|
-
flags: [],
|
|
43287
|
-
prices: [],
|
|
43288
|
-
simulationStatus: 2 /* COMPUTED */
|
|
43289
|
-
};
|
|
43290
|
-
if (e instanceof HealthCacheSimulationError) {
|
|
43291
|
-
return { marginfiAccount, error: e };
|
|
43292
|
-
}
|
|
43293
43335
|
}
|
|
43294
|
-
|
|
43336
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
43337
|
+
return {
|
|
43338
|
+
transactions,
|
|
43339
|
+
actionTxIndex: transactions.length - 1,
|
|
43340
|
+
quoteResponse: swapQuote
|
|
43341
|
+
};
|
|
43295
43342
|
}
|
|
43296
|
-
async function
|
|
43297
|
-
|
|
43298
|
-
|
|
43299
|
-
|
|
43300
|
-
|
|
43301
|
-
|
|
43302
|
-
|
|
43303
|
-
|
|
43304
|
-
|
|
43305
|
-
|
|
43306
|
-
|
|
43307
|
-
|
|
43308
|
-
|
|
43309
|
-
const
|
|
43310
|
-
|
|
43311
|
-
|
|
43312
|
-
|
|
43313
|
-
|
|
43314
|
-
|
|
43315
|
-
|
|
43316
|
-
|
|
43317
|
-
|
|
43318
|
-
|
|
43319
|
-
|
|
43320
|
-
|
|
43343
|
+
async function buildSwapCollateralFlashloanTx({
|
|
43344
|
+
program,
|
|
43345
|
+
marginfiAccount,
|
|
43346
|
+
bankMap,
|
|
43347
|
+
withdrawOpts,
|
|
43348
|
+
depositOpts,
|
|
43349
|
+
swapOpts,
|
|
43350
|
+
bankMetadataMap,
|
|
43351
|
+
addressLookupTableAccounts,
|
|
43352
|
+
connection,
|
|
43353
|
+
overrideInferAccounts,
|
|
43354
|
+
blockhash
|
|
43355
|
+
}) {
|
|
43356
|
+
const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount } = withdrawOpts;
|
|
43357
|
+
const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
|
|
43358
|
+
const swapResult = [];
|
|
43359
|
+
const cuRequestIxs = [
|
|
43360
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
43361
|
+
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
43362
|
+
];
|
|
43363
|
+
let withdrawIxs;
|
|
43364
|
+
switch (withdrawOpts.withdrawBank.config.assetTag) {
|
|
43365
|
+
case 3 /* KAMINO */: {
|
|
43366
|
+
const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
43367
|
+
if (!reserve) {
|
|
43368
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
43369
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
43370
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
43371
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
43372
|
+
);
|
|
43373
|
+
}
|
|
43374
|
+
const adjustedAmount = new BigNumber10.BigNumber(totalPositionAmount).div(withdrawOpts.withdrawBank.assetShareValue).times(1.0001).toNumber();
|
|
43375
|
+
withdrawIxs = await makeKaminoWithdrawIx3({
|
|
43376
|
+
program,
|
|
43377
|
+
bank: withdrawBank,
|
|
43378
|
+
bankMap,
|
|
43379
|
+
tokenProgram: withdrawTokenProgram,
|
|
43380
|
+
amount: adjustedAmount,
|
|
43381
|
+
marginfiAccount,
|
|
43382
|
+
authority: marginfiAccount.authority,
|
|
43383
|
+
reserve,
|
|
43384
|
+
withdrawAll: true,
|
|
43385
|
+
isSync: true,
|
|
43386
|
+
opts: {
|
|
43387
|
+
createAtas: false,
|
|
43388
|
+
wrapAndUnwrapSol: false,
|
|
43389
|
+
overrideInferAccounts
|
|
43390
|
+
}
|
|
43391
|
+
});
|
|
43392
|
+
break;
|
|
43321
43393
|
}
|
|
43322
|
-
|
|
43323
|
-
|
|
43324
|
-
|
|
43325
|
-
|
|
43326
|
-
|
|
43327
|
-
|
|
43328
|
-
|
|
43329
|
-
|
|
43394
|
+
case 4 /* DRIFT */: {
|
|
43395
|
+
const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
|
|
43396
|
+
if (!driftState) {
|
|
43397
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
43398
|
+
withdrawOpts.withdrawBank.address.toBase58(),
|
|
43399
|
+
withdrawOpts.withdrawBank.mint.toBase58(),
|
|
43400
|
+
withdrawOpts.withdrawBank.tokenSymbol
|
|
43401
|
+
);
|
|
43402
|
+
}
|
|
43403
|
+
withdrawIxs = await makeDriftWithdrawIx3({
|
|
43404
|
+
program,
|
|
43405
|
+
bank: withdrawOpts.withdrawBank,
|
|
43406
|
+
bankMap,
|
|
43407
|
+
tokenProgram: withdrawOpts.tokenProgram,
|
|
43408
|
+
amount: totalPositionAmount,
|
|
43409
|
+
marginfiAccount,
|
|
43410
|
+
authority: marginfiAccount.authority,
|
|
43411
|
+
driftSpotMarket: driftState.spotMarketState,
|
|
43412
|
+
userRewards: driftState.userRewards,
|
|
43413
|
+
withdrawAll: true,
|
|
43414
|
+
isSync: false,
|
|
43415
|
+
opts: {
|
|
43416
|
+
createAtas: false,
|
|
43417
|
+
wrapAndUnwrapSol: false,
|
|
43418
|
+
overrideInferAccounts
|
|
43419
|
+
}
|
|
43420
|
+
});
|
|
43421
|
+
break;
|
|
43330
43422
|
}
|
|
43331
|
-
|
|
43332
|
-
|
|
43333
|
-
|
|
43423
|
+
default: {
|
|
43424
|
+
withdrawIxs = await makeWithdrawIx3({
|
|
43425
|
+
program,
|
|
43426
|
+
bank: withdrawBank,
|
|
43427
|
+
bankMap,
|
|
43428
|
+
tokenProgram: withdrawTokenProgram,
|
|
43429
|
+
amount: totalPositionAmount,
|
|
43430
|
+
marginfiAccount,
|
|
43431
|
+
authority: marginfiAccount.authority,
|
|
43432
|
+
withdrawAll: true,
|
|
43433
|
+
isSync: true,
|
|
43434
|
+
opts: {
|
|
43435
|
+
createAtas: false,
|
|
43436
|
+
wrapAndUnwrapSol: false,
|
|
43437
|
+
overrideInferAccounts
|
|
43438
|
+
}
|
|
43439
|
+
});
|
|
43440
|
+
break;
|
|
43334
43441
|
}
|
|
43335
|
-
|
|
43336
|
-
|
|
43337
|
-
|
|
43442
|
+
}
|
|
43443
|
+
if (depositBank.mint.equals(withdrawBank.mint)) {
|
|
43444
|
+
swapResult.push({
|
|
43445
|
+
amountToDeposit: totalPositionAmount,
|
|
43446
|
+
swapInstructions: [],
|
|
43447
|
+
setupInstructions: [],
|
|
43448
|
+
swapLookupTables: []
|
|
43449
|
+
});
|
|
43450
|
+
} else {
|
|
43451
|
+
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
43452
|
+
depositBank.mint,
|
|
43453
|
+
marginfiAccount.authority,
|
|
43454
|
+
true,
|
|
43455
|
+
depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
43456
|
+
);
|
|
43457
|
+
const swapResponses = await getJupiterSwapIxsForFlashloan({
|
|
43458
|
+
quoteParams: {
|
|
43459
|
+
inputMint: withdrawBank.mint.toBase58(),
|
|
43460
|
+
outputMint: depositBank.mint.toBase58(),
|
|
43461
|
+
amount: uiToNative(totalPositionAmount, withdrawBank.mintDecimals).toNumber(),
|
|
43462
|
+
dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
|
|
43463
|
+
slippageBps: swapOpts.jupiterOptions?.slippageBps,
|
|
43464
|
+
swapMode: "ExactIn",
|
|
43465
|
+
platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
|
|
43466
|
+
onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
|
|
43467
|
+
},
|
|
43468
|
+
authority: marginfiAccount.authority,
|
|
43469
|
+
connection,
|
|
43470
|
+
destinationTokenAccount,
|
|
43471
|
+
configParams: swapOpts.jupiterOptions?.configParams
|
|
43472
|
+
});
|
|
43473
|
+
swapResponses.forEach((response) => {
|
|
43474
|
+
const outAmountThreshold = nativeToUi(
|
|
43475
|
+
response.quoteResponse.otherAmountThreshold,
|
|
43476
|
+
depositBank.mintDecimals
|
|
43477
|
+
);
|
|
43478
|
+
swapResult.push({
|
|
43479
|
+
amountToDeposit: outAmountThreshold,
|
|
43480
|
+
swapInstructions: [response.swapInstruction],
|
|
43481
|
+
setupInstructions: response.setupInstructions,
|
|
43482
|
+
swapLookupTables: response.addressLookupTableAddresses,
|
|
43483
|
+
quoteResponse: response.quoteResponse
|
|
43484
|
+
});
|
|
43485
|
+
});
|
|
43486
|
+
}
|
|
43487
|
+
if (swapResult.length === 0) {
|
|
43488
|
+
throw new Error(
|
|
43489
|
+
`No swap routes found for ${withdrawBank.mint.toBase58()} -> ${depositBank.mint.toBase58()}`
|
|
43490
|
+
);
|
|
43491
|
+
}
|
|
43492
|
+
for (const [index, item] of swapResult.entries()) {
|
|
43493
|
+
const {
|
|
43494
|
+
amountToDeposit,
|
|
43495
|
+
swapInstructions,
|
|
43496
|
+
setupInstructions,
|
|
43497
|
+
swapLookupTables,
|
|
43498
|
+
quoteResponse
|
|
43499
|
+
} = item;
|
|
43500
|
+
let depositIxs;
|
|
43501
|
+
switch (depositBank.config.assetTag) {
|
|
43502
|
+
case 3 /* KAMINO */: {
|
|
43503
|
+
const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
|
|
43504
|
+
if (!reserve) {
|
|
43505
|
+
throw TransactionBuildingError.kaminoReserveNotFound(
|
|
43506
|
+
depositBank.address.toBase58(),
|
|
43507
|
+
depositBank.mint.toBase58(),
|
|
43508
|
+
depositBank.tokenSymbol
|
|
43509
|
+
);
|
|
43510
|
+
}
|
|
43511
|
+
depositIxs = await makeKaminoDepositIx3({
|
|
43512
|
+
program,
|
|
43513
|
+
bank: depositBank,
|
|
43514
|
+
tokenProgram: depositTokenProgram,
|
|
43515
|
+
amount: amountToDeposit,
|
|
43516
|
+
accountAddress: marginfiAccount.address,
|
|
43517
|
+
authority: marginfiAccount.authority,
|
|
43518
|
+
group: marginfiAccount.group,
|
|
43519
|
+
reserve,
|
|
43520
|
+
opts: {
|
|
43521
|
+
wrapAndUnwrapSol: false,
|
|
43522
|
+
overrideInferAccounts
|
|
43523
|
+
}
|
|
43524
|
+
});
|
|
43525
|
+
break;
|
|
43526
|
+
}
|
|
43527
|
+
case 4 /* DRIFT */: {
|
|
43528
|
+
const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
|
|
43529
|
+
if (!driftState) {
|
|
43530
|
+
throw TransactionBuildingError.driftStateNotFound(
|
|
43531
|
+
depositBank.address.toBase58(),
|
|
43532
|
+
depositBank.mint.toBase58(),
|
|
43533
|
+
depositBank.tokenSymbol
|
|
43534
|
+
);
|
|
43535
|
+
}
|
|
43536
|
+
const driftMarketIndex = driftState.spotMarketState.marketIndex;
|
|
43537
|
+
const driftOracle = driftState.spotMarketState.oracle;
|
|
43538
|
+
depositIxs = await makeDriftDepositIx3({
|
|
43539
|
+
program,
|
|
43540
|
+
bank: depositBank,
|
|
43541
|
+
tokenProgram: depositTokenProgram,
|
|
43542
|
+
amount: amountToDeposit,
|
|
43543
|
+
accountAddress: marginfiAccount.address,
|
|
43544
|
+
authority: marginfiAccount.authority,
|
|
43545
|
+
group: marginfiAccount.group,
|
|
43546
|
+
driftMarketIndex,
|
|
43547
|
+
driftOracle,
|
|
43548
|
+
opts: {
|
|
43549
|
+
wrapAndUnwrapSol: false,
|
|
43550
|
+
overrideInferAccounts
|
|
43551
|
+
}
|
|
43552
|
+
});
|
|
43553
|
+
break;
|
|
43554
|
+
}
|
|
43555
|
+
default: {
|
|
43556
|
+
depositIxs = await makeDepositIx3({
|
|
43557
|
+
program,
|
|
43558
|
+
bank: depositBank,
|
|
43559
|
+
tokenProgram: depositTokenProgram,
|
|
43560
|
+
amount: amountToDeposit,
|
|
43561
|
+
accountAddress: marginfiAccount.address,
|
|
43562
|
+
authority: marginfiAccount.authority,
|
|
43563
|
+
group: marginfiAccount.group,
|
|
43564
|
+
opts: {
|
|
43565
|
+
wrapAndUnwrapSol: false,
|
|
43566
|
+
overrideInferAccounts
|
|
43567
|
+
}
|
|
43568
|
+
});
|
|
43569
|
+
break;
|
|
43570
|
+
}
|
|
43571
|
+
}
|
|
43572
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
43573
|
+
const flashloanParams = {
|
|
43574
|
+
program,
|
|
43575
|
+
marginfiAccount,
|
|
43576
|
+
bankMap,
|
|
43577
|
+
addressLookupTableAccounts: luts,
|
|
43578
|
+
blockhash
|
|
43579
|
+
};
|
|
43580
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
43581
|
+
...flashloanParams,
|
|
43582
|
+
ixs: [
|
|
43583
|
+
...cuRequestIxs,
|
|
43584
|
+
...withdrawIxs.instructions,
|
|
43585
|
+
...swapInstructions,
|
|
43586
|
+
...depositIxs.instructions
|
|
43587
|
+
],
|
|
43588
|
+
isSync: true
|
|
43589
|
+
});
|
|
43590
|
+
const txSize = getTxSize(flashloanTx);
|
|
43591
|
+
const keySize = getAccountKeys(flashloanTx, luts);
|
|
43592
|
+
const isLast = index === swapResult.length - 1;
|
|
43593
|
+
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
43594
|
+
if (isLast) {
|
|
43595
|
+
throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
|
|
43596
|
+
} else {
|
|
43597
|
+
continue;
|
|
43598
|
+
}
|
|
43599
|
+
} else {
|
|
43600
|
+
return {
|
|
43601
|
+
flashloanTx,
|
|
43602
|
+
setupInstructions,
|
|
43603
|
+
swapQuote: quoteResponse,
|
|
43604
|
+
withdrawIxs,
|
|
43605
|
+
depositIxs
|
|
43606
|
+
};
|
|
43607
|
+
}
|
|
43608
|
+
}
|
|
43609
|
+
throw new Error("Failed to build swap collateral flashloan tx");
|
|
43610
|
+
}
|
|
43611
|
+
async function makeSwapDebtTx(params) {
|
|
43612
|
+
const {
|
|
43613
|
+
program,
|
|
43614
|
+
marginfiAccount,
|
|
43615
|
+
connection,
|
|
43616
|
+
bankMap,
|
|
43617
|
+
oraclePrices,
|
|
43618
|
+
repayOpts,
|
|
43619
|
+
borrowOpts,
|
|
43620
|
+
bankMetadataMap,
|
|
43621
|
+
addressLookupTableAccounts,
|
|
43622
|
+
crossbarUrl,
|
|
43623
|
+
additionalIxs = []
|
|
43624
|
+
} = params;
|
|
43625
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
43626
|
+
const setupIxs = await makeSetupIx({
|
|
43627
|
+
connection,
|
|
43628
|
+
authority: marginfiAccount.authority,
|
|
43629
|
+
tokens: [
|
|
43630
|
+
{ mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
|
|
43631
|
+
{ mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
|
|
43632
|
+
]
|
|
43633
|
+
});
|
|
43634
|
+
const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
|
|
43635
|
+
marginfiAccount,
|
|
43636
|
+
bankMap,
|
|
43637
|
+
[],
|
|
43638
|
+
// debt can be in a drift bank
|
|
43639
|
+
bankMetadataMap
|
|
43640
|
+
);
|
|
43641
|
+
const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
|
|
43642
|
+
marginfiAccount,
|
|
43643
|
+
bankMap,
|
|
43644
|
+
[repayOpts.repayBank.address, borrowOpts.borrowBank.address],
|
|
43645
|
+
bankMetadataMap
|
|
43646
|
+
);
|
|
43647
|
+
const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
|
|
43648
|
+
...params,
|
|
43649
|
+
blockhash
|
|
43650
|
+
});
|
|
43651
|
+
const jupiterSetupInstructions = setupInstructions.filter((ix) => {
|
|
43652
|
+
if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
|
|
43653
|
+
return false;
|
|
43654
|
+
}
|
|
43655
|
+
if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
|
|
43656
|
+
const mintKey = ix.keys[3]?.pubkey;
|
|
43657
|
+
if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
|
|
43658
|
+
return false;
|
|
43659
|
+
}
|
|
43660
|
+
}
|
|
43661
|
+
return true;
|
|
43662
|
+
});
|
|
43663
|
+
setupIxs.push(...jupiterSetupInstructions);
|
|
43664
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
43665
|
+
marginfiAccount,
|
|
43666
|
+
bankMap,
|
|
43667
|
+
oraclePrices,
|
|
43668
|
+
instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
|
|
43669
|
+
program,
|
|
43670
|
+
connection,
|
|
43671
|
+
crossbarUrl
|
|
43672
|
+
});
|
|
43673
|
+
let additionalTxs = [];
|
|
43674
|
+
if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0) {
|
|
43675
|
+
const ixs = [
|
|
43676
|
+
...additionalIxs,
|
|
43677
|
+
...setupIxs,
|
|
43678
|
+
...kaminoRefreshIxs.instructions,
|
|
43679
|
+
...updateDriftMarketIxs.instructions
|
|
43680
|
+
];
|
|
43681
|
+
const txs = splitInstructionsToFitTransactions([], ixs, {
|
|
43682
|
+
blockhash,
|
|
43683
|
+
payerKey: marginfiAccount.authority,
|
|
43684
|
+
luts: addressLookupTableAccounts ?? []
|
|
43685
|
+
});
|
|
43686
|
+
additionalTxs.push(
|
|
43687
|
+
...txs.map(
|
|
43688
|
+
(tx) => addTransactionMetadata(tx, {
|
|
43689
|
+
type: "CREATE_ATA" /* CREATE_ATA */,
|
|
43690
|
+
addressLookupTables: addressLookupTableAccounts
|
|
43691
|
+
})
|
|
43692
|
+
)
|
|
43693
|
+
);
|
|
43694
|
+
}
|
|
43695
|
+
if (updateFeedIxs.length > 0) {
|
|
43696
|
+
const message = new web3_js.TransactionMessage({
|
|
43697
|
+
payerKey: marginfiAccount.authority,
|
|
43698
|
+
recentBlockhash: blockhash,
|
|
43699
|
+
instructions: updateFeedIxs
|
|
43700
|
+
}).compileToV0Message(feedLuts);
|
|
43701
|
+
additionalTxs.push(
|
|
43702
|
+
addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
43703
|
+
addressLookupTables: feedLuts,
|
|
43704
|
+
type: "CRANK" /* CRANK */
|
|
43705
|
+
})
|
|
43706
|
+
);
|
|
43707
|
+
}
|
|
43708
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
43709
|
+
return {
|
|
43710
|
+
transactions,
|
|
43711
|
+
actionTxIndex: transactions.length - 1,
|
|
43712
|
+
quoteResponse: swapQuote
|
|
43713
|
+
};
|
|
43714
|
+
}
|
|
43715
|
+
async function buildSwapDebtFlashloanTx({
|
|
43716
|
+
program,
|
|
43717
|
+
marginfiAccount,
|
|
43718
|
+
bankMap,
|
|
43719
|
+
repayOpts,
|
|
43720
|
+
borrowOpts,
|
|
43721
|
+
swapOpts,
|
|
43722
|
+
bankMetadataMap,
|
|
43723
|
+
addressLookupTableAccounts,
|
|
43724
|
+
connection,
|
|
43725
|
+
overrideInferAccounts,
|
|
43726
|
+
blockhash
|
|
43727
|
+
}) {
|
|
43728
|
+
const { repayBank, tokenProgram: repayTokenProgram, totalPositionAmount } = repayOpts;
|
|
43729
|
+
const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
|
|
43730
|
+
const swapResult = [];
|
|
43731
|
+
const cuRequestIxs = [
|
|
43732
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
|
|
43733
|
+
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
43734
|
+
];
|
|
43735
|
+
if (borrowBank.mint.equals(repayBank.mint)) {
|
|
43736
|
+
swapResult.push({
|
|
43737
|
+
amountToRepay: totalPositionAmount,
|
|
43738
|
+
borrowAmount: totalPositionAmount,
|
|
43739
|
+
swapInstructions: [],
|
|
43740
|
+
setupInstructions: [],
|
|
43741
|
+
swapLookupTables: []
|
|
43742
|
+
});
|
|
43743
|
+
} else {
|
|
43744
|
+
const destinationTokenAccount = getAssociatedTokenAddressSync(
|
|
43745
|
+
repayBank.mint,
|
|
43746
|
+
marginfiAccount.authority,
|
|
43747
|
+
true,
|
|
43748
|
+
repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
|
|
43749
|
+
);
|
|
43750
|
+
const swapResponses = await getJupiterSwapIxsForFlashloan({
|
|
43751
|
+
quoteParams: {
|
|
43752
|
+
inputMint: borrowBank.mint.toBase58(),
|
|
43753
|
+
outputMint: repayBank.mint.toBase58(),
|
|
43754
|
+
amount: uiToNative(totalPositionAmount, repayBank.mintDecimals).toNumber(),
|
|
43755
|
+
dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
|
|
43756
|
+
slippageBps: swapOpts.jupiterOptions?.slippageBps,
|
|
43757
|
+
swapMode: "ExactOut",
|
|
43758
|
+
platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
|
|
43759
|
+
onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
|
|
43760
|
+
},
|
|
43761
|
+
authority: marginfiAccount.authority,
|
|
43762
|
+
connection,
|
|
43763
|
+
destinationTokenAccount,
|
|
43764
|
+
configParams: swapOpts.jupiterOptions?.configParams
|
|
43765
|
+
});
|
|
43766
|
+
swapResponses.forEach((response) => {
|
|
43767
|
+
const borrowAmount = nativeToUi(response.quoteResponse.inAmount, borrowBank.mintDecimals);
|
|
43768
|
+
swapResult.push({
|
|
43769
|
+
amountToRepay: totalPositionAmount,
|
|
43770
|
+
borrowAmount,
|
|
43771
|
+
swapInstructions: [response.swapInstruction],
|
|
43772
|
+
setupInstructions: response.setupInstructions,
|
|
43773
|
+
swapLookupTables: response.addressLookupTableAddresses,
|
|
43774
|
+
quoteResponse: response.quoteResponse
|
|
43775
|
+
});
|
|
43776
|
+
});
|
|
43777
|
+
}
|
|
43778
|
+
if (swapResult.length === 0) {
|
|
43779
|
+
throw new Error(
|
|
43780
|
+
`No swap routes found for ${borrowBank.mint.toBase58()} -> ${repayBank.mint.toBase58()}`
|
|
43781
|
+
);
|
|
43782
|
+
}
|
|
43783
|
+
for (const [index, item] of swapResult.entries()) {
|
|
43784
|
+
const {
|
|
43785
|
+
amountToRepay,
|
|
43786
|
+
borrowAmount,
|
|
43787
|
+
swapInstructions,
|
|
43788
|
+
setupInstructions,
|
|
43789
|
+
swapLookupTables,
|
|
43790
|
+
quoteResponse
|
|
43791
|
+
} = item;
|
|
43792
|
+
const borrowIxs = await makeBorrowIx3({
|
|
43793
|
+
program,
|
|
43794
|
+
bank: borrowBank,
|
|
43795
|
+
bankMap,
|
|
43796
|
+
tokenProgram: borrowTokenProgram,
|
|
43797
|
+
amount: borrowAmount,
|
|
43798
|
+
marginfiAccount,
|
|
43799
|
+
authority: marginfiAccount.authority,
|
|
43800
|
+
isSync: true,
|
|
43801
|
+
opts: {
|
|
43802
|
+
createAtas: false,
|
|
43803
|
+
wrapAndUnwrapSol: false,
|
|
43804
|
+
overrideInferAccounts
|
|
43805
|
+
}
|
|
43806
|
+
});
|
|
43807
|
+
const repayIxs = await makeRepayIx3({
|
|
43808
|
+
program,
|
|
43809
|
+
bank: repayBank,
|
|
43810
|
+
tokenProgram: repayTokenProgram,
|
|
43811
|
+
amount: amountToRepay,
|
|
43812
|
+
accountAddress: marginfiAccount.address,
|
|
43813
|
+
authority: marginfiAccount.authority,
|
|
43814
|
+
repayAll: isWholePosition(
|
|
43815
|
+
{
|
|
43816
|
+
amount: totalPositionAmount,
|
|
43817
|
+
isLending: false
|
|
43818
|
+
},
|
|
43819
|
+
amountToRepay,
|
|
43820
|
+
repayBank.mintDecimals
|
|
43821
|
+
),
|
|
43822
|
+
isSync: true,
|
|
43823
|
+
opts: {
|
|
43824
|
+
wrapAndUnwrapSol: false,
|
|
43825
|
+
overrideInferAccounts
|
|
43826
|
+
}
|
|
43827
|
+
});
|
|
43828
|
+
const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
|
|
43829
|
+
const flashloanParams = {
|
|
43830
|
+
program,
|
|
43831
|
+
marginfiAccount,
|
|
43832
|
+
bankMap,
|
|
43833
|
+
addressLookupTableAccounts: luts,
|
|
43834
|
+
blockhash
|
|
43835
|
+
};
|
|
43836
|
+
const flashloanTx = await makeFlashLoanTx({
|
|
43837
|
+
...flashloanParams,
|
|
43838
|
+
ixs: [
|
|
43839
|
+
...cuRequestIxs,
|
|
43840
|
+
...borrowIxs.instructions,
|
|
43841
|
+
...swapInstructions,
|
|
43842
|
+
...repayIxs.instructions
|
|
43843
|
+
],
|
|
43844
|
+
isSync: true
|
|
43845
|
+
});
|
|
43846
|
+
const txSize = getTxSize(flashloanTx);
|
|
43847
|
+
const keySize = getAccountKeys(flashloanTx, luts);
|
|
43848
|
+
const isLast = index === swapResult.length - 1;
|
|
43849
|
+
if (txSize > MAX_TX_SIZE || keySize > 64) {
|
|
43850
|
+
if (isLast) {
|
|
43851
|
+
throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
|
|
43852
|
+
} else {
|
|
43853
|
+
continue;
|
|
43854
|
+
}
|
|
43855
|
+
} else {
|
|
43856
|
+
return {
|
|
43857
|
+
flashloanTx,
|
|
43858
|
+
setupInstructions,
|
|
43859
|
+
swapQuote: quoteResponse,
|
|
43860
|
+
borrowIxs,
|
|
43861
|
+
repayIxs
|
|
43862
|
+
};
|
|
43863
|
+
}
|
|
43864
|
+
}
|
|
43865
|
+
throw new Error("Failed to build swap debt flashloan tx");
|
|
43866
|
+
}
|
|
43867
|
+
|
|
43868
|
+
// src/services/account/services/account-simulation.service.ts
|
|
43869
|
+
async function simulateAccountHealthCacheWithFallback(props) {
|
|
43870
|
+
let marginfiAccount = props.marginfiAccount;
|
|
43871
|
+
const activeBalances = marginfiAccount.balances.filter((b) => b.active);
|
|
43872
|
+
const { assets: assetValueEquity, liabilities: liabilityValueEquity } = computeHealthComponentsWithoutBiasLegacy(
|
|
43873
|
+
activeBalances,
|
|
43874
|
+
props.bankMap,
|
|
43875
|
+
props.oraclePrices,
|
|
43876
|
+
2 /* Equity */
|
|
43877
|
+
);
|
|
43878
|
+
try {
|
|
43879
|
+
const simulatedAccount = await simulateAccountHealthCache({
|
|
43880
|
+
program: props.program,
|
|
43881
|
+
bankMap: props.bankMap,
|
|
43882
|
+
marginfiAccount: props.marginfiAccount,
|
|
43883
|
+
bankMetadataMap: props.bankMetadataMap
|
|
43884
|
+
});
|
|
43885
|
+
simulatedAccount.healthCache.assetValueEquity = bigNumberToWrappedI80F48(assetValueEquity);
|
|
43886
|
+
simulatedAccount.healthCache.liabilityValueEquity = bigNumberToWrappedI80F48(liabilityValueEquity);
|
|
43887
|
+
marginfiAccount = parseMarginfiAccountRaw(props.marginfiAccount.address, simulatedAccount);
|
|
43888
|
+
} catch (e) {
|
|
43889
|
+
console.log("e", e);
|
|
43890
|
+
const { assets: assetValueMaint, liabilities: liabilityValueMaint } = computeHealthComponentsLegacy(
|
|
43891
|
+
activeBalances,
|
|
43892
|
+
props.bankMap,
|
|
43893
|
+
props.oraclePrices,
|
|
43894
|
+
1 /* Maintenance */,
|
|
43895
|
+
[]
|
|
43896
|
+
);
|
|
43897
|
+
const { assets: assetValueInitial, liabilities: liabilityValueInitial } = computeHealthComponentsLegacy(
|
|
43898
|
+
activeBalances,
|
|
43899
|
+
props.bankMap,
|
|
43900
|
+
props.oraclePrices,
|
|
43901
|
+
0 /* Initial */,
|
|
43902
|
+
[]
|
|
43903
|
+
);
|
|
43904
|
+
marginfiAccount.healthCache = {
|
|
43905
|
+
assetValue: assetValueInitial,
|
|
43906
|
+
liabilityValue: liabilityValueInitial,
|
|
43907
|
+
assetValueMaint,
|
|
43908
|
+
liabilityValueMaint,
|
|
43909
|
+
assetValueEquity,
|
|
43910
|
+
liabilityValueEquity,
|
|
43911
|
+
timestamp: new BigNumber10__default.default(0),
|
|
43912
|
+
flags: [],
|
|
43913
|
+
prices: [],
|
|
43914
|
+
simulationStatus: 2 /* COMPUTED */
|
|
43915
|
+
};
|
|
43916
|
+
if (e instanceof HealthCacheSimulationError) {
|
|
43917
|
+
return { marginfiAccount, error: e };
|
|
43918
|
+
}
|
|
43919
|
+
}
|
|
43920
|
+
return { marginfiAccount };
|
|
43921
|
+
}
|
|
43922
|
+
async function simulateAccountHealthCache(props) {
|
|
43923
|
+
const { program, bankMap, marginfiAccount, bankMetadataMap } = props;
|
|
43924
|
+
const activeBalances = marginfiAccount.balances.filter((b) => b.active);
|
|
43925
|
+
const activeBanks = activeBalances.map((balance) => bankMap.get(balance.bankPk.toBase58())).filter((bank) => !!bank);
|
|
43926
|
+
const kaminoBanks = activeBanks.filter((bank) => bank.config.assetTag === 3 /* KAMINO */);
|
|
43927
|
+
const driftBanks = activeBanks.filter((bank) => bank.config.assetTag === 4 /* DRIFT */);
|
|
43928
|
+
const staleSwbOracles = activeBanks.filter(
|
|
43929
|
+
(bank) => bank.config.oracleSetup === "SwitchboardPull" /* SwitchboardPull */ || bank.config.oracleSetup === "SwitchboardV2" /* SwitchboardV2 */ || bank.config.oracleSetup === "KaminoSwitchboardPull" /* KaminoSwitchboardPull */ || bank.config.oracleSetup === "DriftSwitchboardPull" /* DriftSwitchboardPull */ || bank.config.oracleSetup === "SolendSwitchboardPull" /* SolendSwitchboardPull */
|
|
43930
|
+
).filter((bank) => !bank.oracleKey.equals(new web3_js.PublicKey(ZERO_ORACLE_KEY)));
|
|
43931
|
+
const computeIx = web3_js.ComputeBudgetProgram.setComputeUnitLimit({
|
|
43932
|
+
units: 14e5
|
|
43933
|
+
});
|
|
43934
|
+
const blockhash = (await program.provider.connection.getLatestBlockhash("confirmed")).blockhash;
|
|
43935
|
+
const fundAccountIx = web3_js.SystemProgram.transfer({
|
|
43936
|
+
fromPubkey: new web3_js.PublicKey("DD3AeAssFvjqTvRTrRAtpfjkBF8FpVKnFuwnMLN9haXD"),
|
|
43937
|
+
// marginfi SOL VAULT
|
|
43938
|
+
toPubkey: marginfiAccount.authority,
|
|
43939
|
+
lamports: 1e8
|
|
43940
|
+
// 0.1 SOL
|
|
43941
|
+
});
|
|
43942
|
+
const updateDriftMarketData = driftBanks.map((bank) => {
|
|
43943
|
+
const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
|
|
43944
|
+
if (!bankMetadata?.driftStates) {
|
|
43945
|
+
console.error(`Bank metadata for drift bank ${bank.address.toBase58()} not found`);
|
|
43946
|
+
return;
|
|
43947
|
+
}
|
|
43948
|
+
const driftMarket = bankMetadata.driftStates.spotMarketState;
|
|
43949
|
+
return driftMarket;
|
|
43950
|
+
}).filter((state) => !!state);
|
|
43951
|
+
const refreshReserveData = kaminoBanks.map((bank) => {
|
|
43952
|
+
const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
|
|
43953
|
+
if (!bankMetadata?.kaminoStates) {
|
|
43954
|
+
console.error(`Bank metadata for kamino bank ${bank.address.toBase58()} not found`);
|
|
43955
|
+
return;
|
|
43956
|
+
}
|
|
43957
|
+
if (!bankMetadata?.kaminoStates || !bank.kaminoIntegrationAccounts) {
|
|
43958
|
+
console.error(`Integration data for kamino bank ${bank.address.toBase58()} not found`);
|
|
43959
|
+
return;
|
|
43960
|
+
}
|
|
43961
|
+
const kaminoReserve = bank.kaminoIntegrationAccounts.kaminoReserve;
|
|
43962
|
+
const lendingMarket = bankMetadata.kaminoStates.reserveState.lendingMarket;
|
|
43963
|
+
return {
|
|
43338
43964
|
reserve: kaminoReserve,
|
|
43339
43965
|
lendingMarket
|
|
43340
43966
|
};
|
|
@@ -43348,7 +43974,7 @@ async function simulateAccountHealthCache(props) {
|
|
|
43348
43974
|
swbPullOracles: staleSwbOracles.map((oracle) => ({
|
|
43349
43975
|
key: oracle.oracleKey
|
|
43350
43976
|
})),
|
|
43351
|
-
feePayer:
|
|
43977
|
+
feePayer: marginfiAccount.authority,
|
|
43352
43978
|
connection: program.provider.connection
|
|
43353
43979
|
}) : { instructions: [], luts: [] };
|
|
43354
43980
|
const updateDriftMarketIxs = updateDriftMarketData.map((market) => ({
|
|
@@ -43358,16 +43984,16 @@ async function simulateAccountHealthCache(props) {
|
|
|
43358
43984
|
}));
|
|
43359
43985
|
const healthPulseIxs = await makePulseHealthIx2(
|
|
43360
43986
|
program,
|
|
43361
|
-
|
|
43987
|
+
marginfiAccount.address,
|
|
43362
43988
|
bankMap,
|
|
43363
|
-
balances,
|
|
43989
|
+
marginfiAccount.balances,
|
|
43364
43990
|
activeBalances.map((b) => b.bankPk),
|
|
43365
43991
|
[]
|
|
43366
43992
|
);
|
|
43367
43993
|
const txs = [];
|
|
43368
43994
|
const additionalTx = new web3_js.VersionedTransaction(
|
|
43369
43995
|
new web3_js.TransactionMessage({
|
|
43370
|
-
payerKey:
|
|
43996
|
+
payerKey: marginfiAccount.authority,
|
|
43371
43997
|
recentBlockhash: blockhash,
|
|
43372
43998
|
instructions: [
|
|
43373
43999
|
computeIx,
|
|
@@ -43380,7 +44006,7 @@ async function simulateAccountHealthCache(props) {
|
|
|
43380
44006
|
txs.push(additionalTx);
|
|
43381
44007
|
const swbTx = new web3_js.VersionedTransaction(
|
|
43382
44008
|
new web3_js.TransactionMessage({
|
|
43383
|
-
payerKey:
|
|
44009
|
+
payerKey: marginfiAccount.authority,
|
|
43384
44010
|
recentBlockhash: blockhash,
|
|
43385
44011
|
instructions: [...crankSwbIxs.instructions]
|
|
43386
44012
|
}).compileToV0Message([...crankSwbIxs.luts])
|
|
@@ -43388,7 +44014,7 @@ async function simulateAccountHealthCache(props) {
|
|
|
43388
44014
|
txs.push(swbTx);
|
|
43389
44015
|
const healthTx = new web3_js.VersionedTransaction(
|
|
43390
44016
|
new web3_js.TransactionMessage({
|
|
43391
|
-
payerKey:
|
|
44017
|
+
payerKey: marginfiAccount.authority,
|
|
43392
44018
|
recentBlockhash: blockhash,
|
|
43393
44019
|
instructions: [computeIx, ...healthPulseIxs.instructions]
|
|
43394
44020
|
}).compileToV0Message([])
|
|
@@ -43399,7 +44025,7 @@ async function simulateAccountHealthCache(props) {
|
|
|
43399
44025
|
throw new Error("Too many transactions");
|
|
43400
44026
|
}
|
|
43401
44027
|
const simulationResult = await simulateBundle(program.provider.connection.rpcEndpoint, txs, [
|
|
43402
|
-
|
|
44028
|
+
marginfiAccount.address
|
|
43403
44029
|
]);
|
|
43404
44030
|
const postExecutionAccount = simulationResult.find(
|
|
43405
44031
|
(result) => result.postExecutionAccounts.length > 0
|
|
@@ -43614,23 +44240,19 @@ var fetchMarginfiAccountAddresses = async (program, authority, group) => {
|
|
|
43614
44240
|
return marginfiAccounts;
|
|
43615
44241
|
};
|
|
43616
44242
|
var fetchMarginfiAccountData = async (program, marginfiAccountPk, bankMap, bankMetadataMap) => {
|
|
43617
|
-
const marginfiAccountRaw = await program.account.marginfiAccount.fetch(
|
|
43618
|
-
const marginfiAccount = parseMarginfiAccountRaw(
|
|
44243
|
+
const marginfiAccountRaw = await program.account.marginfiAccount.fetch(
|
|
43619
44244
|
marginfiAccountPk,
|
|
43620
|
-
|
|
44245
|
+
"confirmed"
|
|
43621
44246
|
);
|
|
44247
|
+
const marginfiAccount = parseMarginfiAccountRaw(marginfiAccountPk, marginfiAccountRaw);
|
|
43622
44248
|
try {
|
|
43623
44249
|
const simulatedAccount = await simulateAccountHealthCache({
|
|
43624
44250
|
program,
|
|
43625
44251
|
bankMap,
|
|
43626
|
-
|
|
43627
|
-
balances: marginfiAccount.balances,
|
|
44252
|
+
marginfiAccount,
|
|
43628
44253
|
bankMetadataMap
|
|
43629
44254
|
});
|
|
43630
|
-
const marginfiAccountWithCache = parseMarginfiAccountRaw(
|
|
43631
|
-
marginfiAccountPk,
|
|
43632
|
-
simulatedAccount
|
|
43633
|
-
);
|
|
44255
|
+
const marginfiAccountWithCache = parseMarginfiAccountRaw(marginfiAccountPk, simulatedAccount);
|
|
43634
44256
|
return { marginfiAccount: marginfiAccountWithCache };
|
|
43635
44257
|
} catch (e) {
|
|
43636
44258
|
console.error("Error simulating account health cache", e);
|
|
@@ -43652,10 +44274,7 @@ async function findRandomAvailableAccountIndex(connection, programId, group, aut
|
|
|
43652
44274
|
const BATCH_SIZE = 16;
|
|
43653
44275
|
const MAX_ATTEMPTS = 8;
|
|
43654
44276
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
43655
|
-
const indices = randomDistinctIndices(
|
|
43656
|
-
Math.min(BATCH_SIZE, MAX_INDEX),
|
|
43657
|
-
MAX_INDEX
|
|
43658
|
-
);
|
|
44277
|
+
const indices = randomDistinctIndices(Math.min(BATCH_SIZE, MAX_INDEX), MAX_INDEX);
|
|
43659
44278
|
const pdas = indices.map(
|
|
43660
44279
|
(i) => deriveMarginfiAccount(programId, group, authority, i, thirdPartyId)[0]
|
|
43661
44280
|
);
|
|
@@ -43843,6 +44462,7 @@ var getJupiterSwapIxsForFlashloan = async ({
|
|
|
43843
44462
|
});
|
|
43844
44463
|
})
|
|
43845
44464
|
);
|
|
44465
|
+
hasFeeAccount && finalQuoteParams.platformFeeBps && finalQuoteParams.platformFeeBps > 0;
|
|
43846
44466
|
const swapInstructionResponses = await Promise.all(
|
|
43847
44467
|
swapQuotes.map(
|
|
43848
44468
|
(quote) => jupiterApiClient.swapInstructionsPost({
|
|
@@ -43867,7 +44487,6 @@ var getJupiterSwapIxsForFlashloan = async ({
|
|
|
43867
44487
|
for (let i = 0; i < swapInstructionResponses.length; i++) {
|
|
43868
44488
|
const response = swapInstructionResponses[i];
|
|
43869
44489
|
const quote = swapQuotes[i];
|
|
43870
|
-
i === swapInstructionResponses.length - 1;
|
|
43871
44490
|
if (!response || !quote) continue;
|
|
43872
44491
|
const address = response.addressLookupTableAddresses;
|
|
43873
44492
|
const addressesLength = address.length;
|
|
@@ -46460,7 +47079,6 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
46460
47079
|
bankMap,
|
|
46461
47080
|
oraclePrices,
|
|
46462
47081
|
marginfiAccount: this,
|
|
46463
|
-
balances: this.balances,
|
|
46464
47082
|
bankMetadataMap
|
|
46465
47083
|
});
|
|
46466
47084
|
return {
|
|
@@ -47009,6 +47627,75 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
47009
47627
|
marginfiAccount: this
|
|
47010
47628
|
});
|
|
47011
47629
|
}
|
|
47630
|
+
/**
|
|
47631
|
+
* Creates a transaction to swap one collateral position to another using a flash loan.
|
|
47632
|
+
*
|
|
47633
|
+
* A swap collateral transaction:
|
|
47634
|
+
* 1. Withdraws existing collateral via flash loan
|
|
47635
|
+
* 2. Swaps collateral to new asset (via Jupiter)
|
|
47636
|
+
* 3. Deposits swapped assets as new collateral
|
|
47637
|
+
*
|
|
47638
|
+
* This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
|
|
47639
|
+
* withdrawing and affecting their health during the swap.
|
|
47640
|
+
*
|
|
47641
|
+
* @param params - Swap collateral transaction parameters
|
|
47642
|
+
* @param params.connection - Solana connection instance
|
|
47643
|
+
* @param params.oraclePrices - Map of current oracle prices
|
|
47644
|
+
* @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
|
|
47645
|
+
* @param params.depositOpts - Deposit configuration (bank, tokenProgram)
|
|
47646
|
+
* @param params.swapOpts - Jupiter swap configuration
|
|
47647
|
+
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
47648
|
+
* @param params.overrideInferAccounts - Optional account overrides
|
|
47649
|
+
* @param params.additionalIxs - Additional instructions to include
|
|
47650
|
+
* @param params.crossbarUrl - Crossbar URL for oracle updates
|
|
47651
|
+
*
|
|
47652
|
+
* @returns Object containing transactions array, action index, and swap quote
|
|
47653
|
+
*
|
|
47654
|
+
* @throws {TransactionBuildingError} If swap exceeds transaction size limits
|
|
47655
|
+
* @throws {TransactionBuildingError} If Kamino reserve not found
|
|
47656
|
+
*
|
|
47657
|
+
* @see {@link makeSwapCollateralTx} for detailed implementation
|
|
47658
|
+
*/
|
|
47659
|
+
async makeSwapCollateralTx(params) {
|
|
47660
|
+
return makeSwapCollateralTx({
|
|
47661
|
+
...params,
|
|
47662
|
+
marginfiAccount: this
|
|
47663
|
+
});
|
|
47664
|
+
}
|
|
47665
|
+
/**
|
|
47666
|
+
* Creates a transaction to swap one debt position to another using a flash loan.
|
|
47667
|
+
*
|
|
47668
|
+
* A swap debt transaction:
|
|
47669
|
+
* 1. Borrows new asset via flash loan (new debt)
|
|
47670
|
+
* 2. Swaps new asset to old debt asset (via Jupiter)
|
|
47671
|
+
* 3. Repays old debt with swapped assets
|
|
47672
|
+
*
|
|
47673
|
+
* This allows users to change their debt type (e.g., USDC debt -> SOL debt) without
|
|
47674
|
+
* repaying and affecting their health during the swap.
|
|
47675
|
+
*
|
|
47676
|
+
* @param params - Swap debt transaction parameters
|
|
47677
|
+
* @param params.connection - Solana connection instance
|
|
47678
|
+
* @param params.oraclePrices - Map of current oracle prices
|
|
47679
|
+
* @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
|
|
47680
|
+
* @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
|
|
47681
|
+
* @param params.swapOpts - Jupiter swap configuration
|
|
47682
|
+
* @param params.addressLookupTableAccounts - Address lookup tables
|
|
47683
|
+
* @param params.overrideInferAccounts - Optional account overrides
|
|
47684
|
+
* @param params.additionalIxs - Additional instructions to include
|
|
47685
|
+
* @param params.crossbarUrl - Crossbar URL for oracle updates
|
|
47686
|
+
*
|
|
47687
|
+
* @returns Object containing transactions array, action index, and swap quote
|
|
47688
|
+
*
|
|
47689
|
+
* @throws {TransactionBuildingError} If swap exceeds transaction size limits
|
|
47690
|
+
*
|
|
47691
|
+
* @see {@link makeSwapDebtTx} for detailed implementation
|
|
47692
|
+
*/
|
|
47693
|
+
async makeSwapDebtTx(params) {
|
|
47694
|
+
return makeSwapDebtTx({
|
|
47695
|
+
...params,
|
|
47696
|
+
marginfiAccount: this
|
|
47697
|
+
});
|
|
47698
|
+
}
|
|
47012
47699
|
/**
|
|
47013
47700
|
* Creates a deposit transaction.
|
|
47014
47701
|
*
|
|
@@ -47436,6 +48123,50 @@ var MarginfiAccountWrapper = class {
|
|
|
47436
48123
|
};
|
|
47437
48124
|
return this.account.makeRepayWithCollatTx(fullParams);
|
|
47438
48125
|
}
|
|
48126
|
+
/**
|
|
48127
|
+
* Creates a swap collateral transaction with auto-injected client data.
|
|
48128
|
+
*
|
|
48129
|
+
* Swaps one collateral type for another (e.g., JitoSOL -> mSOL) using a flash loan
|
|
48130
|
+
* so account health is not affected during the swap.
|
|
48131
|
+
*
|
|
48132
|
+
* Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap, addressLookupTables
|
|
48133
|
+
*
|
|
48134
|
+
* @param params - Swap collateral parameters (user provides: connection, withdrawOpts, depositOpts, swapOpts, etc.)
|
|
48135
|
+
*/
|
|
48136
|
+
async makeSwapCollateralTx(params) {
|
|
48137
|
+
const fullParams = {
|
|
48138
|
+
...params,
|
|
48139
|
+
program: this.client.program,
|
|
48140
|
+
marginfiAccount: this.account,
|
|
48141
|
+
bankMap: this.client.bankMap,
|
|
48142
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
48143
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
48144
|
+
addressLookupTableAccounts: this.client.addressLookupTables
|
|
48145
|
+
};
|
|
48146
|
+
return this.account.makeSwapCollateralTx(fullParams);
|
|
48147
|
+
}
|
|
48148
|
+
/**
|
|
48149
|
+
* Creates a swap debt transaction with auto-injected client data.
|
|
48150
|
+
*
|
|
48151
|
+
* Swaps one debt type for another (e.g., USDC debt -> SOL debt) using a flash loan
|
|
48152
|
+
* so account health is not affected during the swap.
|
|
48153
|
+
*
|
|
48154
|
+
* Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap, addressLookupTables
|
|
48155
|
+
*
|
|
48156
|
+
* @param params - Swap debt parameters (user provides: connection, repayOpts, borrowOpts, swapOpts, etc.)
|
|
48157
|
+
*/
|
|
48158
|
+
async makeSwapDebtTx(params) {
|
|
48159
|
+
const fullParams = {
|
|
48160
|
+
...params,
|
|
48161
|
+
program: this.client.program,
|
|
48162
|
+
marginfiAccount: this.account,
|
|
48163
|
+
bankMap: this.client.bankMap,
|
|
48164
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
48165
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
48166
|
+
addressLookupTableAccounts: this.client.addressLookupTables
|
|
48167
|
+
};
|
|
48168
|
+
return this.account.makeSwapDebtTx(fullParams);
|
|
48169
|
+
}
|
|
47439
48170
|
/**
|
|
47440
48171
|
* Creates a deposit transaction with auto-injected client data.
|
|
47441
48172
|
*
|
|
@@ -47902,16 +48633,23 @@ var Project0Client = class _Project0Client {
|
|
|
47902
48633
|
* @param accountAddress - The public key of the marginfi account
|
|
47903
48634
|
* @returns A wrapped account ready to use
|
|
47904
48635
|
*/
|
|
47905
|
-
async fetchAccount(accountAddress) {
|
|
47906
|
-
const
|
|
47907
|
-
|
|
47908
|
-
this.program,
|
|
48636
|
+
async fetchAccount(accountAddress, skipHealthCache) {
|
|
48637
|
+
const marginfiAccountRaw = await this.program.account.marginfiAccount.fetch(accountAddress);
|
|
48638
|
+
let marginfiAccountParsed = MarginfiAccount.fromAccountParsed(
|
|
47909
48639
|
accountAddress,
|
|
47910
|
-
|
|
47911
|
-
this.bankIntegrationMap
|
|
48640
|
+
marginfiAccountRaw
|
|
47912
48641
|
);
|
|
47913
|
-
|
|
47914
|
-
|
|
48642
|
+
if (!skipHealthCache) {
|
|
48643
|
+
const bankMap = new Map(this.banks.map((b) => [b.address.toBase58(), b]));
|
|
48644
|
+
const { account: simulatedAccount } = await marginfiAccountParsed.simulateHealthCache(
|
|
48645
|
+
this.program,
|
|
48646
|
+
bankMap,
|
|
48647
|
+
this.oraclePriceByBank,
|
|
48648
|
+
this.bankIntegrationMap
|
|
48649
|
+
);
|
|
48650
|
+
marginfiAccountParsed = simulatedAccount;
|
|
48651
|
+
}
|
|
48652
|
+
return new MarginfiAccountWrapper(marginfiAccountParsed, this);
|
|
47915
48653
|
}
|
|
47916
48654
|
static async initialize(connection, config) {
|
|
47917
48655
|
const { groupPk, programId } = config;
|
|
@@ -48269,6 +49007,8 @@ exports.makeRepayTx = makeRepayTx;
|
|
|
48269
49007
|
exports.makeRepayWithCollatTx = makeRepayWithCollatTx;
|
|
48270
49008
|
exports.makeSetupIx = makeSetupIx;
|
|
48271
49009
|
exports.makeSmartCrankSwbFeedIx = makeSmartCrankSwbFeedIx;
|
|
49010
|
+
exports.makeSwapCollateralTx = makeSwapCollateralTx;
|
|
49011
|
+
exports.makeSwapDebtTx = makeSwapDebtTx;
|
|
48272
49012
|
exports.makeTxPriorityIx = makeTxPriorityIx;
|
|
48273
49013
|
exports.makeUnwrapSolIx = makeUnwrapSolIx;
|
|
48274
49014
|
exports.makeUpdateDriftMarketIxs = makeUpdateDriftMarketIxs;
|