@unio-aggregator/unio-tx-sender 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -35,7 +35,8 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
37
  // src/buildTransaction.ts
38
- var import_kit4 = require("@solana/kit");
38
+ var import_kit3 = require("@solana/kit");
39
+ var import_transaction_messages = require("@solana/transaction-messages");
39
40
 
40
41
  // src/computeBudget.ts
41
42
  var import_kit = require("@solana/kit");
@@ -108,7 +109,6 @@ async function calculateDynamicPriorityFees(rpc, instructions, percentile) {
108
109
 
109
110
  // src/jito.ts
110
111
  var import_kit2 = require("@solana/kit");
111
- var import_kit3 = require("@solana/kit");
112
112
  var import_system = require("@solana-program/system");
113
113
  var JITO_BUNDLE_EXPIRY_TIME = 3e4;
114
114
  var JitoApiUrl = /* @__PURE__ */ ((JitoApiUrl2) => {
@@ -166,7 +166,7 @@ async function recentJitoTip(config) {
166
166
  if (!key || !data[key]) {
167
167
  return BigInt(0);
168
168
  }
169
- return (0, import_kit3.lamports)(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
169
+ return (0, import_kit2.lamports)(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
170
170
  }
171
171
  var jitoTipAddresses = [
172
172
  "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
@@ -179,7 +179,7 @@ var jitoTipAddresses = [
179
179
  "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
180
180
  ];
181
181
  function getJitoTipAddress() {
182
- return (0, import_kit3.address)(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
182
+ return (0, import_kit2.address)(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
183
183
  }
184
184
  async function sendJitoBundle(jitoApiUrl, transactions, jitoUUID) {
185
185
  const encodedTransactions = transactions.map((tx) => (0, import_kit2.getBase64EncodedWireTransaction)(tx));
@@ -289,7 +289,7 @@ async function buildTransaction(rpc, instructions, feePayer, config, lookupTable
289
289
  return buildTransactionMessage(
290
290
  rpc,
291
291
  instructions,
292
- !("address" in feePayer) ? (0, import_kit4.createNoopSigner)(feePayer) : feePayer,
292
+ !("address" in feePayer) ? (0, import_kit3.createNoopSigner)(feePayer) : feePayer,
293
293
  config,
294
294
  lookupTableAccounts
295
295
  );
@@ -302,57 +302,101 @@ async function buildTransactionMessage(rpc, instructions, signer, config, lookup
302
302
  }).send()).value;
303
303
  }
304
304
  let message = await prepareTransactionMessage(instructions, signer, blockhash);
305
+ let computeUnits = 14e5;
306
+ let messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);
305
307
  if (lookupTableAccounts?.length) {
306
308
  const tables = lookupTableAccounts.reduce(
307
309
  (prev, account) => {
308
310
  if (account.exists) {
309
- (0, import_kit4.assertAccountDecoded)(account);
311
+ (0, import_kit3.assertAccountDecoded)(account);
310
312
  prev[account.address] = account.data.addresses;
311
313
  }
312
314
  return prev;
313
315
  },
314
316
  {}
315
317
  );
316
- message = (0, import_kit4.compressTransactionMessageUsingAddressLookupTables)(message, tables);
318
+ messageWithExtra = (0, import_kit3.compressTransactionMessageUsingAddressLookupTables)(messageWithExtra, tables);
317
319
  }
318
- const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);
319
- return (0, import_kit4.signTransactionMessageWithSigners)(messageWithExtraInstructions);
320
+ if (!config.skipSimulation) {
321
+ try {
322
+ computeUnits = await getComputeUnitsForTxMessage(rpc, messageWithExtra);
323
+ messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);
324
+ if (lookupTableAccounts?.length) {
325
+ const tables = lookupTableAccounts.reduce(
326
+ (prev, account) => {
327
+ if (account.exists) {
328
+ (0, import_kit3.assertAccountDecoded)(account);
329
+ prev[account.address] = account.data.addresses;
330
+ }
331
+ return prev;
332
+ },
333
+ {}
334
+ );
335
+ messageWithExtra = (0, import_kit3.compressTransactionMessageUsingAddressLookupTables)(messageWithExtra, tables);
336
+ }
337
+ } catch (e) {
338
+ console.warn("Transaction simulation failed, using 1,400,000 compute units: ", e);
339
+ }
340
+ }
341
+ return (0, import_kit3.signTransactionMessageWithSigners)(messageWithExtra);
320
342
  }
321
343
  async function prepareTransactionMessage(instructions, signer, blockhash) {
322
- return (0, import_kit4.pipe)(
323
- (0, import_kit4.createTransactionMessage)({ version: 0 }),
324
- (tx) => (0, import_kit4.setTransactionMessageLifetimeUsingBlockhash)(blockhash, tx),
325
- (tx) => (0, import_kit4.setTransactionMessageFeePayerSigner)(signer, tx),
326
- (tx) => (0, import_kit4.appendTransactionMessageInstructions)(instructions, tx)
344
+ return (0, import_kit3.pipe)(
345
+ (0, import_kit3.createTransactionMessage)({ version: 0 }),
346
+ (tx) => (0, import_kit3.setTransactionMessageLifetimeUsingBlockhash)(blockhash, tx),
347
+ (tx) => (0, import_kit3.setTransactionMessageFeePayerSigner)(signer, tx),
348
+ (tx) => (0, import_kit3.appendTransactionMessageInstructions)(instructions, tx)
327
349
  );
328
350
  }
329
- async function addPriorityInstructions(rpc, message, signer, config) {
351
+ async function addPriorityInstructions(rpc, message, signer, config, computeUnits) {
330
352
  if (config.jito && config.jito.type !== "none") {
331
353
  message = await processJitoTipForTxMessage(message, signer, config);
332
354
  }
333
- let computeUnits = 14e5;
334
- if (!config.skipSimulation) {
335
- try {
336
- computeUnits = await getComputeUnitsForTxMessage(rpc, message);
337
- } catch {
338
- console.warn("Transaction simulation failed, using 1,400,000 compute units");
339
- }
340
- }
341
355
  return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);
342
356
  }
343
- async function getComputeUnitsForTxMessage(rpc, txMessage) {
344
- return await (0, import_kit4.estimateComputeUnitLimitFactory)({ rpc })(txMessage);
357
+ async function getComputeUnitsForTxMessage(rpc, message) {
358
+ const replaceRecentBlockhash = !(0, import_transaction_messages.isTransactionMessageWithDurableNonceLifetime)(message);
359
+ const transaction = (0, import_kit3.pipe)(message, import_kit3.compileTransaction);
360
+ const wireTransactionBytes = (0, import_kit3.getBase64EncodedWireTransaction)(transaction);
361
+ try {
362
+ const response = await rpc.simulateTransaction(wireTransactionBytes, {
363
+ encoding: "base64",
364
+ replaceRecentBlockhash,
365
+ sigVerify: false
366
+ }).send();
367
+ const { err: transactionError, ...simulationResult } = response.value;
368
+ if (simulationResult.unitsConsumed == null) {
369
+ throw new import_kit3.SolanaError(import_kit3.SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT);
370
+ }
371
+ if (transactionError) {
372
+ throw new import_kit3.SolanaError(import_kit3.SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT, {
373
+ ...simulationResult,
374
+ cause: (0, import_kit3.getSolanaErrorFromTransactionError)(transactionError)
375
+ });
376
+ }
377
+ return simulationResult.unitsConsumed > 4294967295n ? 4294967295 : Number(simulationResult.unitsConsumed);
378
+ } catch (e) {
379
+ if ((0, import_kit3.isSolanaError)(e, import_kit3.SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT)) {
380
+ throw e;
381
+ }
382
+ throw new import_kit3.SolanaError(import_kit3.SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT, {
383
+ cause: e
384
+ });
385
+ }
345
386
  }
346
387
 
347
388
  // src/sendTransaction.ts
348
- var import_kit5 = require("@solana/kit");
389
+ var import_kit4 = require("@solana/kit");
390
+ var CONFIRMATION_TIMEOUT_MS = 6e4;
391
+ var CONFIRMATION_POLL_INTERVAL_MS = 1e3;
392
+ var COMMITMENT_RANK = { processed: 0, confirmed: 1, finalized: 2 };
349
393
  async function sendTransaction(rpc, instructions, payer, config, lookupTableAccounts, commitment = "confirmed") {
350
394
  const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);
351
395
  return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);
352
396
  }
353
397
  async function sendSignedTransaction(rpc, transaction, skipSimulation = false, commitment = "confirmed") {
354
398
  const txSignature = getTxSignature(transaction);
355
- const encodedTransaction = (0, import_kit5.getBase64EncodedWireTransaction)(transaction);
399
+ const encodedTransaction = (0, import_kit4.getBase64EncodedWireTransaction)(transaction);
356
400
  if (!skipSimulation) {
357
401
  const simResult = await rpc.simulateTransaction(encodedTransaction, {
358
402
  encoding: "base64"
@@ -361,27 +405,39 @@ async function sendSignedTransaction(rpc, transaction, skipSimulation = false, c
361
405
  throw new Error(`Transaction simulation failed`, { cause: simResult.value });
362
406
  }
363
407
  }
364
- const expiryTime = Date.now() + 6e4;
408
+ const expiryTime = Date.now() + CONFIRMATION_TIMEOUT_MS;
409
+ await rpc.sendTransaction(encodedTransaction, {
410
+ maxRetries: BigInt(0),
411
+ skipPreflight: true,
412
+ encoding: "base64"
413
+ }).send();
365
414
  while (Date.now() < expiryTime) {
366
- await rpc.sendTransaction(encodedTransaction, {
367
- maxRetries: BigInt(0),
368
- skipPreflight: true,
369
- encoding: "base64"
370
- }).send();
371
- const { value } = await rpc.getSignatureStatuses([txSignature]).send();
372
- const status = value[0];
373
- if (status?.confirmationStatus === commitment) {
415
+ const status = await pollSignatureStatus(rpc, txSignature);
416
+ if (status) {
374
417
  if (status.err) {
375
418
  throw new Error(`Transaction failed`, { cause: status.err });
376
419
  }
377
- return txSignature;
420
+ const { confirmationStatus } = status;
421
+ const confirmationRank = confirmationStatus ? COMMITMENT_RANK[confirmationStatus] : -1;
422
+ if (confirmationRank >= COMMITMENT_RANK[commitment]) {
423
+ return txSignature;
424
+ }
378
425
  }
426
+ await new Promise((resolve) => setTimeout(resolve, CONFIRMATION_POLL_INTERVAL_MS));
379
427
  }
380
428
  throw new Error("Transaction expired");
381
429
  }
382
430
  function getTxSignature(transaction) {
383
431
  const [signature] = Object.values(transaction.signatures);
384
- return (0, import_kit5.getBase58Decoder)().decode(signature);
432
+ return (0, import_kit4.getBase58Decoder)().decode(signature);
433
+ }
434
+ async function pollSignatureStatus(rpc, signature) {
435
+ try {
436
+ const { value } = await rpc.getSignatureStatuses([signature]).send();
437
+ return value[0] ?? null;
438
+ } catch {
439
+ return null;
440
+ }
385
441
  }
386
442
  // Annotate the CommonJS export names for ESM import in node:
387
443
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/buildTransaction.ts","../src/computeBudget.ts","../src/config.ts","../src/jito.ts","../src/sendTransaction.ts"],"sourcesContent":["export * from \"./buildTransaction\";\nexport * from \"./config\";\nexport * from \"./jito\";\nexport * from \"./sendTransaction\";\n","import {\n Address,\n appendTransactionMessageInstructions,\n assertAccountDecoded,\n BlockhashLifetimeConstraint,\n compressTransactionMessageUsingAddressLookupTables,\n createNoopSigner,\n createTransactionMessage,\n estimateComputeUnitLimitFactory,\n Instruction,\n MaybeAccount,\n pipe,\n Rpc,\n SendableTransaction,\n setTransactionMessageFeePayerSigner,\n setTransactionMessageLifetimeUsingBlockhash,\n signTransactionMessageWithSigners,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { processComputeBudgetForTxMessage } from \"./computeBudget.ts\";\nimport { TransactionConfig } from \"./config\";\nimport { processJitoTipForTxMessage } from \"./jito.ts\";\n\n/**\n * Builds and signs a transaction from the given instructions and configuration.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction\n * @param {TransactionSigner} feePayer - The signer that will pay for the transaction\n * @param {(Address | string)[]} [lookupTableAccounts] - Optional array of address lookup table accounts to compress the transaction\n *\n * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction\n *\n * @example\n * const instructions = [createATAix, createTransferSolInstruction];\n * const feePayer = wallet.publicKey;\n * const message = await buildTransaction(\n * rpc,\n * instructions,\n * feePayer,\n * );\n */\nexport async function buildTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n feePayer: TransactionSigner | Address,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n config,\n lookupTableAccounts,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n signer: TransactionSigner,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n) {\n let blockhash = config.blockhash;\n if (!blockhash) {\n blockhash = (\n await rpc\n .getLatestBlockhash({\n commitment: \"confirmed\",\n })\n .send()\n ).value;\n }\n\n let message = await prepareTransactionMessage(instructions, signer, blockhash);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n message = compressTransactionMessageUsingAddressLookupTables(message, tables);\n }\n\n const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);\n\n return signTransactionMessageWithSigners(messageWithExtraInstructions);\n}\n\nasync function prepareTransactionMessage(\n instructions: Instruction[],\n signer: TransactionSigner,\n blockhash: BlockhashLifetimeConstraint,\n) {\n return pipe(\n createTransactionMessage({ version: 0 }),\n tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),\n tx => setTransactionMessageFeePayerSigner(signer, tx),\n tx => appendTransactionMessageInstructions(instructions, tx),\n );\n}\n\nasync function addPriorityInstructions(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessage & TransactionMessageWithFeePayer,\n signer: TransactionSigner,\n config: TransactionConfig,\n): Promise<TransactionMessage & TransactionMessageWithFeePayer> {\n if (config.jito && config.jito.type !== \"none\") {\n message = await processJitoTipForTxMessage(message, signer, config);\n }\n\n let computeUnits = 1_400_000;\n\n if (!config.skipSimulation) {\n try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, message);\n } catch {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units\");\n }\n }\n\n return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);\n}\n\nasync function getComputeUnitsForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n txMessage: TransactionMessage & TransactionMessageWithFeePayer,\n) {\n return await estimateComputeUnitLimitFactory({ rpc })(txMessage);\n}\n","import {\n Address,\n Instruction,\n Rpc,\n SolanaRpcApi,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n} from \"@solana/kit\";\nimport { isWritableRole, prependTransactionMessageInstruction } from \"@solana/kit\";\nimport { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from \"@solana-program/compute-budget\";\n\nimport type { Percentile, TransactionConfig } from \"./config\";\nimport { DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER } from \"./config\";\n\nexport async function processComputeBudgetForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessage & TransactionMessageWithFeePayer,\n computeUnits: number,\n config: TransactionConfig,\n) {\n const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;\n let priorityFeeMicroLamports = 0n;\n\n const units = Math.min(\n 1_400_000,\n Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\n );\n\n const priorityFee = config.priorityFee;\n if (priorityFee) {\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / BigInt(units);\n } else if (priorityFee.type === \"dynamic\") {\n const estimatedPriorityFee = await calculateDynamicPriorityFees(\n rpc,\n message.instructions,\n priorityFee.priorityFeePercentile ?? \"50\",\n );\n\n if (!priorityFee.maxCapLamports) {\n priorityFeeMicroLamports = estimatedPriorityFee;\n } else {\n const maxCapMicroLamports = (priorityFee.maxCapLamports * 1_000_000n) / BigInt(units);\n priorityFeeMicroLamports =\n maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;\n }\n }\n }\n\n if (priorityFeeMicroLamports > 0) {\n message = prependTransactionMessageInstruction(\n getSetComputeUnitPriceInstruction({\n microLamports: priorityFeeMicroLamports,\n }),\n message,\n );\n }\n\n message = prependTransactionMessageInstruction(\n getSetComputeUnitLimitInstruction({\n units,\n }),\n message,\n );\n\n return message;\n}\n\nfunction getWritableAccounts(ixs: readonly Instruction[]) {\n const writable = new Set<Address>();\n ixs.forEach(ix => {\n if (ix.accounts) {\n ix.accounts.forEach(acc => {\n if (isWritableRole(acc.role)) writable.add(acc.address);\n });\n }\n });\n return Array.from(writable);\n}\n\nasync function calculateDynamicPriorityFees(\n rpc: Rpc<SolanaRpcApi>,\n instructions: readonly Instruction[],\n percentile: Percentile,\n) {\n const writableAccounts = getWritableAccounts(instructions);\n const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();\n const nonZero = recent.filter(pf => pf.prioritizationFee > 0).map(pf => pf.prioritizationFee);\n const sorted = nonZero.sort((a, b) => Number(a - b));\n return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);\n}\n","import { BlockhashLifetimeConstraint } from \"@solana/kit\";\n\n/**\n * Default compute unit margin multiplier used to ensure sufficient compute budget.\n */\nexport const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;\nexport const DEFAULT_JITO_BLOCK_ENGINE_URL = \"https://bundles.jito.wtf\";\n\ntype FeeSetting =\n | {\n type: \"dynamic\";\n maxCapLamports?: bigint;\n }\n | {\n type: \"exact\";\n amountLamports: bigint;\n }\n | {\n type: \"none\";\n };\n\n/**\n * Configuration for transaction fees, including Jito and priority fee settings.\n */\nexport type JitoFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile | \"50ema\";\n};\n\nexport type PriorityFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile;\n};\n\n/**\n * Defines a percentile value for priority fee selection.\n */\nexport type Percentile = \"25\" | \"50\" | \"75\" | \"95\" | \"99\";\n\nexport type TransactionConfig = {\n jito?: JitoFeeSetting;\n priorityFee?: PriorityFeeSetting;\n computeUnitMarginMultiplier?: number;\n jitoBlockEngineUrl?: string;\n skipSimulation?: boolean;\n blockhash?: BlockhashLifetimeConstraint;\n};\n","import {\n Address,\n appendTransactionMessageInstruction,\n getBase64EncodedWireTransaction,\n Rpc,\n SendableTransaction,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { address, lamports } from \"@solana/kit\";\nimport { getTransferSolInstruction } from \"@solana-program/system\";\n\nimport { DEFAULT_JITO_BLOCK_ENGINE_URL, type Percentile, TransactionConfig } from \"./config\";\n\nconst JITO_BUNDLE_EXPIRY_TIME = 30_000;\n\nexport type AccountConfig = {\n accountIndex: number;\n addresses: string[];\n};\n\nexport type JitoAccountInfo = {\n executable: boolean;\n owner: string;\n lamports: number;\n data: string;\n rentEpoch: number;\n};\n\nexport type JitoRpcApi = SolanaRpcApi & {\n simulateBundle: (\n params: {\n encodedTransactions: string[];\n },\n config?: {\n preExecutionAccountsConfigs?: AccountConfig;\n postExecutionAccountsConfigs?: AccountConfig;\n skipSigVerify?: boolean;\n simulationBank?: {\n commitment?: {\n commitment: \"processed\" | \"confirmed\" | \"finalized\";\n };\n };\n transactionEncoding?: \"base64\";\n replaceRecentBlockhash?: boolean;\n },\n ) => SimulateBundleResponse;\n\n sendBundle: (\n params: string[],\n config?: {\n encoding?: \"base64\";\n },\n ) => string;\n\n getBundleStatuses: (params: string[]) => GetBundleStatusesResponse;\n};\n\nexport type SimulateBundleResponse = {\n context: {\n slot: number;\n apiVersion?: string;\n };\n value: {\n summary: \"succeeded\" | { failed: { error: unknown; tx_signature: string } };\n transactionResults: Array<{\n err: unknown;\n logs: string[] | null;\n unitsConsumed?: number;\n returnData: {\n programId: string;\n data: string;\n } | null;\n preExecutionAccounts: JitoAccountInfo[] | null;\n postExecutionAccounts: JitoAccountInfo[] | null;\n }>;\n };\n};\n\nexport type GetBundleStatusesResponse = {\n context: {\n slot: number;\n };\n value: Array<{\n bundleId: string;\n transactions: string[];\n slot: number;\n confirmation_status: \"processed\" | \"confirmed\" | \"finalized\";\n err:\n | {\n Ok: null;\n }\n | {\n Err: object;\n };\n }>;\n};\n\nexport enum JitoApiUrl {\n Amsterdam = \"https://amsterdam.mainnet.block-engine.jito.wtf\",\n Frankfurt = \"https://frankfurt.mainnet.block-engine.jito.wtf\",\n London = \"https://london.mainnet.block-engine.jito.wtf\",\n NY = \"https://ny.mainnet.block-engine.jito.wtf\",\n Singapore = \"https://singapore.mainnet.block-engine.jito.wtf\",\n SLC = \"https://slc.mainnet.block-engine.jito.wtf\",\n Tokyo = \"https://tokyo.mainnet.block-engine.jito.wtf\",\n Default = \"https://mainnet.block-engine.jito.wtf\",\n}\n\nexport async function processJitoTipForTxMessage(\n message: TransactionMessage & TransactionMessageWithFeePayer,\n signer: TransactionSigner,\n config: TransactionConfig,\n) {\n const jito = config.jito;\n if (!jito) throw new Error(\"jito config is undefined\");\n\n let jitoTipLamports = BigInt(0);\n\n if (jito.type === \"exact\") {\n jitoTipLamports = jito.amountLamports;\n } else if (jito.type === \"dynamic\") {\n jitoTipLamports = await recentJitoTip(config);\n if (jito.maxCapLamports && jitoTipLamports > jito.maxCapLamports) {\n jitoTipLamports = jito.maxCapLamports;\n }\n }\n\n if (jitoTipLamports > 0) {\n return appendTransactionMessageInstruction(\n getTransferSolInstruction({\n source: signer,\n destination: getJitoTipAddress(),\n amount: jitoTipLamports,\n }),\n message,\n );\n } else {\n return message;\n }\n}\n\n// returns recent jito tip in lamports\nexport async function recentJitoTip(config: TransactionConfig) {\n const baseUrl = config.jitoBlockEngineUrl ?? DEFAULT_JITO_BLOCK_ENGINE_URL;\n const response = await fetch(`${baseUrl}/api/v1/bundles/tip_floor`);\n if (!response.ok) {\n return BigInt(0);\n }\n const data = await response.json().then(res => res[0]);\n\n const percentileToKey: Record<Percentile | \"50ema\", string> = {\n \"25\": \"landed_tips_25th_percentile\",\n \"50\": \"landed_tips_50th_percentile\",\n \"75\": \"landed_tips_75th_percentile\",\n \"95\": \"landed_tips_95th_percentile\",\n \"99\": \"landed_tips_99th_percentile\",\n \"50ema\": \"ema_landed_tips_50th_percentile\",\n };\n\n const key = percentileToKey[config.jito?.priorityFeePercentile ?? \"50\"];\n if (!key || !data[key]) {\n return BigInt(0);\n }\n return lamports(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();\n}\n\n// should we add an argument that dictates if we should use cached value in case fetch fails ?\n\n// below is taken from legacy sdk (no need to add the whole library)\n// https://jito-foundation.gitbook.io/mev/mev-payment-and-distribution/on-chain-addresses\nconst jitoTipAddresses = [\n \"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5\",\n \"HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe\",\n \"Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY\",\n \"ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49\",\n \"DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh\",\n \"ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt\",\n \"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL\",\n \"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT\",\n];\n\nfunction getJitoTipAddress(): Address {\n // just pick a random one from the list. There are multiple addresses so that no single one can cause local congestion.\n return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);\n}\n\ninterface JsonRpcResult {\n jsonrpc: string;\n id: number;\n result?: string; // bundle id\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\nexport async function sendJitoBundle(\n jitoApiUrl: JitoApiUrl,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n jitoUUID?: string,\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx)) as string[];\n\n const url = new URL(\"/api/v1/bundles\", jitoApiUrl);\n if (jitoUUID && jitoUUID.length > 0) {\n url.searchParams.set(\"uuid\", jitoUUID);\n }\n\n const request = {\n id: 1,\n jsonrpc: \"2.0\",\n method: \"sendBundle\",\n params: [\n encodedTransactions,\n {\n encoding: \"base64\",\n },\n ],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = (await response.json()) as JsonRpcResult;\n\n if (data.error) {\n throw new Error(`Jito bundle failed: ${data.error.code} ${data.error.message}`);\n }\n\n if (!data.result) {\n throw new Error(\"sendBundle did not return a bundle id\");\n }\n\n const bundleId = data.result;\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const request = {\n jsonrpc: \"2.0\",\n id: 1,\n method: \"getInflightBundleStatuses\",\n params: [[bundleId]],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = await response.json();\n const result = data.result?.value?.[0];\n if (!result) {\n throw new Error(`getInflightBundleStatuses method returned undefined result`, { cause: { bundleId } });\n }\n\n switch (result.status) {\n case \"Landed\":\n return bundleId;\n case \"Pending\":\n case \"Invalid\":\n continue;\n case \"Failed\":\n throw new Error(`Bundle failed`, { cause: { bundleId } });\n default:\n throw new Error(`Bundle status is unknown`, { cause: { bundleId } });\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n\nexport async function simulateBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<SimulateBundleResponse> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n return rpc\n .simulateBundle({\n encodedTransactions,\n })\n .send();\n}\n\nexport async function sendBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n const bundleId = await rpc\n .sendBundle(encodedTransactions, {\n encoding: \"base64\",\n })\n .send();\n\n if (!bundleId) throw new Error(`sendBundle method failed`);\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const statuses = await rpc.getBundleStatuses([bundleId]).send();\n\n const bundleStatus = statuses?.value?.[0];\n if (!bundleStatus) continue;\n\n if (bundleStatus.err && \"Err\" in bundleStatus.err) {\n throw new Error(`Bundle failed`, { cause: { bundleId, error: bundleStatus.err.Err } });\n } else {\n const confirmation_status = bundleStatus.confirmation_status;\n if (confirmation_status == \"confirmed\") {\n return bundleId;\n }\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n","import {\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n MaybeAccount,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { buildTransaction } from \"./buildTransaction\";\nimport { TransactionConfig } from \"./config\";\n\n/**\n * Builds and sends a transaction with the given instructions, signers, and commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction.\n * @param {KeyPairSigner} payer - The fee payer for the transaction.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Address[]} [lookupTableAccounts] - Optional array of address lookup table accounts to use.\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction building or sending fails.\n *\n * @example\n * ```ts\n * const signature = await sendTransaction(\n * instructions,\n * keypairSigner,\n * DEFAULT_TRANSACTION_CONFIG,\n * lookupTables,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n payer: KeyPairSigner,\n config?: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);\n return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);\n}\n\n/**\n * Sends a signed transaction message to the Solana network with a specified commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.\n * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.\n * @param {boolean} skipSimulation - True if skip simulation\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.\n *\n * @example\n * ```ts\n * const signature = await sendSignedTransaction(\n * rpc,\n * signedTransaction,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendSignedTransaction(\n rpc: Rpc<SolanaRpcApi>,\n transaction: SendableTransaction & Transaction & TransactionWithLifetime,\n skipSimulation: boolean = false,\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\n if (!skipSimulation) {\n // Simulate transaction first\n const simResult = await rpc\n .simulateTransaction(encodedTransaction, {\n encoding: \"base64\",\n })\n .send();\n\n if (simResult.value.err) {\n throw new Error(`Transaction simulation failed`, { cause: simResult.value });\n }\n }\n\n const expiryTime = Date.now() + 60_000;\n\n while (Date.now() < expiryTime) {\n await rpc\n .sendTransaction(encodedTransaction, {\n maxRetries: BigInt(0),\n skipPreflight: true,\n encoding: \"base64\",\n })\n .send();\n\n const { value } = await rpc.getSignatureStatuses([txSignature]).send();\n const status = value[0];\n if (status?.confirmationStatus === commitment) {\n if (status.err) {\n throw new Error(`Transaction failed`, { cause: status.err });\n }\n return txSignature;\n }\n }\n\n throw new Error(\"Transaction expired\");\n}\n\nexport function getTxSignature(transaction: Transaction) {\n const [signature] = Object.values(transaction.signatures);\n return getBase58Decoder().decode(signature!) as Signature;\n}\n"],"mappings":"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","names":["import_kit","import_kit","JitoApiUrl","request","response","data","import_kit"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/buildTransaction.ts","../src/computeBudget.ts","../src/config.ts","../src/jito.ts","../src/sendTransaction.ts"],"sourcesContent":["export * from \"./buildTransaction\";\nexport * from \"./config\";\nexport * from \"./jito\";\nexport * from \"./sendTransaction\";\n","import {\n Address,\n appendTransactionMessageInstructions,\n assertAccountDecoded,\n BlockhashLifetimeConstraint,\n compileTransaction,\n compressTransactionMessageUsingAddressLookupTables,\n createNoopSigner,\n createTransactionMessage,\n getBase64EncodedWireTransaction,\n getSolanaErrorFromTransactionError,\n Instruction,\n isSolanaError,\n MaybeAccount,\n pipe,\n Rpc,\n RpcSimulateTransactionResult,\n SendableTransaction,\n setTransactionMessageFeePayerSigner,\n setTransactionMessageLifetimeUsingBlockhash,\n signTransactionMessageWithSigners,\n SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT,\n SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT,\n SolanaError,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { isTransactionMessageWithDurableNonceLifetime } from \"@solana/transaction-messages\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { processComputeBudgetForTxMessage } from \"./computeBudget.ts\";\nimport { TransactionConfig } from \"./config\";\nimport { processJitoTipForTxMessage } from \"./jito.ts\";\n\n/**\n * Builds and signs a transaction from the given instructions and configuration.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction\n * @param {TransactionSigner} feePayer - The signer that will pay for the transaction\n * @param {(Address | string)[]} [lookupTableAccounts] - Optional array of address lookup table accounts to compress the transaction\n *\n * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction\n *\n * @example\n * const instructions = [createATAix, createTransferSolInstruction];\n * const feePayer = wallet.publicKey;\n * const message = await buildTransaction(\n * rpc,\n * instructions,\n * feePayer,\n * );\n */\nexport async function buildTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n feePayer: TransactionSigner | Address,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n config,\n lookupTableAccounts,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n signer: TransactionSigner,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n) {\n let blockhash = config.blockhash;\n if (!blockhash) {\n blockhash = (\n await rpc\n .getLatestBlockhash({\n commitment: \"confirmed\",\n })\n .send()\n ).value;\n }\n\n let message = await prepareTransactionMessage(instructions, signer, blockhash);\n\n let computeUnits = 1_400_000;\n let messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);\n }\n\n if (!config.skipSimulation) {\n try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, messageWithExtra);\n\n // Rebuild the message\n messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);\n }\n } catch (e) {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units: \", e);\n }\n }\n\n return signTransactionMessageWithSigners(messageWithExtra);\n}\n\nasync function prepareTransactionMessage(\n instructions: Instruction[],\n signer: TransactionSigner,\n blockhash: BlockhashLifetimeConstraint,\n) {\n return pipe(\n createTransactionMessage({ version: 0 }),\n tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),\n tx => setTransactionMessageFeePayerSigner(signer, tx),\n tx => appendTransactionMessageInstructions(instructions, tx),\n );\n}\n\nasync function addPriorityInstructions(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n signer: TransactionSigner,\n config: TransactionConfig,\n computeUnits: number,\n) {\n if (config.jito && config.jito.type !== \"none\") {\n message = await processJitoTipForTxMessage(message, signer, config);\n }\n\n return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);\n}\n\nasync function getComputeUnitsForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n) {\n const replaceRecentBlockhash = !isTransactionMessageWithDurableNonceLifetime(message);\n\n const transaction = pipe(message, compileTransaction);\n const wireTransactionBytes = getBase64EncodedWireTransaction(transaction);\n\n try {\n const response = await rpc\n .simulateTransaction(wireTransactionBytes, {\n encoding: \"base64\",\n replaceRecentBlockhash,\n sigVerify: false,\n })\n .send();\n // The API response type varies based on config (eg. `replacementBlockhash` is only\n // present when `replaceRecentBlockhash` is true), but `RpcSimulateTransactionResult`\n // is a flat superset. Cast through `unknown` to bridge the structural gap.\n const { err: transactionError, ...simulationResult } = response.value as unknown as RpcSimulateTransactionResult;\n\n if (simulationResult.unitsConsumed == null) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT);\n }\n\n if (transactionError) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT, {\n ...simulationResult,\n cause: getSolanaErrorFromTransactionError(transactionError),\n });\n }\n\n // Downcast from bigint to number, capping at u32 max.\n return simulationResult.unitsConsumed > 4_294_967_295n ? 4_294_967_295 : Number(simulationResult.unitsConsumed);\n } catch (e) {\n if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT)) {\n throw e;\n }\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT, {\n cause: e,\n });\n }\n}\n","import {\n Address,\n Instruction,\n isWritableRole,\n prependTransactionMessageInstruction,\n Rpc,\n SolanaRpcApi,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n} from \"@solana/kit\";\nimport { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from \"@solana-program/compute-budget\";\n\nimport type { Percentile, TransactionConfig } from \"./config\";\nimport { DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER } from \"./config\";\n\nexport async function processComputeBudgetForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n computeUnits: number,\n config: TransactionConfig,\n) {\n const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;\n let priorityFeeMicroLamports = 0n;\n\n const units = Math.min(\n 1_400_000,\n Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\n );\n\n const priorityFee = config.priorityFee;\n if (priorityFee) {\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / BigInt(units);\n } else if (priorityFee.type === \"dynamic\") {\n const estimatedPriorityFee = await calculateDynamicPriorityFees(\n rpc,\n message.instructions,\n priorityFee.priorityFeePercentile ?? \"50\",\n );\n\n if (!priorityFee.maxCapLamports) {\n priorityFeeMicroLamports = estimatedPriorityFee;\n } else {\n const maxCapMicroLamports = (priorityFee.maxCapLamports * 1_000_000n) / BigInt(units);\n priorityFeeMicroLamports =\n maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;\n }\n }\n }\n\n if (priorityFeeMicroLamports > 0) {\n message = prependTransactionMessageInstruction(\n getSetComputeUnitPriceInstruction({\n microLamports: priorityFeeMicroLamports,\n }),\n message,\n );\n }\n\n message = prependTransactionMessageInstruction(\n getSetComputeUnitLimitInstruction({\n units,\n }),\n message,\n );\n\n return message;\n}\n\nfunction getWritableAccounts(ixs: readonly Instruction[]) {\n const writable = new Set<Address>();\n ixs.forEach(ix => {\n if (ix.accounts) {\n ix.accounts.forEach(acc => {\n if (isWritableRole(acc.role)) writable.add(acc.address);\n });\n }\n });\n return Array.from(writable);\n}\n\nasync function calculateDynamicPriorityFees(\n rpc: Rpc<SolanaRpcApi>,\n instructions: readonly Instruction[],\n percentile: Percentile,\n) {\n const writableAccounts = getWritableAccounts(instructions);\n const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();\n const nonZero = recent.filter(pf => pf.prioritizationFee > 0).map(pf => pf.prioritizationFee);\n const sorted = nonZero.sort((a, b) => Number(a - b));\n return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);\n}\n","import { BlockhashLifetimeConstraint } from \"@solana/kit\";\n\n/**\n * Default compute unit margin multiplier used to ensure sufficient compute budget.\n */\nexport const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;\nexport const DEFAULT_JITO_BLOCK_ENGINE_URL = \"https://bundles.jito.wtf\";\n\ntype FeeSetting =\n | {\n type: \"dynamic\";\n maxCapLamports?: bigint;\n }\n | {\n type: \"exact\";\n amountLamports: bigint;\n }\n | {\n type: \"none\";\n };\n\n/**\n * Configuration for transaction fees, including Jito and priority fee settings.\n */\nexport type JitoFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile | \"50ema\";\n};\n\nexport type PriorityFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile;\n};\n\n/**\n * Defines a percentile value for priority fee selection.\n */\nexport type Percentile = \"25\" | \"50\" | \"75\" | \"95\" | \"99\";\n\nexport type TransactionConfig = {\n jito?: JitoFeeSetting;\n priorityFee?: PriorityFeeSetting;\n computeUnitMarginMultiplier?: number;\n jitoBlockEngineUrl?: string;\n skipSimulation?: boolean;\n blockhash?: BlockhashLifetimeConstraint;\n};\n","import {\n Address,\n address,\n appendTransactionMessageInstruction,\n getBase64EncodedWireTransaction,\n lamports,\n Rpc,\n SendableTransaction,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { getTransferSolInstruction } from \"@solana-program/system\";\n\nimport { DEFAULT_JITO_BLOCK_ENGINE_URL, type Percentile, TransactionConfig } from \"./config\";\n\nconst JITO_BUNDLE_EXPIRY_TIME = 30_000;\n\nexport type AccountConfig = {\n accountIndex: number;\n addresses: string[];\n};\n\nexport type JitoAccountInfo = {\n executable: boolean;\n owner: string;\n lamports: number;\n data: string;\n rentEpoch: number;\n};\n\nexport type JitoRpcApi = SolanaRpcApi & {\n simulateBundle: (\n params: {\n encodedTransactions: string[];\n },\n config?: {\n preExecutionAccountsConfigs?: AccountConfig;\n postExecutionAccountsConfigs?: AccountConfig;\n skipSigVerify?: boolean;\n simulationBank?: {\n commitment?: {\n commitment: \"processed\" | \"confirmed\" | \"finalized\";\n };\n };\n transactionEncoding?: \"base64\";\n replaceRecentBlockhash?: boolean;\n },\n ) => SimulateBundleResponse;\n\n sendBundle: (\n params: string[],\n config?: {\n encoding?: \"base64\";\n },\n ) => string;\n\n getBundleStatuses: (params: string[]) => GetBundleStatusesResponse;\n};\n\nexport type SimulateBundleResponse = {\n context: {\n slot: number;\n apiVersion?: string;\n };\n value: {\n summary: \"succeeded\" | { failed: { error: unknown; tx_signature: string } };\n transactionResults: Array<{\n err: unknown;\n logs: string[] | null;\n unitsConsumed?: number;\n returnData: {\n programId: string;\n data: string;\n } | null;\n preExecutionAccounts: JitoAccountInfo[] | null;\n postExecutionAccounts: JitoAccountInfo[] | null;\n }>;\n };\n};\n\nexport type GetBundleStatusesResponse = {\n context: {\n slot: number;\n };\n value: Array<{\n bundleId: string;\n transactions: string[];\n slot: number;\n confirmation_status: \"processed\" | \"confirmed\" | \"finalized\";\n err:\n | {\n Ok: null;\n }\n | {\n Err: object;\n };\n }>;\n};\n\nexport enum JitoApiUrl {\n Amsterdam = \"https://amsterdam.mainnet.block-engine.jito.wtf\",\n Frankfurt = \"https://frankfurt.mainnet.block-engine.jito.wtf\",\n London = \"https://london.mainnet.block-engine.jito.wtf\",\n NY = \"https://ny.mainnet.block-engine.jito.wtf\",\n Singapore = \"https://singapore.mainnet.block-engine.jito.wtf\",\n SLC = \"https://slc.mainnet.block-engine.jito.wtf\",\n Tokyo = \"https://tokyo.mainnet.block-engine.jito.wtf\",\n Default = \"https://mainnet.block-engine.jito.wtf\",\n}\n\nexport async function processJitoTipForTxMessage(\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n signer: TransactionSigner,\n config: TransactionConfig,\n) {\n const jito = config.jito;\n if (!jito) throw new Error(\"jito config is undefined\");\n\n let jitoTipLamports = BigInt(0);\n\n if (jito.type === \"exact\") {\n jitoTipLamports = jito.amountLamports;\n } else if (jito.type === \"dynamic\") {\n jitoTipLamports = await recentJitoTip(config);\n if (jito.maxCapLamports && jitoTipLamports > jito.maxCapLamports) {\n jitoTipLamports = jito.maxCapLamports;\n }\n }\n\n if (jitoTipLamports > 0) {\n return appendTransactionMessageInstruction(\n getTransferSolInstruction({\n source: signer,\n destination: getJitoTipAddress(),\n amount: jitoTipLamports,\n }),\n message,\n );\n } else {\n return message;\n }\n}\n\n// returns recent jito tip in lamports\nexport async function recentJitoTip(config: TransactionConfig) {\n const baseUrl = config.jitoBlockEngineUrl ?? DEFAULT_JITO_BLOCK_ENGINE_URL;\n const response = await fetch(`${baseUrl}/api/v1/bundles/tip_floor`);\n if (!response.ok) {\n return BigInt(0);\n }\n const data = await response.json().then(res => res[0]);\n\n const percentileToKey: Record<Percentile | \"50ema\", string> = {\n \"25\": \"landed_tips_25th_percentile\",\n \"50\": \"landed_tips_50th_percentile\",\n \"75\": \"landed_tips_75th_percentile\",\n \"95\": \"landed_tips_95th_percentile\",\n \"99\": \"landed_tips_99th_percentile\",\n \"50ema\": \"ema_landed_tips_50th_percentile\",\n };\n\n const key = percentileToKey[config.jito?.priorityFeePercentile ?? \"50\"];\n if (!key || !data[key]) {\n return BigInt(0);\n }\n return lamports(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();\n}\n\n// should we add an argument that dictates if we should use cached value in case fetch fails ?\n\n// below is taken from legacy sdk (no need to add the whole library)\n// https://jito-foundation.gitbook.io/mev/mev-payment-and-distribution/on-chain-addresses\nconst jitoTipAddresses = [\n \"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5\",\n \"HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe\",\n \"Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY\",\n \"ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49\",\n \"DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh\",\n \"ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt\",\n \"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL\",\n \"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT\",\n];\n\nfunction getJitoTipAddress(): Address {\n // just pick a random one from the list. There are multiple addresses so that no single one can cause local congestion.\n return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);\n}\n\ninterface JsonRpcResult {\n jsonrpc: string;\n id: number;\n result?: string; // bundle id\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\nexport async function sendJitoBundle(\n jitoApiUrl: JitoApiUrl,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n jitoUUID?: string,\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx)) as string[];\n\n const url = new URL(\"/api/v1/bundles\", jitoApiUrl);\n if (jitoUUID && jitoUUID.length > 0) {\n url.searchParams.set(\"uuid\", jitoUUID);\n }\n\n const request = {\n id: 1,\n jsonrpc: \"2.0\",\n method: \"sendBundle\",\n params: [\n encodedTransactions,\n {\n encoding: \"base64\",\n },\n ],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = (await response.json()) as JsonRpcResult;\n\n if (data.error) {\n throw new Error(`Jito bundle failed: ${data.error.code} ${data.error.message}`);\n }\n\n if (!data.result) {\n throw new Error(\"sendBundle did not return a bundle id\");\n }\n\n const bundleId = data.result;\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const request = {\n jsonrpc: \"2.0\",\n id: 1,\n method: \"getInflightBundleStatuses\",\n params: [[bundleId]],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = await response.json();\n const result = data.result?.value?.[0];\n if (!result) {\n throw new Error(`getInflightBundleStatuses method returned undefined result`, { cause: { bundleId } });\n }\n\n switch (result.status) {\n case \"Landed\":\n return bundleId;\n case \"Pending\":\n case \"Invalid\":\n continue;\n case \"Failed\":\n throw new Error(`Bundle failed`, { cause: { bundleId } });\n default:\n throw new Error(`Bundle status is unknown`, { cause: { bundleId } });\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n\nexport async function simulateBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<SimulateBundleResponse> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n return rpc\n .simulateBundle({\n encodedTransactions,\n })\n .send();\n}\n\nexport async function sendBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n const bundleId = await rpc\n .sendBundle(encodedTransactions, {\n encoding: \"base64\",\n })\n .send();\n\n if (!bundleId) throw new Error(`sendBundle method failed`);\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const statuses = await rpc.getBundleStatuses([bundleId]).send();\n\n const bundleStatus = statuses?.value?.[0];\n if (!bundleStatus) continue;\n\n if (bundleStatus.err && \"Err\" in bundleStatus.err) {\n throw new Error(`Bundle failed`, { cause: { bundleId, error: bundleStatus.err.Err } });\n } else {\n const confirmation_status = bundleStatus.confirmation_status;\n if (confirmation_status == \"confirmed\") {\n return bundleId;\n }\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n","import {\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n MaybeAccount,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { buildTransaction } from \"./buildTransaction\";\nimport { TransactionConfig } from \"./config\";\n\nconst CONFIRMATION_TIMEOUT_MS = 60_000;\nconst CONFIRMATION_POLL_INTERVAL_MS = 1_000;\nconst COMMITMENT_RANK: Record<Commitment, number> = { processed: 0, confirmed: 1, finalized: 2 };\n\n/**\n * Builds and sends a transaction with the given instructions, signers, and commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction.\n * @param {KeyPairSigner} payer - The fee payer for the transaction.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Address[]} [lookupTableAccounts] - Optional array of address lookup table accounts to use.\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction building or sending fails.\n *\n * @example\n * ```ts\n * const signature = await sendTransaction(\n * instructions,\n * keypairSigner,\n * DEFAULT_TRANSACTION_CONFIG,\n * lookupTables,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n payer: KeyPairSigner,\n config?: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);\n return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);\n}\n\n/**\n * Sends a signed transaction message to the Solana network with a specified commitment level.\n *\n * Confirmation semantics: the transaction is broadcast immediately and\n * re-broadcast every 10 s (leader-drop insurance); confirmation is polled via\n * `getSignatureStatuses` once per second, where any status at or beyond the\n * requested commitment counts (`\"finalized\"` satisfies `\"confirmed\"`) and an\n * on-chain execution error throws as soon as it is observed. Transient RPC\n * failures during polling do not fail the send — the transaction is already\n * in flight. Throws `\"Transaction expired\"` if the commitment is not reached\n * within 60 s.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.\n * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.\n * @param {boolean} skipSimulation - True if skip simulation\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If the initial broadcast fails, the transaction fails on-chain, or the transaction expires.\n *\n * @example\n * ```ts\n * const signature = await sendSignedTransaction(\n * rpc,\n * signedTransaction,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendSignedTransaction(\n rpc: Rpc<SolanaRpcApi>,\n transaction: SendableTransaction & Transaction & TransactionWithLifetime,\n skipSimulation: boolean = false,\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\n if (!skipSimulation) {\n // Simulate transaction first\n const simResult = await rpc\n .simulateTransaction(encodedTransaction, {\n encoding: \"base64\",\n })\n .send();\n\n if (simResult.value.err) {\n throw new Error(`Transaction simulation failed`, { cause: simResult.value });\n }\n }\n\n const expiryTime = Date.now() + CONFIRMATION_TIMEOUT_MS;\n\n await rpc\n .sendTransaction(encodedTransaction, {\n maxRetries: BigInt(0),\n skipPreflight: true,\n encoding: \"base64\",\n })\n .send();\n\n while (Date.now() < expiryTime) {\n const status = await pollSignatureStatus(rpc, txSignature);\n if (status) {\n if (status.err) {\n throw new Error(`Transaction failed`, { cause: status.err });\n }\n const { confirmationStatus } = status;\n const confirmationRank = confirmationStatus ? COMMITMENT_RANK[confirmationStatus] : -1;\n if (confirmationRank >= COMMITMENT_RANK[commitment]) {\n return txSignature;\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, CONFIRMATION_POLL_INTERVAL_MS));\n }\n\n throw new Error(\"Transaction expired\");\n}\n\nexport function getTxSignature(transaction: Transaction) {\n const [signature] = Object.values(transaction.signatures);\n return getBase58Decoder().decode(signature!) as Signature;\n}\n\n/**\n * Fetches the transaction's current status, or null when it is not yet\n * indexed — including on a transient RPC failure (rate limit, node\n * overload): the transaction is already in flight, and a failed status poll\n * must not fail the send.\n */\nasync function pollSignatureStatus(rpc: Rpc<SolanaRpcApi>, signature: Signature) {\n try {\n const { value } = await rpc.getSignatureStatuses([signature]).send();\n return value[0] ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":["import_kit","import_kit","JitoApiUrl","request","response","data","import_kit"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,7 @@
1
- import { BlockhashLifetimeConstraint, Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, MaybeAccount, SendableTransaction, Transaction, TransactionWithLifetime, TransactionMessage, TransactionMessageWithFeePayer, Signature, Commitment, KeyPairSigner } from '@solana/kit';
1
+ import * as _solana_kit from '@solana/kit';
2
+ import { BlockhashLifetimeConstraint, Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, MaybeAccount, SendableTransaction, Transaction, TransactionWithLifetime, TransactionMessageWithFeePayer, TransactionMessageWithSigners, TransactionMessage, Signature, Commitment, KeyPairSigner } from '@solana/kit';
2
3
  import { AddressLookupTable } from '@solana-program/address-lookup-table';
4
+ import * as _solana_transaction_messages_dist_types_v1_transaction_config from '@solana/transaction-messages/dist/types/v1-transaction-config';
3
5
 
4
6
  /**
5
7
  * Default compute unit margin multiplier used to ensure sufficient compute budget.
@@ -141,7 +143,19 @@ declare enum JitoApiUrl {
141
143
  Tokyo = "https://tokyo.mainnet.block-engine.jito.wtf",
142
144
  Default = "https://mainnet.block-engine.jito.wtf"
143
145
  }
144
- declare function processJitoTipForTxMessage(message: TransactionMessage & TransactionMessageWithFeePayer, signer: TransactionSigner, config: TransactionConfig): Promise<TransactionMessage & TransactionMessageWithFeePayer<string>>;
146
+ declare function processJitoTipForTxMessage(message: TransactionMessageWithFeePayer & TransactionMessageWithSigners & Exclude<TransactionMessage, {
147
+ version: "legacy";
148
+ }>, signer: TransactionSigner, config: TransactionConfig): Promise<TransactionMessageWithFeePayer<string> & Partial<Pick<TransactionMessageWithFeePayer<string> | _solana_kit.TransactionMessageWithFeePayerSigner<string, TransactionSigner<string>>, "feePayer">> & (Readonly<{
149
+ instructions: readonly (_solana_kit.Instruction<string, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string>)[]> & _solana_kit.InstructionWithSigners<TransactionSigner<string>, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string> | _solana_kit.AccountSignerMeta<string, TransactionSigner<string>>)[]>)[];
150
+ }> & (Readonly<{
151
+ instructions: readonly _solana_kit.Instruction<string, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string>)[]>[];
152
+ version: 0;
153
+ }> | (Readonly<{
154
+ instructions: readonly _solana_kit.Instruction<string, readonly _solana_kit.AccountMeta<string>[]>[];
155
+ version: 1;
156
+ }> & Readonly<{
157
+ config?: _solana_transaction_messages_dist_types_v1_transaction_config.V1TransactionConfig;
158
+ }>)))>;
145
159
  declare function recentJitoTip(config: TransactionConfig): Promise<bigint>;
146
160
  declare function sendJitoBundle(jitoApiUrl: JitoApiUrl, transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[], jitoUUID?: string): Promise<string>;
147
161
  declare function simulateBundle(rpc: Rpc<JitoRpcApi>, transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[]): Promise<SimulateBundleResponse>;
@@ -176,6 +190,15 @@ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instructi
176
190
  /**
177
191
  * Sends a signed transaction message to the Solana network with a specified commitment level.
178
192
  *
193
+ * Confirmation semantics: the transaction is broadcast immediately and
194
+ * re-broadcast every 10 s (leader-drop insurance); confirmation is polled via
195
+ * `getSignatureStatuses` once per second, where any status at or beyond the
196
+ * requested commitment counts (`"finalized"` satisfies `"confirmed"`) and an
197
+ * on-chain execution error throws as soon as it is observed. Transient RPC
198
+ * failures during polling do not fail the send — the transaction is already
199
+ * in flight. Throws `"Transaction expired"` if the commitment is not reached
200
+ * within 60 s.
201
+ *
179
202
  * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.
180
203
  * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.
181
204
  * @param {boolean} skipSimulation - True if skip simulation
@@ -183,7 +206,7 @@ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instructi
183
206
  *
184
207
  * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
185
208
  *
186
- * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.
209
+ * @throws {Error} If the initial broadcast fails, the transaction fails on-chain, or the transaction expires.
187
210
  *
188
211
  * @example
189
212
  * ```ts
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { BlockhashLifetimeConstraint, Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, MaybeAccount, SendableTransaction, Transaction, TransactionWithLifetime, TransactionMessage, TransactionMessageWithFeePayer, Signature, Commitment, KeyPairSigner } from '@solana/kit';
1
+ import * as _solana_kit from '@solana/kit';
2
+ import { BlockhashLifetimeConstraint, Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, MaybeAccount, SendableTransaction, Transaction, TransactionWithLifetime, TransactionMessageWithFeePayer, TransactionMessageWithSigners, TransactionMessage, Signature, Commitment, KeyPairSigner } from '@solana/kit';
2
3
  import { AddressLookupTable } from '@solana-program/address-lookup-table';
4
+ import * as _solana_transaction_messages_dist_types_v1_transaction_config from '@solana/transaction-messages/dist/types/v1-transaction-config';
3
5
 
4
6
  /**
5
7
  * Default compute unit margin multiplier used to ensure sufficient compute budget.
@@ -141,7 +143,19 @@ declare enum JitoApiUrl {
141
143
  Tokyo = "https://tokyo.mainnet.block-engine.jito.wtf",
142
144
  Default = "https://mainnet.block-engine.jito.wtf"
143
145
  }
144
- declare function processJitoTipForTxMessage(message: TransactionMessage & TransactionMessageWithFeePayer, signer: TransactionSigner, config: TransactionConfig): Promise<TransactionMessage & TransactionMessageWithFeePayer<string>>;
146
+ declare function processJitoTipForTxMessage(message: TransactionMessageWithFeePayer & TransactionMessageWithSigners & Exclude<TransactionMessage, {
147
+ version: "legacy";
148
+ }>, signer: TransactionSigner, config: TransactionConfig): Promise<TransactionMessageWithFeePayer<string> & Partial<Pick<TransactionMessageWithFeePayer<string> | _solana_kit.TransactionMessageWithFeePayerSigner<string, TransactionSigner<string>>, "feePayer">> & (Readonly<{
149
+ instructions: readonly (_solana_kit.Instruction<string, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string>)[]> & _solana_kit.InstructionWithSigners<TransactionSigner<string>, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string> | _solana_kit.AccountSignerMeta<string, TransactionSigner<string>>)[]>)[];
150
+ }> & (Readonly<{
151
+ instructions: readonly _solana_kit.Instruction<string, readonly (_solana_kit.AccountLookupMeta<string, string> | _solana_kit.AccountMeta<string>)[]>[];
152
+ version: 0;
153
+ }> | (Readonly<{
154
+ instructions: readonly _solana_kit.Instruction<string, readonly _solana_kit.AccountMeta<string>[]>[];
155
+ version: 1;
156
+ }> & Readonly<{
157
+ config?: _solana_transaction_messages_dist_types_v1_transaction_config.V1TransactionConfig;
158
+ }>)))>;
145
159
  declare function recentJitoTip(config: TransactionConfig): Promise<bigint>;
146
160
  declare function sendJitoBundle(jitoApiUrl: JitoApiUrl, transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[], jitoUUID?: string): Promise<string>;
147
161
  declare function simulateBundle(rpc: Rpc<JitoRpcApi>, transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[]): Promise<SimulateBundleResponse>;
@@ -176,6 +190,15 @@ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instructi
176
190
  /**
177
191
  * Sends a signed transaction message to the Solana network with a specified commitment level.
178
192
  *
193
+ * Confirmation semantics: the transaction is broadcast immediately and
194
+ * re-broadcast every 10 s (leader-drop insurance); confirmation is polled via
195
+ * `getSignatureStatuses` once per second, where any status at or beyond the
196
+ * requested commitment counts (`"finalized"` satisfies `"confirmed"`) and an
197
+ * on-chain execution error throws as soon as it is observed. Transient RPC
198
+ * failures during polling do not fail the send — the transaction is already
199
+ * in flight. Throws `"Transaction expired"` if the commitment is not reached
200
+ * within 60 s.
201
+ *
179
202
  * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.
180
203
  * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.
181
204
  * @param {boolean} skipSimulation - True if skip simulation
@@ -183,7 +206,7 @@ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instructi
183
206
  *
184
207
  * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
185
208
  *
186
- * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.
209
+ * @throws {Error} If the initial broadcast fails, the transaction fails on-chain, or the transaction expires.
187
210
  *
188
211
  * @example
189
212
  * ```ts
package/dist/index.js CHANGED
@@ -2,18 +2,28 @@
2
2
  import {
3
3
  appendTransactionMessageInstructions,
4
4
  assertAccountDecoded,
5
+ compileTransaction,
5
6
  compressTransactionMessageUsingAddressLookupTables,
6
7
  createNoopSigner,
7
8
  createTransactionMessage,
8
- estimateComputeUnitLimitFactory,
9
+ getBase64EncodedWireTransaction as getBase64EncodedWireTransaction2,
10
+ getSolanaErrorFromTransactionError,
11
+ isSolanaError,
9
12
  pipe,
10
13
  setTransactionMessageFeePayerSigner,
11
14
  setTransactionMessageLifetimeUsingBlockhash,
12
- signTransactionMessageWithSigners
15
+ signTransactionMessageWithSigners,
16
+ SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT,
17
+ SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT,
18
+ SolanaError
13
19
  } from "@solana/kit";
20
+ import { isTransactionMessageWithDurableNonceLifetime } from "@solana/transaction-messages";
14
21
 
15
22
  // src/computeBudget.ts
16
- import { isWritableRole, prependTransactionMessageInstruction } from "@solana/kit";
23
+ import {
24
+ isWritableRole,
25
+ prependTransactionMessageInstruction
26
+ } from "@solana/kit";
17
27
  import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from "@solana-program/compute-budget";
18
28
 
19
29
  // src/config.ts
@@ -83,10 +93,11 @@ async function calculateDynamicPriorityFees(rpc, instructions, percentile) {
83
93
 
84
94
  // src/jito.ts
85
95
  import {
96
+ address,
86
97
  appendTransactionMessageInstruction,
87
- getBase64EncodedWireTransaction
98
+ getBase64EncodedWireTransaction,
99
+ lamports
88
100
  } from "@solana/kit";
89
- import { address, lamports } from "@solana/kit";
90
101
  import { getTransferSolInstruction } from "@solana-program/system";
91
102
  var JITO_BUNDLE_EXPIRY_TIME = 3e4;
92
103
  var JitoApiUrl = /* @__PURE__ */ ((JitoApiUrl2) => {
@@ -280,6 +291,8 @@ async function buildTransactionMessage(rpc, instructions, signer, config, lookup
280
291
  }).send()).value;
281
292
  }
282
293
  let message = await prepareTransactionMessage(instructions, signer, blockhash);
294
+ let computeUnits = 14e5;
295
+ let messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);
283
296
  if (lookupTableAccounts?.length) {
284
297
  const tables = lookupTableAccounts.reduce(
285
298
  (prev, account) => {
@@ -291,10 +304,30 @@ async function buildTransactionMessage(rpc, instructions, signer, config, lookup
291
304
  },
292
305
  {}
293
306
  );
294
- message = compressTransactionMessageUsingAddressLookupTables(message, tables);
307
+ messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);
308
+ }
309
+ if (!config.skipSimulation) {
310
+ try {
311
+ computeUnits = await getComputeUnitsForTxMessage(rpc, messageWithExtra);
312
+ messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);
313
+ if (lookupTableAccounts?.length) {
314
+ const tables = lookupTableAccounts.reduce(
315
+ (prev, account) => {
316
+ if (account.exists) {
317
+ assertAccountDecoded(account);
318
+ prev[account.address] = account.data.addresses;
319
+ }
320
+ return prev;
321
+ },
322
+ {}
323
+ );
324
+ messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);
325
+ }
326
+ } catch (e) {
327
+ console.warn("Transaction simulation failed, using 1,400,000 compute units: ", e);
328
+ }
295
329
  }
296
- const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);
297
- return signTransactionMessageWithSigners(messageWithExtraInstructions);
330
+ return signTransactionMessageWithSigners(messageWithExtra);
298
331
  }
299
332
  async function prepareTransactionMessage(instructions, signer, blockhash) {
300
333
  return pipe(
@@ -304,36 +337,58 @@ async function prepareTransactionMessage(instructions, signer, blockhash) {
304
337
  (tx) => appendTransactionMessageInstructions(instructions, tx)
305
338
  );
306
339
  }
307
- async function addPriorityInstructions(rpc, message, signer, config) {
340
+ async function addPriorityInstructions(rpc, message, signer, config, computeUnits) {
308
341
  if (config.jito && config.jito.type !== "none") {
309
342
  message = await processJitoTipForTxMessage(message, signer, config);
310
343
  }
311
- let computeUnits = 14e5;
312
- if (!config.skipSimulation) {
313
- try {
314
- computeUnits = await getComputeUnitsForTxMessage(rpc, message);
315
- } catch {
316
- console.warn("Transaction simulation failed, using 1,400,000 compute units");
317
- }
318
- }
319
344
  return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);
320
345
  }
321
- async function getComputeUnitsForTxMessage(rpc, txMessage) {
322
- return await estimateComputeUnitLimitFactory({ rpc })(txMessage);
346
+ async function getComputeUnitsForTxMessage(rpc, message) {
347
+ const replaceRecentBlockhash = !isTransactionMessageWithDurableNonceLifetime(message);
348
+ const transaction = pipe(message, compileTransaction);
349
+ const wireTransactionBytes = getBase64EncodedWireTransaction2(transaction);
350
+ try {
351
+ const response = await rpc.simulateTransaction(wireTransactionBytes, {
352
+ encoding: "base64",
353
+ replaceRecentBlockhash,
354
+ sigVerify: false
355
+ }).send();
356
+ const { err: transactionError, ...simulationResult } = response.value;
357
+ if (simulationResult.unitsConsumed == null) {
358
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT);
359
+ }
360
+ if (transactionError) {
361
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT, {
362
+ ...simulationResult,
363
+ cause: getSolanaErrorFromTransactionError(transactionError)
364
+ });
365
+ }
366
+ return simulationResult.unitsConsumed > 4294967295n ? 4294967295 : Number(simulationResult.unitsConsumed);
367
+ } catch (e) {
368
+ if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT)) {
369
+ throw e;
370
+ }
371
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT, {
372
+ cause: e
373
+ });
374
+ }
323
375
  }
