@0dotxyz/p0-ts-sdk 2.5.5-alpha.1 → 2.5.5-alpha.3

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 CHANGED
@@ -69954,26 +69954,9 @@ var CU_IXS = () => [
69954
69954
  web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 }),
69955
69955
  web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
69956
69956
  ];
69957
- function requireBank(bankMap, address) {
69958
- const bank = bankMap.get(address.toBase58());
69959
- if (!bank) {
69960
- throw TransactionBuildingError.transferPositionsInvalidSelection(
69961
- `bank ${address.toBase58()} not found`,
69962
- [address.toBase58()]
69963
- );
69964
- }
69965
- return bank;
69966
- }
69967
- function requireTokenProgram(tokenProgramsByBank, address) {
69968
- const tp = tokenProgramsByBank.get(address.toBase58());
69969
- if (!tp) {
69970
- throw TransactionBuildingError.transferPositionsInvalidSelection(
69971
- `token program for bank ${address.toBase58()} not provided`,
69972
- [address.toBase58()]
69973
- );
69974
- }
69975
- return tp;
69976
- }
69957
+ var invalidSelection = (address) => (message) => TransactionBuildingError.transferPositionsInvalidSelection(message, [
69958
+ address.toBase58()
69959
+ ]);
69977
69960
  function classifyAndValidate(params) {
69978
69961
  const {
69979
69962
  marginfiAccount: accountA,
@@ -69996,8 +69979,8 @@ function classifyAndValidate(params) {
69996
69979
  const activeBalancesA = accountA.balances.filter((b) => b.active);
69997
69980
  const positions = [];
69998
69981
  for (const bankAddress of bankAddresses) {
69999
- const bank = requireBank(bankMap, bankAddress);
70000
- const tokenProgram = requireTokenProgram(tokenProgramsByBank, bankAddress);
69982
+ const bank = requireBank(bankMap, bankAddress, invalidSelection(bankAddress));
69983
+ const tokenProgram = requireTokenProgram(tokenProgramsByBank, bankAddress, invalidSelection(bankAddress));
70001
69984
  const balance = activeBalancesA.find((b) => b.bankPk.equals(bankAddress));
70002
69985
  if (!balance) {
70003
69986
  throw TransactionBuildingError.transferPositionsInvalidSelection(
@@ -70362,7 +70345,7 @@ async function makeTransferPositionsTx(params) {
70362
70345
  const innerIxs = await buildInnerIxs(ctx, positions, false);
70363
70346
  const transferred = new Set(positions.map((p) => p.bankAddress.toBase58()));
70364
70347
  const projectedActiveBanksA = dedupeBanks(
70365
- accountA.balances.filter((b) => b.active && !transferred.has(b.bankPk.toBase58())).map((b) => requireBank(bankMap, b.bankPk))
70348
+ accountA.balances.filter((b) => b.active && !transferred.has(b.bankPk.toBase58())).map((b) => requireBank(bankMap, b.bankPk, invalidSelection(b.bankPk)))
70366
70349
  );
70367
70350
  const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
70368
70351
  const preIxs = createIx ? [createIx] : [];
@@ -70410,8 +70393,15 @@ async function makeTransferPositionsTx(params) {
70410
70393
  )
70411
70394
  );
70412
70395
  }
70396
+ const destinationOnlyBalances = accountB.balances.filter(
70397
+ (b) => b.active && !accountA.balances.some((a) => a.active && a.bankPk.equals(b.bankPk))
70398
+ );
70399
+ const crankBalanceView = {
70400
+ ...accountA,
70401
+ balances: [...accountA.balances, ...destinationOnlyBalances]
70402
+ };
70413
70403
  const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
70414
- marginfiAccount: accountA,
70404
+ marginfiAccount: crankBalanceView,
70415
70405
  bankMap,
70416
70406
  oraclePrices,
70417
70407
  assetShareValueMultiplierByBank,
@@ -70440,6 +70430,301 @@ async function makeTransferPositionsTx(params) {
70440
70430
  destinationAccount: accountB
70441
70431
  };
70442
70432
  }
70433
+ var BULK_TX_SIZE_MARGIN = 128;
70434
+ function computeV0TxSizeSafe(ixs, payer, luts) {
70435
+ try {
70436
+ return computeV0TxSize(ixs, payer, luts);
70437
+ } catch {
70438
+ return { size: Number.MAX_SAFE_INTEGER, accountCount: Number.MAX_SAFE_INTEGER };
70439
+ }
70440
+ }
70441
+ function fitsInTx(ixs, payer, luts) {
70442
+ const { size, accountCount } = computeV0TxSizeSafe(ixs, payer, luts);
70443
+ return size <= MAX_TX_SIZE - BULK_TX_SIZE_MARGIN && accountCount <= MAX_ACCOUNT_LOCKS;
70444
+ }
70445
+ function buildTxRefreshIxs(args) {
70446
+ const { marginfiAccount, bankMap, bankMetadataMap, txBanks } = args;
70447
+ const ixs = [];
70448
+ const kaminoPks = txBanks.filter((b) => b.config.assetTag === 3 /* KAMINO */).map((b) => b.address);
70449
+ if (kaminoPks.length > 0) {
70450
+ ixs.push(
70451
+ ...makeRefreshKaminoBanksIxs(marginfiAccount, bankMap, kaminoPks, bankMetadataMap).instructions
70452
+ );
70453
+ }
70454
+ const jupPksInTx = txBanks.filter((b) => b.config.assetTag === 6 /* JUPLEND */).map((b) => b.address);
70455
+ if (jupPksInTx.length > 0) {
70456
+ ixs.push(
70457
+ ...makeUpdateJupLendRateIxs(marginfiAccount, bankMap, jupPksInTx, bankMetadataMap).instructions
70458
+ );
70459
+ }
70460
+ return ixs;
70461
+ }
70462
+ async function makeBulkWithdrawTx(params) {
70463
+ const {
70464
+ program,
70465
+ connection,
70466
+ marginfiAccount,
70467
+ bankAddresses,
70468
+ bankMap,
70469
+ bankMetadataMap,
70470
+ oraclePrices,
70471
+ assetShareValueMultiplierByBank,
70472
+ tokenProgramsByBank,
70473
+ overrideInferAccounts
70474
+ } = params;
70475
+ const luts = params.addressLookupTableAccounts ?? [];
70476
+ const groupRateLimiterEnabled = params.groupRateLimiterEnabled ?? false;
70477
+ const authority = marginfiAccount.authority;
70478
+ if (bankAddresses.length === 0) throw new Error("no banks to withdraw");
70479
+ const activeBalances = marginfiAccount.balances.filter((b) => b.active);
70480
+ const legs = [];
70481
+ const withdrawnSoFar = [];
70482
+ for (const bankAddress of bankAddresses) {
70483
+ const bank = requireBank(bankMap, bankAddress);
70484
+ const tokenProgram = requireTokenProgram(tokenProgramsByBank, bankAddress);
70485
+ const balance = activeBalances.find((b) => b.bankPk.equals(bankAddress));
70486
+ if (!balance || !balance.assetShares.gt(0)) {
70487
+ throw new Error(`no active deposit for bank ${bankAddress.toBase58()}`);
70488
+ }
70489
+ const multiplier = assetShareValueMultiplierByBank.get(bankAddress.toBase58());
70490
+ const uiAmount = computeQuantityUi(balance, bank, multiplier).assets;
70491
+ const packBanks = computeHealthCheckAccounts(
70492
+ marginfiAccount.balances,
70493
+ bankMap,
70494
+ [],
70495
+ [...withdrawnSoFar, bankAddress]
70496
+ );
70497
+ const observationBanksOverride = computeHealthAccountMetas(packBanks, true, [bank]);
70498
+ const shared = {
70499
+ program,
70500
+ bank,
70501
+ bankMap,
70502
+ tokenProgram,
70503
+ marginfiAccount,
70504
+ authority,
70505
+ bankMetadataMap,
70506
+ withdrawAll: true,
70507
+ opts: {
70508
+ createAtas: false,
70509
+ // ATAs are created in the prelude txs
70510
+ wrapAndUnwrapSol: true,
70511
+ overrideInferAccounts,
70512
+ observationBanksOverride
70513
+ }
70514
+ };
70515
+ let instructions2;
70516
+ switch (bank.config.assetTag) {
70517
+ case 3 /* KAMINO */: {
70518
+ const reserve = bankMetadataMap[bankAddress.toBase58()]?.kaminoStates?.reserveState;
70519
+ if (!reserve) {
70520
+ throw new Error(`kamino reserve state missing for bank ${bankAddress.toBase58()}`);
70521
+ }
70522
+ const withdraw = await makeKaminoWithdrawIx3({
70523
+ ...shared,
70524
+ cTokenAmount: uiAmount.div(multiplier ?? new BigNumber3.BigNumber(1)),
70525
+ reserve
70526
+ });
70527
+ instructions2 = withdraw.instructions;
70528
+ break;
70529
+ }
70530
+ case 6 /* JUPLEND */: {
70531
+ const jupLendingState = bankMetadataMap[bankAddress.toBase58()]?.jupLendStates?.jupLendingState;
70532
+ if (!jupLendingState) {
70533
+ throw new Error(`juplend lending state missing for bank ${bankAddress.toBase58()}`);
70534
+ }
70535
+ const withdraw = await makeJuplendWithdrawIx2({
70536
+ ...shared,
70537
+ amount: uiAmount,
70538
+ jupLendingState
70539
+ });
70540
+ instructions2 = withdraw.instructions;
70541
+ break;
70542
+ }
70543
+ case 4 /* DRIFT */: {
70544
+ const driftState = bankMetadataMap[bankAddress.toBase58()]?.driftStates;
70545
+ if (!driftState) {
70546
+ throw new Error(`drift state missing for bank ${bankAddress.toBase58()}`);
70547
+ }
70548
+ const withdraw = await makeDriftWithdrawIx3({
70549
+ ...shared,
70550
+ amount: uiAmount,
70551
+ driftSpotMarket: driftState.spotMarketState,
70552
+ userRewards: driftState.userRewards
70553
+ });
70554
+ instructions2 = withdraw.instructions;
70555
+ break;
70556
+ }
70557
+ default: {
70558
+ const withdraw = await makeWithdrawIx3({
70559
+ ...shared,
70560
+ amount: uiAmount
70561
+ });
70562
+ instructions2 = withdraw.instructions;
70563
+ break;
70564
+ }
70565
+ }
70566
+ legs.push({ bank, instructions: instructions2 });
70567
+ withdrawnSoFar.push(bankAddress);
70568
+ }
70569
+ const bundles = [];
70570
+ let current = [];
70571
+ const assembleTxIxs = (bundle) => [
70572
+ ...buildTxRefreshIxs({
70573
+ marginfiAccount,
70574
+ bankMap,
70575
+ bankMetadataMap,
70576
+ txBanks: bundle.map((l) => l.bank)
70577
+ }),
70578
+ ...bundle.flatMap((l) => l.instructions)
70579
+ ];
70580
+ for (const leg of legs) {
70581
+ const candidate = [...current, leg];
70582
+ if (current.length > 0 && !fitsInTx(assembleTxIxs(candidate), authority, luts)) {
70583
+ bundles.push(current);
70584
+ current = [leg];
70585
+ } else {
70586
+ current = candidate;
70587
+ }
70588
+ }
70589
+ if (current.length > 0) bundles.push(current);
70590
+ for (const bundle of bundles) {
70591
+ const ixs = assembleTxIxs(bundle);
70592
+ if (bundle.length === 1 && !fitsInTx(ixs, authority, luts)) {
70593
+ throw new Error(
70594
+ `withdraw for bank ${bundle[0].bank.address.toBase58()} does not fit one transaction`
70595
+ );
70596
+ }
70597
+ }
70598
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
70599
+ const withdrawTxs = bundles.map((bundle) => {
70600
+ const message = new web3_js.TransactionMessage({
70601
+ payerKey: authority,
70602
+ recentBlockhash: blockhash,
70603
+ instructions: assembleTxIxs(bundle)
70604
+ }).compileToV0Message(luts);
70605
+ return addTransactionMetadata(new web3_js.VersionedTransaction(message), {
70606
+ addressLookupTables: luts,
70607
+ type: "WITHDRAW" /* WITHDRAW */
70608
+ });
70609
+ });
70610
+ const additionalTxs = [];
70611
+ const setupIxs = await makeSetupIx({
70612
+ connection,
70613
+ authority,
70614
+ tokens: legs.map((l) => ({
70615
+ mint: l.bank.mint,
70616
+ tokenProgram: requireTokenProgram(tokenProgramsByBank, l.bank.address)
70617
+ }))
70618
+ });
70619
+ if (setupIxs.length > 0) {
70620
+ const setupTxs = splitInstructionsToFitTransactions([], setupIxs, {
70621
+ blockhash,
70622
+ payerKey: authority,
70623
+ luts
70624
+ });
70625
+ additionalTxs.push(
70626
+ ...setupTxs.map(
70627
+ (tx) => addTransactionMetadata(tx, {
70628
+ type: "CREATE_ATA" /* CREATE_ATA */,
70629
+ addressLookupTables: luts
70630
+ })
70631
+ )
70632
+ );
70633
+ }
70634
+ const { instructions: crankIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
70635
+ marginfiAccount,
70636
+ bankMap,
70637
+ oraclePrices,
70638
+ assetShareValueMultiplierByBank,
70639
+ instructions: legs.flatMap((l) => l.instructions),
70640
+ program,
70641
+ connection,
70642
+ crossbarUrl: params.crossbarUrl,
70643
+ groupRateLimiterEnabled
70644
+ });
70645
+ if (crankIxs.length > 0) {
70646
+ const message = new web3_js.TransactionMessage({
70647
+ payerKey: authority,
70648
+ recentBlockhash: blockhash,
70649
+ instructions: crankIxs
70650
+ }).compileToV0Message(feedLuts);
70651
+ additionalTxs.push(
70652
+ addTransactionMetadata(new web3_js.VersionedTransaction(message), {
70653
+ addressLookupTables: feedLuts,
70654
+ type: "CRANK" /* CRANK */
70655
+ })
70656
+ );
70657
+ }
70658
+ return {
70659
+ transactions: [...additionalTxs, ...withdrawTxs],
70660
+ actionTxIndex: additionalTxs.length
70661
+ };
70662
+ }
70663
+ async function makeBulkRepayTx(params) {
70664
+ const {
70665
+ program,
70666
+ connection,
70667
+ marginfiAccount,
70668
+ bankAddresses,
70669
+ bankMap,
70670
+ tokenProgramsByBank,
70671
+ overrideInferAccounts
70672
+ } = params;
70673
+ const luts = params.addressLookupTableAccounts ?? [];
70674
+ const authority = marginfiAccount.authority;
70675
+ if (bankAddresses.length === 0) throw new Error("no banks to repay");
70676
+ const activeBalances = marginfiAccount.balances.filter((b) => b.active);
70677
+ const legs = [];
70678
+ for (const bankAddress of bankAddresses) {
70679
+ const bank = requireBank(bankMap, bankAddress);
70680
+ const tokenProgram = requireTokenProgram(tokenProgramsByBank, bankAddress);
70681
+ const balance = activeBalances.find((b) => b.bankPk.equals(bankAddress));
70682
+ if (!balance || !balance.liabilityShares.gt(0)) {
70683
+ throw new Error(`no active debt for bank ${bankAddress.toBase58()}`);
70684
+ }
70685
+ const uiAmount = computeQuantityUi(balance, bank).liabilities;
70686
+ const repay = await makeRepayIx3({
70687
+ program,
70688
+ bank,
70689
+ tokenProgram,
70690
+ amount: uiAmount,
70691
+ accountAddress: marginfiAccount.address,
70692
+ authority,
70693
+ repayAll: true,
70694
+ opts: {
70695
+ wrapAndUnwrapSol: true,
70696
+ overrideInferAccounts
70697
+ }
70698
+ });
70699
+ legs.push({ bank, instructions: repay.instructions });
70700
+ }
70701
+ const bundles = [];
70702
+ let current = [];
70703
+ for (const leg of legs) {
70704
+ const candidate = [...current, leg];
70705
+ const candidateIxs = candidate.flatMap((l) => l.instructions);
70706
+ if (current.length > 0 && !fitsInTx(candidateIxs, authority, luts)) {
70707
+ bundles.push(current);
70708
+ current = [leg];
70709
+ } else {
70710
+ current = candidate;
70711
+ }
70712
+ }
70713
+ if (current.length > 0) bundles.push(current);
70714
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
70715
+ const transactions = bundles.map((bundle) => {
70716
+ const message = new web3_js.TransactionMessage({
70717
+ payerKey: authority,
70718
+ recentBlockhash: blockhash,
70719
+ instructions: bundle.flatMap((l) => l.instructions)
70720
+ }).compileToV0Message(luts);
70721
+ return addTransactionMetadata(new web3_js.VersionedTransaction(message), {
70722
+ addressLookupTables: luts,
70723
+ type: "REPAY" /* REPAY */
70724
+ });
70725
+ });
70726
+ return { transactions, actionTxIndex: 0 };
70727
+ }
70443
70728
 
70444
70729
  // src/services/account/services/account-simulation.service.ts
70445
70730
  async function simulateAccountHealthCacheWithFallback(params) {
@@ -72852,6 +73137,22 @@ function computeBankMetrics(params) {
72852
73137
  };
72853
73138
  }
72854
73139
 
73140
+ // src/services/bank/utils/lookup.utils.ts
73141
+ function requireBank(bankMap, address, makeError = (message) => new Error(message)) {
73142
+ const bank = bankMap.get(address.toBase58());
73143
+ if (!bank) {
73144
+ throw makeError(`bank ${address.toBase58()} not found`);
73145
+ }
73146
+ return bank;
73147
+ }
73148
+ function requireTokenProgram(tokenProgramsByBank, address, makeError = (message) => new Error(message)) {
73149
+ const tokenProgram = tokenProgramsByBank.get(address.toBase58());
73150
+ if (!tokenProgram) {
73151
+ throw makeError(`token program for bank ${address.toBase58()} not provided`);
73152
+ }
73153
+ return tokenProgram;
73154
+ }
73155
+
72855
73156
  // src/services/bank/bank.service.ts
72856
73157
  async function freezeBankConfigIx(program, bankAddress, bankConfigOpt) {
72857
73158
  let bankConfigRaw;
@@ -76065,6 +76366,8 @@ exports.makeAddPermissionlessStakedBankIx = makeAddPermissionlessStakedBankIx;
76065
76366
  exports.makeBeginFlashLoanIx = makeBeginFlashLoanIx3;
76066
76367
  exports.makeBorrowIx = makeBorrowIx3;
76067
76368
  exports.makeBorrowTx = makeBorrowTx;
76369
+ exports.makeBulkRepayTx = makeBulkRepayTx;
76370
+ exports.makeBulkWithdrawTx = makeBulkWithdrawTx;
76068
76371
  exports.makeBundleTipIx = makeBundleTipIx;
76069
76372
  exports.makeCloseMarginfiAccountIx = makeCloseMarginfiAccountIx;
76070
76373
  exports.makeCloseMarginfiAccountTx = makeCloseMarginfiAccountTx;
@@ -76145,6 +76448,8 @@ exports.parseRpcPythPriceData = parseRpcPythPriceData;
76145
76448
  exports.parseSwbOraclePriceData = parseSwbOraclePriceData;
76146
76449
  exports.partitionBanksByCrankability = partitionBanksByCrankability;
76147
76450
  exports.patchDepositAmount = patchDepositAmount;
76451
+ exports.requireBank = requireBank;
76452
+ exports.requireTokenProgram = requireTokenProgram;
76148
76453
  exports.resolveAmount = resolveAmount;
76149
76454
  exports.resolveBridgeBanks = resolveBridgeBanks;
76150
76455
  exports.runSwapEngine = runSwapEngine;