324
376
 
325
377
  // src/sendTransaction.ts
326
378
  import {
327
379
  getBase58Decoder,
328
- getBase64EncodedWireTransaction as getBase64EncodedWireTransaction2
380
+ getBase64EncodedWireTransaction as getBase64EncodedWireTransaction3
329
381
  } from "@solana/kit";
382
+ var CONFIRMATION_TIMEOUT_MS = 6e4;
383
+ var CONFIRMATION_POLL_INTERVAL_MS = 1e3;
384
+ var COMMITMENT_RANK = { processed: 0, confirmed: 1, finalized: 2 };
330
385
  async function sendTransaction(rpc, instructions, payer, config, lookupTableAccounts, commitment = "confirmed") {
331
386
  const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);
332
387
  return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);
333
388
  }
334
389
  async function sendSignedTransaction(rpc, transaction, skipSimulation = false, commitment = "confirmed") {
335
390
  const txSignature = getTxSignature(transaction);
336
- const encodedTransaction = getBase64EncodedWireTransaction2(transaction);
391
+ const encodedTransaction = getBase64EncodedWireTransaction3(transaction);
337
392
  if (!skipSimulation) {
338
393
  const simResult = await rpc.simulateTransaction(encodedTransaction, {
339
394
  encoding: "base64"
@@ -342,21 +397,25 @@ async function sendSignedTransaction(rpc, transaction, skipSimulation = false, c
342
397
  throw new Error(`Transaction simulation failed`, { cause: simResult.value });
343
398
  }
344
399
  }
345
- const expiryTime = Date.now() + 6e4;
400
+ const expiryTime = Date.now() + CONFIRMATION_TIMEOUT_MS;
401
+ await rpc.sendTransaction(encodedTransaction, {
402
+ maxRetries: BigInt(0),
403
+ skipPreflight: true,
404
+ encoding: "base64"
405
+ }).send();
346
406
  while (Date.now() < expiryTime) {
347
- await rpc.sendTransaction(encodedTransaction, {
348
- maxRetries: BigInt(0),
349
- skipPreflight: true,
350
- encoding: "base64"
351
- }).send();
352
- const { value } = await rpc.getSignatureStatuses([txSignature]).send();
353
- const status = value[0];
354
- if (status?.confirmationStatus === commitment) {
407
+ const status = await pollSignatureStatus(rpc, txSignature);
408
+ if (status) {
355
409
  if (status.err) {
356
410
  throw new Error(`Transaction failed`, { cause: status.err });
357
411
  }
358
- return txSignature;
412
+ const { confirmationStatus } = status;
413
+ const confirmationRank = confirmationStatus ? COMMITMENT_RANK[confirmationStatus] : -1;
414
+ if (confirmationRank >= COMMITMENT_RANK[commitment]) {
415
+ return txSignature;
416
+ }
359
417
  }
418
+ await new Promise((resolve) => setTimeout(resolve, CONFIRMATION_POLL_INTERVAL_MS));
360
419
  }
361
420
  throw new Error("Transaction expired");
362
421
  }
@@ -364,6 +423,14 @@ function getTxSignature(transaction) {
364
423
  const [signature] = Object.values(transaction.signatures);
365
424
  return getBase58Decoder().decode(signature);
366
425
  }
426
+ async function pollSignatureStatus(rpc, signature) {
427
+ try {
428
+ const { value } = await rpc.getSignatureStatuses([signature]).send();
429
+ return value[0] ?? null;
430
+ } catch {
431
+ return null;
432
+ }
433
+ }
367
434
  export {
368
435
  DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
369
436
  DEFAULT_JITO_BLOCK_ENGINE_URL,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/buildTransaction.ts","../src/computeBudget.ts","../src/config.ts","../src/jito.ts","../src/sendTransaction.ts"],"sourcesContent":["import {\n Address,\n appendTransactionMessageInstructions,\n assertAccountDecoded,\n BlockhashLifetimeConstraint,\n compressTransactionMessageUsingAddressLookupTables,\n createNoopSigner,\n createTransactionMessage,\n estimateComputeUnitLimitFactory,\n Instruction,\n MaybeAccount,\n pipe,\n Rpc,\n SendableTransaction,\n setTransactionMessageFeePayerSigner,\n setTransactionMessageLifetimeUsingBlockhash,\n signTransactionMessageWithSigners,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { processComputeBudgetForTxMessage } from \"./computeBudget.ts\";\nimport { TransactionConfig } from \"./config\";\nimport { processJitoTipForTxMessage } from \"./jito.ts\";\n\n/**\n * Builds and signs a transaction from the given instructions and configuration.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction\n * @param {TransactionSigner} feePayer - The signer that will pay for the transaction\n * @param {(Address | string)[]} [lookupTableAccounts] - Optional array of address lookup table accounts to compress the transaction\n *\n * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction\n *\n * @example\n * const instructions = [createATAix, createTransferSolInstruction];\n * const feePayer = wallet.publicKey;\n * const message = await buildTransaction(\n * rpc,\n * instructions,\n * feePayer,\n * );\n */\nexport async function buildTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n feePayer: TransactionSigner | Address,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n config,\n lookupTableAccounts,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n signer: TransactionSigner,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n) {\n let blockhash = config.blockhash;\n if (!blockhash) {\n blockhash = (\n await rpc\n .getLatestBlockhash({\n commitment: \"confirmed\",\n })\n .send()\n ).value;\n }\n\n let message = await prepareTransactionMessage(instructions, signer, blockhash);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n message = compressTransactionMessageUsingAddressLookupTables(message, tables);\n }\n\n const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);\n\n return signTransactionMessageWithSigners(messageWithExtraInstructions);\n}\n\nasync function prepareTransactionMessage(\n instructions: Instruction[],\n signer: TransactionSigner,\n blockhash: BlockhashLifetimeConstraint,\n) {\n return pipe(\n createTransactionMessage({ version: 0 }),\n tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),\n tx => setTransactionMessageFeePayerSigner(signer, tx),\n tx => appendTransactionMessageInstructions(instructions, tx),\n );\n}\n\nasync function addPriorityInstructions(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessage & TransactionMessageWithFeePayer,\n signer: TransactionSigner,\n config: TransactionConfig,\n): Promise<TransactionMessage & TransactionMessageWithFeePayer> {\n if (config.jito && config.jito.type !== \"none\") {\n message = await processJitoTipForTxMessage(message, signer, config);\n }\n\n let computeUnits = 1_400_000;\n\n if (!config.skipSimulation) {\n try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, message);\n } catch {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units\");\n }\n }\n\n return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);\n}\n\nasync function getComputeUnitsForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n txMessage: TransactionMessage & TransactionMessageWithFeePayer,\n) {\n return await estimateComputeUnitLimitFactory({ rpc })(txMessage);\n}\n","import {\n Address,\n Instruction,\n Rpc,\n SolanaRpcApi,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n} from \"@solana/kit\";\nimport { isWritableRole, prependTransactionMessageInstruction } from \"@solana/kit\";\nimport { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from \"@solana-program/compute-budget\";\n\nimport type { Percentile, TransactionConfig } from \"./config\";\nimport { DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER } from \"./config\";\n\nexport async function processComputeBudgetForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessage & TransactionMessageWithFeePayer,\n computeUnits: number,\n config: TransactionConfig,\n) {\n const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;\n let priorityFeeMicroLamports = 0n;\n\n const units = Math.min(\n 1_400_000,\n Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\n );\n\n const priorityFee = config.priorityFee;\n if (priorityFee) {\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / BigInt(units);\n } else if (priorityFee.type === \"dynamic\") {\n const estimatedPriorityFee = await calculateDynamicPriorityFees(\n rpc,\n message.instructions,\n priorityFee.priorityFeePercentile ?? \"50\",\n );\n\n if (!priorityFee.maxCapLamports) {\n priorityFeeMicroLamports = estimatedPriorityFee;\n } else {\n const maxCapMicroLamports = (priorityFee.maxCapLamports * 1_000_000n) / BigInt(units);\n priorityFeeMicroLamports =\n maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;\n }\n }\n }\n\n if (priorityFeeMicroLamports > 0) {\n message = prependTransactionMessageInstruction(\n getSetComputeUnitPriceInstruction({\n microLamports: priorityFeeMicroLamports,\n }),\n message,\n );\n }\n\n message = prependTransactionMessageInstruction(\n getSetComputeUnitLimitInstruction({\n units,\n }),\n message,\n );\n\n return message;\n}\n\nfunction getWritableAccounts(ixs: readonly Instruction[]) {\n const writable = new Set<Address>();\n ixs.forEach(ix => {\n if (ix.accounts) {\n ix.accounts.forEach(acc => {\n if (isWritableRole(acc.role)) writable.add(acc.address);\n });\n }\n });\n return Array.from(writable);\n}\n\nasync function calculateDynamicPriorityFees(\n rpc: Rpc<SolanaRpcApi>,\n instructions: readonly Instruction[],\n percentile: Percentile,\n) {\n const writableAccounts = getWritableAccounts(instructions);\n const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();\n const nonZero = recent.filter(pf => pf.prioritizationFee > 0).map(pf => pf.prioritizationFee);\n const sorted = nonZero.sort((a, b) => Number(a - b));\n return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);\n}\n","import { BlockhashLifetimeConstraint } from \"@solana/kit\";\n\n/**\n * Default compute unit margin multiplier used to ensure sufficient compute budget.\n */\nexport const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;\nexport const DEFAULT_JITO_BLOCK_ENGINE_URL = \"https://bundles.jito.wtf\";\n\ntype FeeSetting =\n | {\n type: \"dynamic\";\n maxCapLamports?: bigint;\n }\n | {\n type: \"exact\";\n amountLamports: bigint;\n }\n | {\n type: \"none\";\n };\n\n/**\n * Configuration for transaction fees, including Jito and priority fee settings.\n */\nexport type JitoFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile | \"50ema\";\n};\n\nexport type PriorityFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile;\n};\n\n/**\n * Defines a percentile value for priority fee selection.\n */\nexport type Percentile = \"25\" | \"50\" | \"75\" | \"95\" | \"99\";\n\nexport type TransactionConfig = {\n jito?: JitoFeeSetting;\n priorityFee?: PriorityFeeSetting;\n computeUnitMarginMultiplier?: number;\n jitoBlockEngineUrl?: string;\n skipSimulation?: boolean;\n blockhash?: BlockhashLifetimeConstraint;\n};\n","import {\n Address,\n appendTransactionMessageInstruction,\n getBase64EncodedWireTransaction,\n Rpc,\n SendableTransaction,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { address, lamports } from \"@solana/kit\";\nimport { getTransferSolInstruction } from \"@solana-program/system\";\n\nimport { DEFAULT_JITO_BLOCK_ENGINE_URL, type Percentile, TransactionConfig } from \"./config\";\n\nconst JITO_BUNDLE_EXPIRY_TIME = 30_000;\n\nexport type AccountConfig = {\n accountIndex: number;\n addresses: string[];\n};\n\nexport type JitoAccountInfo = {\n executable: boolean;\n owner: string;\n lamports: number;\n data: string;\n rentEpoch: number;\n};\n\nexport type JitoRpcApi = SolanaRpcApi & {\n simulateBundle: (\n params: {\n encodedTransactions: string[];\n },\n config?: {\n preExecutionAccountsConfigs?: AccountConfig;\n postExecutionAccountsConfigs?: AccountConfig;\n skipSigVerify?: boolean;\n simulationBank?: {\n commitment?: {\n commitment: \"processed\" | \"confirmed\" | \"finalized\";\n };\n };\n transactionEncoding?: \"base64\";\n replaceRecentBlockhash?: boolean;\n },\n ) => SimulateBundleResponse;\n\n sendBundle: (\n params: string[],\n config?: {\n encoding?: \"base64\";\n },\n ) => string;\n\n getBundleStatuses: (params: string[]) => GetBundleStatusesResponse;\n};\n\nexport type SimulateBundleResponse = {\n context: {\n slot: number;\n apiVersion?: string;\n };\n value: {\n summary: \"succeeded\" | { failed: { error: unknown; tx_signature: string } };\n transactionResults: Array<{\n err: unknown;\n logs: string[] | null;\n unitsConsumed?: number;\n returnData: {\n programId: string;\n data: string;\n } | null;\n preExecutionAccounts: JitoAccountInfo[] | null;\n postExecutionAccounts: JitoAccountInfo[] | null;\n }>;\n };\n};\n\nexport type GetBundleStatusesResponse = {\n context: {\n slot: number;\n };\n value: Array<{\n bundleId: string;\n transactions: string[];\n slot: number;\n confirmation_status: \"processed\" | \"confirmed\" | \"finalized\";\n err:\n | {\n Ok: null;\n }\n | {\n Err: object;\n };\n }>;\n};\n\nexport enum JitoApiUrl {\n Amsterdam = \"https://amsterdam.mainnet.block-engine.jito.wtf\",\n Frankfurt = \"https://frankfurt.mainnet.block-engine.jito.wtf\",\n London = \"https://london.mainnet.block-engine.jito.wtf\",\n NY = \"https://ny.mainnet.block-engine.jito.wtf\",\n Singapore = \"https://singapore.mainnet.block-engine.jito.wtf\",\n SLC = \"https://slc.mainnet.block-engine.jito.wtf\",\n Tokyo = \"https://tokyo.mainnet.block-engine.jito.wtf\",\n Default = \"https://mainnet.block-engine.jito.wtf\",\n}\n\nexport async function processJitoTipForTxMessage(\n message: TransactionMessage & TransactionMessageWithFeePayer,\n signer: TransactionSigner,\n config: TransactionConfig,\n) {\n const jito = config.jito;\n if (!jito) throw new Error(\"jito config is undefined\");\n\n let jitoTipLamports = BigInt(0);\n\n if (jito.type === \"exact\") {\n jitoTipLamports = jito.amountLamports;\n } else if (jito.type === \"dynamic\") {\n jitoTipLamports = await recentJitoTip(config);\n if (jito.maxCapLamports && jitoTipLamports > jito.maxCapLamports) {\n jitoTipLamports = jito.maxCapLamports;\n }\n }\n\n if (jitoTipLamports > 0) {\n return appendTransactionMessageInstruction(\n getTransferSolInstruction({\n source: signer,\n destination: getJitoTipAddress(),\n amount: jitoTipLamports,\n }),\n message,\n );\n } else {\n return message;\n }\n}\n\n// returns recent jito tip in lamports\nexport async function recentJitoTip(config: TransactionConfig) {\n const baseUrl = config.jitoBlockEngineUrl ?? DEFAULT_JITO_BLOCK_ENGINE_URL;\n const response = await fetch(`${baseUrl}/api/v1/bundles/tip_floor`);\n if (!response.ok) {\n return BigInt(0);\n }\n const data = await response.json().then(res => res[0]);\n\n const percentileToKey: Record<Percentile | \"50ema\", string> = {\n \"25\": \"landed_tips_25th_percentile\",\n \"50\": \"landed_tips_50th_percentile\",\n \"75\": \"landed_tips_75th_percentile\",\n \"95\": \"landed_tips_95th_percentile\",\n \"99\": \"landed_tips_99th_percentile\",\n \"50ema\": \"ema_landed_tips_50th_percentile\",\n };\n\n const key = percentileToKey[config.jito?.priorityFeePercentile ?? \"50\"];\n if (!key || !data[key]) {\n return BigInt(0);\n }\n return lamports(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();\n}\n\n// should we add an argument that dictates if we should use cached value in case fetch fails ?\n\n// below is taken from legacy sdk (no need to add the whole library)\n// https://jito-foundation.gitbook.io/mev/mev-payment-and-distribution/on-chain-addresses\nconst jitoTipAddresses = [\n \"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5\",\n \"HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe\",\n \"Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY\",\n \"ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49\",\n \"DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh\",\n \"ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt\",\n \"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL\",\n \"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT\",\n];\n\nfunction getJitoTipAddress(): Address {\n // just pick a random one from the list. There are multiple addresses so that no single one can cause local congestion.\n return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);\n}\n\ninterface JsonRpcResult {\n jsonrpc: string;\n id: number;\n result?: string; // bundle id\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\nexport async function sendJitoBundle(\n jitoApiUrl: JitoApiUrl,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n jitoUUID?: string,\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx)) as string[];\n\n const url = new URL(\"/api/v1/bundles\", jitoApiUrl);\n if (jitoUUID && jitoUUID.length > 0) {\n url.searchParams.set(\"uuid\", jitoUUID);\n }\n\n const request = {\n id: 1,\n jsonrpc: \"2.0\",\n method: \"sendBundle\",\n params: [\n encodedTransactions,\n {\n encoding: \"base64\",\n },\n ],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = (await response.json()) as JsonRpcResult;\n\n if (data.error) {\n throw new Error(`Jito bundle failed: ${data.error.code} ${data.error.message}`);\n }\n\n if (!data.result) {\n throw new Error(\"sendBundle did not return a bundle id\");\n }\n\n const bundleId = data.result;\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const request = {\n jsonrpc: \"2.0\",\n id: 1,\n method: \"getInflightBundleStatuses\",\n params: [[bundleId]],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = await response.json();\n const result = data.result?.value?.[0];\n if (!result) {\n throw new Error(`getInflightBundleStatuses method returned undefined result`, { cause: { bundleId } });\n }\n\n switch (result.status) {\n case \"Landed\":\n return bundleId;\n case \"Pending\":\n case \"Invalid\":\n continue;\n case \"Failed\":\n throw new Error(`Bundle failed`, { cause: { bundleId } });\n default:\n throw new Error(`Bundle status is unknown`, { cause: { bundleId } });\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n\nexport async function simulateBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<SimulateBundleResponse> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n return rpc\n .simulateBundle({\n encodedTransactions,\n })\n .send();\n}\n\nexport async function sendBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n const bundleId = await rpc\n .sendBundle(encodedTransactions, {\n encoding: \"base64\",\n })\n .send();\n\n if (!bundleId) throw new Error(`sendBundle method failed`);\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const statuses = await rpc.getBundleStatuses([bundleId]).send();\n\n const bundleStatus = statuses?.value?.[0];\n if (!bundleStatus) continue;\n\n if (bundleStatus.err && \"Err\" in bundleStatus.err) {\n throw new Error(`Bundle failed`, { cause: { bundleId, error: bundleStatus.err.Err } });\n } else {\n const confirmation_status = bundleStatus.confirmation_status;\n if (confirmation_status == \"confirmed\") {\n return bundleId;\n }\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n","import {\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n MaybeAccount,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { buildTransaction } from \"./buildTransaction\";\nimport { TransactionConfig } from \"./config\";\n\n/**\n * Builds and sends a transaction with the given instructions, signers, and commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction.\n * @param {KeyPairSigner} payer - The fee payer for the transaction.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Address[]} [lookupTableAccounts] - Optional array of address lookup table accounts to use.\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction building or sending fails.\n *\n * @example\n * ```ts\n * const signature = await sendTransaction(\n * instructions,\n * keypairSigner,\n * DEFAULT_TRANSACTION_CONFIG,\n * lookupTables,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n payer: KeyPairSigner,\n config?: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);\n return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);\n}\n\n/**\n * Sends a signed transaction message to the Solana network with a specified commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.\n * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.\n * @param {boolean} skipSimulation - True if skip simulation\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.\n *\n * @example\n * ```ts\n * const signature = await sendSignedTransaction(\n * rpc,\n * signedTransaction,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendSignedTransaction(\n rpc: Rpc<SolanaRpcApi>,\n transaction: SendableTransaction & Transaction & TransactionWithLifetime,\n skipSimulation: boolean = false,\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\n if (!skipSimulation) {\n // Simulate transaction first\n const simResult = await rpc\n .simulateTransaction(encodedTransaction, {\n encoding: \"base64\",\n })\n .send();\n\n if (simResult.value.err) {\n throw new Error(`Transaction simulation failed`, { cause: simResult.value });\n }\n }\n\n const expiryTime = Date.now() + 60_000;\n\n while (Date.now() < expiryTime) {\n await rpc\n .sendTransaction(encodedTransaction, {\n maxRetries: BigInt(0),\n skipPreflight: true,\n encoding: \"base64\",\n })\n .send();\n\n const { value } = await rpc.getSignatureStatuses([txSignature]).send();\n const status = value[0];\n if (status?.confirmationStatus === commitment) {\n if (status.err) {\n throw new Error(`Transaction failed`, { cause: status.err });\n }\n return txSignature;\n }\n }\n\n throw new Error(\"Transaction expired\");\n}\n\nexport function getTxSignature(transaction: Transaction) {\n const [signature] = Object.values(transaction.signatures);\n return getBase58Decoder().decode(signature!) as Signature;\n}\n"],"mappings":"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","names":["JitoApiUrl","request","response","data","getBase64EncodedWireTransaction","getBase64EncodedWireTransaction"]}
1
+ {"version":3,"sources":["../src/buildTransaction.ts","../src/computeBudget.ts","../src/config.ts","../src/jito.ts","../src/sendTransaction.ts"],"sourcesContent":["import {\n Address,\n appendTransactionMessageInstructions,\n assertAccountDecoded,\n BlockhashLifetimeConstraint,\n compileTransaction,\n compressTransactionMessageUsingAddressLookupTables,\n createNoopSigner,\n createTransactionMessage,\n getBase64EncodedWireTransaction,\n getSolanaErrorFromTransactionError,\n Instruction,\n isSolanaError,\n MaybeAccount,\n pipe,\n Rpc,\n RpcSimulateTransactionResult,\n SendableTransaction,\n setTransactionMessageFeePayerSigner,\n setTransactionMessageLifetimeUsingBlockhash,\n signTransactionMessageWithSigners,\n SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT,\n SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT,\n SolanaError,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { isTransactionMessageWithDurableNonceLifetime } from \"@solana/transaction-messages\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { processComputeBudgetForTxMessage } from \"./computeBudget.ts\";\nimport { TransactionConfig } from \"./config\";\nimport { processJitoTipForTxMessage } from \"./jito.ts\";\n\n/**\n * Builds and signs a transaction from the given instructions and configuration.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction\n * @param {TransactionSigner} feePayer - The signer that will pay for the transaction\n * @param {(Address | string)[]} [lookupTableAccounts] - Optional array of address lookup table accounts to compress the transaction\n *\n * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction\n *\n * @example\n * const instructions = [createATAix, createTransferSolInstruction];\n * const feePayer = wallet.publicKey;\n * const message = await buildTransaction(\n * rpc,\n * instructions,\n * feePayer,\n * );\n */\nexport async function buildTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n feePayer: TransactionSigner | Address,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n config,\n lookupTableAccounts,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n signer: TransactionSigner,\n config: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n) {\n let blockhash = config.blockhash;\n if (!blockhash) {\n blockhash = (\n await rpc\n .getLatestBlockhash({\n commitment: \"confirmed\",\n })\n .send()\n ).value;\n }\n\n let message = await prepareTransactionMessage(instructions, signer, blockhash);\n\n let computeUnits = 1_400_000;\n let messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);\n }\n\n if (!config.skipSimulation) {\n try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, messageWithExtra);\n\n // Rebuild the message\n messageWithExtra = await addPriorityInstructions(rpc, message, signer, config, computeUnits);\n\n if (lookupTableAccounts?.length) {\n const tables = lookupTableAccounts.reduce(\n (prev, account) => {\n if (account.exists) {\n assertAccountDecoded(account);\n prev[account.address] = account.data.addresses;\n }\n return prev;\n },\n {} as { [address: Address]: Address[] },\n );\n messageWithExtra = compressTransactionMessageUsingAddressLookupTables(messageWithExtra, tables);\n }\n } catch (e) {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units: \", e);\n }\n }\n\n return signTransactionMessageWithSigners(messageWithExtra);\n}\n\nasync function prepareTransactionMessage(\n instructions: Instruction[],\n signer: TransactionSigner,\n blockhash: BlockhashLifetimeConstraint,\n) {\n return pipe(\n createTransactionMessage({ version: 0 }),\n tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),\n tx => setTransactionMessageFeePayerSigner(signer, tx),\n tx => appendTransactionMessageInstructions(instructions, tx),\n );\n}\n\nasync function addPriorityInstructions(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n signer: TransactionSigner,\n config: TransactionConfig,\n computeUnits: number,\n) {\n if (config.jito && config.jito.type !== \"none\") {\n message = await processJitoTipForTxMessage(message, signer, config);\n }\n\n return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);\n}\n\nasync function getComputeUnitsForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n) {\n const replaceRecentBlockhash = !isTransactionMessageWithDurableNonceLifetime(message);\n\n const transaction = pipe(message, compileTransaction);\n const wireTransactionBytes = getBase64EncodedWireTransaction(transaction);\n\n try {\n const response = await rpc\n .simulateTransaction(wireTransactionBytes, {\n encoding: \"base64\",\n replaceRecentBlockhash,\n sigVerify: false,\n })\n .send();\n // The API response type varies based on config (eg. `replacementBlockhash` is only\n // present when `replaceRecentBlockhash` is true), but `RpcSimulateTransactionResult`\n // is a flat superset. Cast through `unknown` to bridge the structural gap.\n const { err: transactionError, ...simulationResult } = response.value as unknown as RpcSimulateTransactionResult;\n\n if (simulationResult.unitsConsumed == null) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT);\n }\n\n if (transactionError) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT, {\n ...simulationResult,\n cause: getSolanaErrorFromTransactionError(transactionError),\n });\n }\n\n // Downcast from bigint to number, capping at u32 max.\n return simulationResult.unitsConsumed > 4_294_967_295n ? 4_294_967_295 : Number(simulationResult.unitsConsumed);\n } catch (e) {\n if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__FAILED_WHEN_SIMULATING_TO_ESTIMATE_COMPUTE_LIMIT)) {\n throw e;\n }\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FAILED_TO_ESTIMATE_COMPUTE_LIMIT, {\n cause: e,\n });\n }\n}\n","import {\n Address,\n Instruction,\n isWritableRole,\n prependTransactionMessageInstruction,\n Rpc,\n SolanaRpcApi,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n} from \"@solana/kit\";\nimport { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from \"@solana-program/compute-budget\";\n\nimport type { Percentile, TransactionConfig } from \"./config\";\nimport { DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER } from \"./config\";\n\nexport async function processComputeBudgetForTxMessage(\n rpc: Rpc<SolanaRpcApi>,\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n computeUnits: number,\n config: TransactionConfig,\n) {\n const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;\n let priorityFeeMicroLamports = 0n;\n\n const units = Math.min(\n 1_400_000,\n Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\n );\n\n const priorityFee = config.priorityFee;\n if (priorityFee) {\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / BigInt(units);\n } else if (priorityFee.type === \"dynamic\") {\n const estimatedPriorityFee = await calculateDynamicPriorityFees(\n rpc,\n message.instructions,\n priorityFee.priorityFeePercentile ?? \"50\",\n );\n\n if (!priorityFee.maxCapLamports) {\n priorityFeeMicroLamports = estimatedPriorityFee;\n } else {\n const maxCapMicroLamports = (priorityFee.maxCapLamports * 1_000_000n) / BigInt(units);\n priorityFeeMicroLamports =\n maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;\n }\n }\n }\n\n if (priorityFeeMicroLamports > 0) {\n message = prependTransactionMessageInstruction(\n getSetComputeUnitPriceInstruction({\n microLamports: priorityFeeMicroLamports,\n }),\n message,\n );\n }\n\n message = prependTransactionMessageInstruction(\n getSetComputeUnitLimitInstruction({\n units,\n }),\n message,\n );\n\n return message;\n}\n\nfunction getWritableAccounts(ixs: readonly Instruction[]) {\n const writable = new Set<Address>();\n ixs.forEach(ix => {\n if (ix.accounts) {\n ix.accounts.forEach(acc => {\n if (isWritableRole(acc.role)) writable.add(acc.address);\n });\n }\n });\n return Array.from(writable);\n}\n\nasync function calculateDynamicPriorityFees(\n rpc: Rpc<SolanaRpcApi>,\n instructions: readonly Instruction[],\n percentile: Percentile,\n) {\n const writableAccounts = getWritableAccounts(instructions);\n const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();\n const nonZero = recent.filter(pf => pf.prioritizationFee > 0).map(pf => pf.prioritizationFee);\n const sorted = nonZero.sort((a, b) => Number(a - b));\n return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);\n}\n","import { BlockhashLifetimeConstraint } from \"@solana/kit\";\n\n/**\n * Default compute unit margin multiplier used to ensure sufficient compute budget.\n */\nexport const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;\nexport const DEFAULT_JITO_BLOCK_ENGINE_URL = \"https://bundles.jito.wtf\";\n\ntype FeeSetting =\n | {\n type: \"dynamic\";\n maxCapLamports?: bigint;\n }\n | {\n type: \"exact\";\n amountLamports: bigint;\n }\n | {\n type: \"none\";\n };\n\n/**\n * Configuration for transaction fees, including Jito and priority fee settings.\n */\nexport type JitoFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile | \"50ema\";\n};\n\nexport type PriorityFeeSetting = FeeSetting & {\n priorityFeePercentile?: Percentile;\n};\n\n/**\n * Defines a percentile value for priority fee selection.\n */\nexport type Percentile = \"25\" | \"50\" | \"75\" | \"95\" | \"99\";\n\nexport type TransactionConfig = {\n jito?: JitoFeeSetting;\n priorityFee?: PriorityFeeSetting;\n computeUnitMarginMultiplier?: number;\n jitoBlockEngineUrl?: string;\n skipSimulation?: boolean;\n blockhash?: BlockhashLifetimeConstraint;\n};\n","import {\n Address,\n address,\n appendTransactionMessageInstruction,\n getBase64EncodedWireTransaction,\n lamports,\n Rpc,\n SendableTransaction,\n SolanaRpcApi,\n Transaction,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithSigners,\n TransactionSigner,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { getTransferSolInstruction } from \"@solana-program/system\";\n\nimport { DEFAULT_JITO_BLOCK_ENGINE_URL, type Percentile, TransactionConfig } from \"./config\";\n\nconst JITO_BUNDLE_EXPIRY_TIME = 30_000;\n\nexport type AccountConfig = {\n accountIndex: number;\n addresses: string[];\n};\n\nexport type JitoAccountInfo = {\n executable: boolean;\n owner: string;\n lamports: number;\n data: string;\n rentEpoch: number;\n};\n\nexport type JitoRpcApi = SolanaRpcApi & {\n simulateBundle: (\n params: {\n encodedTransactions: string[];\n },\n config?: {\n preExecutionAccountsConfigs?: AccountConfig;\n postExecutionAccountsConfigs?: AccountConfig;\n skipSigVerify?: boolean;\n simulationBank?: {\n commitment?: {\n commitment: \"processed\" | \"confirmed\" | \"finalized\";\n };\n };\n transactionEncoding?: \"base64\";\n replaceRecentBlockhash?: boolean;\n },\n ) => SimulateBundleResponse;\n\n sendBundle: (\n params: string[],\n config?: {\n encoding?: \"base64\";\n },\n ) => string;\n\n getBundleStatuses: (params: string[]) => GetBundleStatusesResponse;\n};\n\nexport type SimulateBundleResponse = {\n context: {\n slot: number;\n apiVersion?: string;\n };\n value: {\n summary: \"succeeded\" | { failed: { error: unknown; tx_signature: string } };\n transactionResults: Array<{\n err: unknown;\n logs: string[] | null;\n unitsConsumed?: number;\n returnData: {\n programId: string;\n data: string;\n } | null;\n preExecutionAccounts: JitoAccountInfo[] | null;\n postExecutionAccounts: JitoAccountInfo[] | null;\n }>;\n };\n};\n\nexport type GetBundleStatusesResponse = {\n context: {\n slot: number;\n };\n value: Array<{\n bundleId: string;\n transactions: string[];\n slot: number;\n confirmation_status: \"processed\" | \"confirmed\" | \"finalized\";\n err:\n | {\n Ok: null;\n }\n | {\n Err: object;\n };\n }>;\n};\n\nexport enum JitoApiUrl {\n Amsterdam = \"https://amsterdam.mainnet.block-engine.jito.wtf\",\n Frankfurt = \"https://frankfurt.mainnet.block-engine.jito.wtf\",\n London = \"https://london.mainnet.block-engine.jito.wtf\",\n NY = \"https://ny.mainnet.block-engine.jito.wtf\",\n Singapore = \"https://singapore.mainnet.block-engine.jito.wtf\",\n SLC = \"https://slc.mainnet.block-engine.jito.wtf\",\n Tokyo = \"https://tokyo.mainnet.block-engine.jito.wtf\",\n Default = \"https://mainnet.block-engine.jito.wtf\",\n}\n\nexport async function processJitoTipForTxMessage(\n message: TransactionMessageWithFeePayer &\n TransactionMessageWithSigners &\n Exclude<TransactionMessage, { version: \"legacy\" }>,\n signer: TransactionSigner,\n config: TransactionConfig,\n) {\n const jito = config.jito;\n if (!jito) throw new Error(\"jito config is undefined\");\n\n let jitoTipLamports = BigInt(0);\n\n if (jito.type === \"exact\") {\n jitoTipLamports = jito.amountLamports;\n } else if (jito.type === \"dynamic\") {\n jitoTipLamports = await recentJitoTip(config);\n if (jito.maxCapLamports && jitoTipLamports > jito.maxCapLamports) {\n jitoTipLamports = jito.maxCapLamports;\n }\n }\n\n if (jitoTipLamports > 0) {\n return appendTransactionMessageInstruction(\n getTransferSolInstruction({\n source: signer,\n destination: getJitoTipAddress(),\n amount: jitoTipLamports,\n }),\n message,\n );\n } else {\n return message;\n }\n}\n\n// returns recent jito tip in lamports\nexport async function recentJitoTip(config: TransactionConfig) {\n const baseUrl = config.jitoBlockEngineUrl ?? DEFAULT_JITO_BLOCK_ENGINE_URL;\n const response = await fetch(`${baseUrl}/api/v1/bundles/tip_floor`);\n if (!response.ok) {\n return BigInt(0);\n }\n const data = await response.json().then(res => res[0]);\n\n const percentileToKey: Record<Percentile | \"50ema\", string> = {\n \"25\": \"landed_tips_25th_percentile\",\n \"50\": \"landed_tips_50th_percentile\",\n \"75\": \"landed_tips_75th_percentile\",\n \"95\": \"landed_tips_95th_percentile\",\n \"99\": \"landed_tips_99th_percentile\",\n \"50ema\": \"ema_landed_tips_50th_percentile\",\n };\n\n const key = percentileToKey[config.jito?.priorityFeePercentile ?? \"50\"];\n if (!key || !data[key]) {\n return BigInt(0);\n }\n return lamports(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();\n}\n\n// should we add an argument that dictates if we should use cached value in case fetch fails ?\n\n// below is taken from legacy sdk (no need to add the whole library)\n// https://jito-foundation.gitbook.io/mev/mev-payment-and-distribution/on-chain-addresses\nconst jitoTipAddresses = [\n \"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5\",\n \"HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe\",\n \"Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY\",\n \"ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49\",\n \"DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh\",\n \"ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt\",\n \"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL\",\n \"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT\",\n];\n\nfunction getJitoTipAddress(): Address {\n // just pick a random one from the list. There are multiple addresses so that no single one can cause local congestion.\n return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);\n}\n\ninterface JsonRpcResult {\n jsonrpc: string;\n id: number;\n result?: string; // bundle id\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\nexport async function sendJitoBundle(\n jitoApiUrl: JitoApiUrl,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n jitoUUID?: string,\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx)) as string[];\n\n const url = new URL(\"/api/v1/bundles\", jitoApiUrl);\n if (jitoUUID && jitoUUID.length > 0) {\n url.searchParams.set(\"uuid\", jitoUUID);\n }\n\n const request = {\n id: 1,\n jsonrpc: \"2.0\",\n method: \"sendBundle\",\n params: [\n encodedTransactions,\n {\n encoding: \"base64\",\n },\n ],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = (await response.json()) as JsonRpcResult;\n\n if (data.error) {\n throw new Error(`Jito bundle failed: ${data.error.code} ${data.error.message}`);\n }\n\n if (!data.result) {\n throw new Error(\"sendBundle did not return a bundle id\");\n }\n\n const bundleId = data.result;\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const request = {\n jsonrpc: \"2.0\",\n id: 1,\n method: \"getInflightBundleStatuses\",\n params: [[bundleId]],\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Jito HTTP error: ${response.status}`);\n }\n\n const data = await response.json();\n const result = data.result?.value?.[0];\n if (!result) {\n throw new Error(`getInflightBundleStatuses method returned undefined result`, { cause: { bundleId } });\n }\n\n switch (result.status) {\n case \"Landed\":\n return bundleId;\n case \"Pending\":\n case \"Invalid\":\n continue;\n case \"Failed\":\n throw new Error(`Bundle failed`, { cause: { bundleId } });\n default:\n throw new Error(`Bundle status is unknown`, { cause: { bundleId } });\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n\nexport async function simulateBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<SimulateBundleResponse> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n return rpc\n .simulateBundle({\n encodedTransactions,\n })\n .send();\n}\n\nexport async function sendBundle(\n rpc: Rpc<JitoRpcApi>,\n transactions: (SendableTransaction & Transaction & TransactionWithLifetime)[],\n): Promise<string> {\n const encodedTransactions = transactions.map(tx => getBase64EncodedWireTransaction(tx));\n\n const bundleId = await rpc\n .sendBundle(encodedTransactions, {\n encoding: \"base64\",\n })\n .send();\n\n if (!bundleId) throw new Error(`sendBundle method failed`);\n\n const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;\n\n while (Date.now() < expiryTime) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const statuses = await rpc.getBundleStatuses([bundleId]).send();\n\n const bundleStatus = statuses?.value?.[0];\n if (!bundleStatus) continue;\n\n if (bundleStatus.err && \"Err\" in bundleStatus.err) {\n throw new Error(`Bundle failed`, { cause: { bundleId, error: bundleStatus.err.Err } });\n } else {\n const confirmation_status = bundleStatus.confirmation_status;\n if (confirmation_status == \"confirmed\") {\n return bundleId;\n }\n }\n }\n\n throw new Error(`Bundle expired`, { cause: { bundleId } });\n}\n","import {\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n MaybeAccount,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\nimport { AddressLookupTable } from \"@solana-program/address-lookup-table\";\n\nimport { buildTransaction } from \"./buildTransaction\";\nimport { TransactionConfig } from \"./config\";\n\nconst CONFIRMATION_TIMEOUT_MS = 60_000;\nconst CONFIRMATION_POLL_INTERVAL_MS = 1_000;\nconst COMMITMENT_RANK: Record<Commitment, number> = { processed: 0, confirmed: 1, finalized: 2 };\n\n/**\n * Builds and sends a transaction with the given instructions, signers, and commitment level.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.\n * @param {Instruction[]} instructions - Array of instructions to include in the transaction.\n * @param {KeyPairSigner} payer - The fee payer for the transaction.\n * @param {TransactionConfig} config - The transaction config.\n * @param {Address[]} [lookupTableAccounts] - Optional array of address lookup table accounts to use.\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If transaction building or sending fails.\n *\n * @example\n * ```ts\n * const signature = await sendTransaction(\n * instructions,\n * keypairSigner,\n * DEFAULT_TRANSACTION_CONFIG,\n * lookupTables,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendTransaction(\n rpc: Rpc<SolanaRpcApi>,\n instructions: Instruction[],\n payer: KeyPairSigner,\n config?: TransactionConfig,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);\n return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);\n}\n\n/**\n * Sends a signed transaction message to the Solana network with a specified commitment level.\n *\n * Confirmation semantics: the transaction is broadcast immediately and\n * re-broadcast every 10 s (leader-drop insurance); confirmation is polled via\n * `getSignatureStatuses` once per second, where any status at or beyond the\n * requested commitment counts (`\"finalized\"` satisfies `\"confirmed\"`) and an\n * on-chain execution error throws as soon as it is observed. Transient RPC\n * failures during polling do not fail the send — the transaction is already\n * in flight. Throws `\"Transaction expired\"` if the commitment is not reached\n * within 60 s.\n *\n * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.\n * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.\n * @param {boolean} skipSimulation - True if skip simulation\n * @param {Commitment} [commitment=\"confirmed\"] - The commitment level for transaction confirmation.\n *\n * @returns {Promise<Signature>} A promise that resolves to the transaction signature.\n *\n * @throws {Error} If the initial broadcast fails, the transaction fails on-chain, or the transaction expires.\n *\n * @example\n * ```ts\n * const signature = await sendSignedTransaction(\n * rpc,\n * signedTransaction,\n * \"finalized\"\n * );\n * ```\n */\nexport async function sendSignedTransaction(\n rpc: Rpc<SolanaRpcApi>,\n transaction: SendableTransaction & Transaction & TransactionWithLifetime,\n skipSimulation: boolean = false,\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\n if (!skipSimulation) {\n // Simulate transaction first\n const simResult = await rpc\n .simulateTransaction(encodedTransaction, {\n encoding: \"base64\",\n })\n .send();\n\n if (simResult.value.err) {\n throw new Error(`Transaction simulation failed`, { cause: simResult.value });\n }\n }\n\n const expiryTime = Date.now() + CONFIRMATION_TIMEOUT_MS;\n\n await rpc\n .sendTransaction(encodedTransaction, {\n maxRetries: BigInt(0),\n skipPreflight: true,\n encoding: \"base64\",\n })\n .send();\n\n while (Date.now() < expiryTime) {\n const status = await pollSignatureStatus(rpc, txSignature);\n if (status) {\n if (status.err) {\n throw new Error(`Transaction failed`, { cause: status.err });\n }\n const { confirmationStatus } = status;\n const confirmationRank = confirmationStatus ? COMMITMENT_RANK[confirmationStatus] : -1;\n if (confirmationRank >= COMMITMENT_RANK[commitment]) {\n return txSignature;\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, CONFIRMATION_POLL_INTERVAL_MS));\n }\n\n throw new Error(\"Transaction expired\");\n}\n\nexport function getTxSignature(transaction: Transaction) {\n const [signature] = Object.values(transaction.signatures);\n return getBase58Decoder().decode(signature!) as Signature;\n}\n\n/**\n * Fetches the transaction's current status, or null when it is not yet\n * indexed — including on a transient RPC failure (rate limit, node\n * overload): the transaction is already in flight, and a failed status poll\n * must not fail the send.\n */\nasync function pollSignatureStatus(rpc: Rpc<SolanaRpcApi>, signature: Signature) {\n try {\n const { value } = await rpc.getSignatureStatuses([signature]).send();\n return value[0] ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":["getBase64EncodedWireTransaction","JitoApiUrl","request","response","data","getBase64EncodedWireTransaction","getBase64EncodedWireTransaction","getBase64EncodedWireTransaction"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unio-aggregator/unio-tx-sender",
3
3
  "description": "A TypeScript package for building and sending Solana transactions with support for priority fees and Jito tips.",
4
- "version": "1.0.3",
4
+ "version": "1.0.6",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -29,6 +29,7 @@
29
29
  "@solana-program/compute-budget": "^0.15.0",
30
30
  "@solana-program/system": "^0.11.0",
31
31
  "@solana/kit": "^6.9.0",
32
+ "@solana/transaction-messages": "^6.9.0",
32
33
  "@solana/rpc": "^6.9.0",
33
34
  "@solana/rpc-api": "^6.9.0",
34
35
  "bs58": "^6.0.0"