@unio-aggregator/unio-tx-sender 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,15 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  var index_exports = {};
21
21
  __export(index_exports, {
22
22
  DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER: () => DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
23
- DEFAULT_TRANSACTION_CONFIG: () => DEFAULT_TRANSACTION_CONFIG,
23
+ DEFAULT_JITO_BLOCK_ENGINE_URL: () => DEFAULT_JITO_BLOCK_ENGINE_URL,
24
+ JitoApiUrl: () => JitoApiUrl,
24
25
  buildTransaction: () => buildTransaction,
26
+ getTxSignature: () => getTxSignature,
27
+ processJitoTipForTxMessage: () => processJitoTipForTxMessage,
28
+ recentJitoTip: () => recentJitoTip,
29
+ sendBundle: () => sendBundle,
30
+ sendJitoBundle: () => sendJitoBundle,
25
31
  sendSignedTransaction: () => sendSignedTransaction,
26
- sendTransaction: () => sendTransaction
32
+ sendTransaction: () => sendTransaction,
33
+ simulateBundle: () => simulateBundle
27
34
  });
28
35
  module.exports = __toCommonJS(index_exports);
29
36
 
30
37
  // src/buildTransaction.ts
31
- var import_kit3 = require("@solana/kit");
38
+ var import_kit4 = require("@solana/kit");
32
39
 
33
40
  // src/computeBudget.ts
34
41
  var import_kit = require("@solana/kit");
@@ -36,38 +43,34 @@ var import_compute_budget = require("@solana-program/compute-budget");
36
43
 
37
44
  // src/config.ts
38
45
  var DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;
39
- var DEFAULT_TRANSACTION_CONFIG = {
40
- priorityFee: {
41
- type: "none",
42
- priorityFeePercentile: "50"
43
- },
44
- jito: {
45
- type: "none",
46
- priorityFeePercentile: "50"
47
- },
48
- computeUnitMarginMultiplier: DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
49
- jitoBlockEngineUrl: "https://bundles.jito.wtf",
50
- skipSimulation: false
51
- };
46
+ var DEFAULT_JITO_BLOCK_ENGINE_URL = "https://bundles.jito.wtf";
52
47
 
53
48
  // src/computeBudget.ts
54
49
  async function processComputeBudgetForTxMessage(rpc, message, computeUnits, config) {
55
- const priorityFee = config.priorityFee;
56
50
  const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;
57
51
  let priorityFeeMicroLamports = 0n;
58
- if (priorityFee.type === "exact") {
59
- priorityFeeMicroLamports = priorityFee.amountLamports * 1000000n / BigInt(computeUnits);
60
- } else if (priorityFee.type === "dynamic") {
61
- const estimatedPriorityFee = await calculateDynamicPriorityFees(
62
- rpc,
63
- message.instructions,
64
- priorityFee.priorityFeePercentile ?? "50"
65
- );
66
- if (!priorityFee.maxCapLamports) {
67
- priorityFeeMicroLamports = estimatedPriorityFee;
68
- } else {
69
- const maxCapMicroLamports = priorityFee.maxCapLamports * 1000000n / BigInt(computeUnits);
70
- priorityFeeMicroLamports = maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;
52
+ const units = BigInt(
53
+ Math.min(
54
+ 14e5,
55
+ Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER))
56
+ )
57
+ );
58
+ const priorityFee = config.priorityFee;
59
+ if (priorityFee) {
60
+ if (priorityFee.type === "exact") {
61
+ priorityFeeMicroLamports = priorityFee.amountLamports * 1000000n / units;
62
+ } else if (priorityFee.type === "dynamic") {
63
+ const estimatedPriorityFee = await calculateDynamicPriorityFees(
64
+ rpc,
65
+ message.instructions,
66
+ priorityFee.priorityFeePercentile ?? "50"
67
+ );
68
+ if (!priorityFee.maxCapLamports) {
69
+ priorityFeeMicroLamports = estimatedPriorityFee;
70
+ } else {
71
+ const maxCapMicroLamports = priorityFee.maxCapLamports * 1000000n / units;
72
+ priorityFeeMicroLamports = maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;
73
+ }
71
74
  }
72
75
  }
73
76
  if (priorityFeeMicroLamports > 0) {
@@ -80,7 +83,7 @@ async function processComputeBudgetForTxMessage(rpc, message, computeUnits, conf
80
83
  }
81
84
  message = (0, import_kit.prependTransactionMessageInstruction)(
82
85
  (0, import_compute_budget.getSetComputeUnitLimitInstruction)({
83
- units: Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER))
86
+ units: computeUnits
84
87
  }),
85
88
  message
86
89
  );
@@ -107,17 +110,34 @@ async function calculateDynamicPriorityFees(rpc, instructions, percentile) {
107
110
 
108
111
  // src/jito.ts
109
112
  var import_kit2 = require("@solana/kit");
113
+ var import_kit3 = require("@solana/kit");
110
114
  var import_system = require("@solana-program/system");
115
+ var JITO_BUNDLE_EXPIRY_TIME = 3e4;
116
+ var JitoApiUrl = /* @__PURE__ */ ((JitoApiUrl2) => {
117
+ JitoApiUrl2["Amsterdam"] = "https://amsterdam.mainnet.block-engine.jito.wtf";
118
+ JitoApiUrl2["Frankfurt"] = "https://frankfurt.mainnet.block-engine.jito.wtf";
119
+ JitoApiUrl2["London"] = "https://london.mainnet.block-engine.jito.wtf";
120
+ JitoApiUrl2["NY"] = "https://ny.mainnet.block-engine.jito.wtf";
121
+ JitoApiUrl2["Singapore"] = "https://singapore.mainnet.block-engine.jito.wtf";
122
+ JitoApiUrl2["SLC"] = "https://slc.mainnet.block-engine.jito.wtf";
123
+ JitoApiUrl2["Tokyo"] = "https://tokyo.mainnet.block-engine.jito.wtf";
124
+ JitoApiUrl2["Default"] = "https://mainnet.block-engine.jito.wtf";
125
+ return JitoApiUrl2;
126
+ })(JitoApiUrl || {});
111
127
  async function processJitoTipForTxMessage(message, signer, config) {
112
- let jitoTipLamports = BigInt(0);
113
128
  const jito = config.jito;
129
+ if (!jito) throw new Error("jito config is undefined");
130
+ let jitoTipLamports = BigInt(0);
114
131
  if (jito.type === "exact") {
115
132
  jitoTipLamports = jito.amountLamports;
116
133
  } else if (jito.type === "dynamic") {
117
134
  jitoTipLamports = await recentJitoTip(config);
135
+ if (jito.maxCapLamports && jitoTipLamports > jito.maxCapLamports) {
136
+ jitoTipLamports = jito.maxCapLamports;
137
+ }
118
138
  }
119
139
  if (jitoTipLamports > 0) {
120
- return (0, import_kit2.prependTransactionMessageInstruction)(
140
+ return (0, import_kit2.appendTransactionMessageInstruction)(
121
141
  (0, import_system.getTransferSolInstruction)({
122
142
  source: signer,
123
143
  destination: getJitoTipAddress(),
@@ -130,7 +150,8 @@ async function processJitoTipForTxMessage(message, signer, config) {
130
150
  }
131
151
  }
132
152
  async function recentJitoTip(config) {
133
- const response = await fetch(`${config.jitoBlockEngineUrl}/api/v1/bundles/tip_floor`);
153
+ const baseUrl = config.jitoBlockEngineUrl ?? DEFAULT_JITO_BLOCK_ENGINE_URL;
154
+ const response = await fetch(`${baseUrl}/api/v1/bundles/tip_floor`);
134
155
  if (!response.ok) {
135
156
  return BigInt(0);
136
157
  }
@@ -143,11 +164,11 @@ async function recentJitoTip(config) {
143
164
  "99": "landed_tips_99th_percentile",
144
165
  "50ema": "ema_landed_tips_50th_percentile"
145
166
  };
146
- const key = percentileToKey[config.priorityFee.priorityFeePercentile ?? "50"];
167
+ const key = percentileToKey[config.jito?.priorityFeePercentile ?? "50"];
147
168
  if (!key || !data[key]) {
148
169
  return BigInt(0);
149
170
  }
150
- return (0, import_kit2.lamports)(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
171
+ return (0, import_kit3.lamports)(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
151
172
  }
152
173
  var jitoTipAddresses = [
153
174
  "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
@@ -160,50 +181,155 @@ var jitoTipAddresses = [
160
181
  "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
161
182
  ];
162
183
  function getJitoTipAddress() {
163
- return (0, import_kit2.address)(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
184
+ return (0, import_kit3.address)(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
185
+ }
186
+ async function sendJitoBundle(jitoApiUrl, transactions, jitoUUID) {
187
+ const encodedTransactions = transactions.map((tx) => (0, import_kit2.getBase64EncodedWireTransaction)(tx));
188
+ const url = new URL("/api/v1/bundles", jitoApiUrl);
189
+ if (jitoUUID && jitoUUID.length > 0) {
190
+ url.searchParams.set("uuid", jitoUUID);
191
+ }
192
+ const request = {
193
+ id: 1,
194
+ jsonrpc: "2.0",
195
+ method: "sendBundle",
196
+ params: [
197
+ encodedTransactions,
198
+ {
199
+ encoding: "base64"
200
+ }
201
+ ]
202
+ };
203
+ const response = await fetch(url, {
204
+ method: "POST",
205
+ headers: {
206
+ "Content-Type": "application/json"
207
+ },
208
+ body: JSON.stringify(request)
209
+ });
210
+ if (!response.ok) {
211
+ throw new Error(`Jito HTTP error: ${response.status}`);
212
+ }
213
+ const data = await response.json();
214
+ if (data.error) {
215
+ throw new Error(`Jito bundle failed: ${data.error.code} ${data.error.message}`);
216
+ }
217
+ if (!data.result) {
218
+ throw new Error("sendBundle did not return a bundle id");
219
+ }
220
+ const bundleId = data.result;
221
+ const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;
222
+ while (Date.now() < expiryTime) {
223
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
224
+ const request2 = {
225
+ jsonrpc: "2.0",
226
+ id: 1,
227
+ method: "getInflightBundleStatuses",
228
+ params: [[bundleId]]
229
+ };
230
+ const response2 = await fetch(url, {
231
+ method: "POST",
232
+ headers: {
233
+ "Content-Type": "application/json"
234
+ },
235
+ body: JSON.stringify(request2)
236
+ });
237
+ if (!response2.ok) {
238
+ throw new Error(`Jito HTTP error: ${response2.status}`);
239
+ }
240
+ const data2 = await response2.json();
241
+ const result = data2.result?.value?.[0];
242
+ if (!result) {
243
+ throw new Error(`getInflightBundleStatuses method returned undefined result`, { cause: { bundleId } });
244
+ }
245
+ switch (result.status) {
246
+ case "Landed":
247
+ return bundleId;
248
+ case "Pending":
249
+ case "Invalid":
250
+ continue;
251
+ case "Failed":
252
+ throw new Error(`Bundle failed`, { cause: { bundleId } });
253
+ default:
254
+ throw new Error(`Bundle status is unknown`, { cause: { bundleId } });
255
+ }
256
+ }
257
+ throw new Error(`Bundle expired`, { cause: { bundleId } });
258
+ }
259
+ async function simulateBundle(rpc, transactions) {
260
+ const encodedTransactions = transactions.map((tx) => (0, import_kit2.getBase64EncodedWireTransaction)(tx));
261
+ return rpc.simulateBundle({
262
+ encodedTransactions
263
+ }).send();
264
+ }
265
+ async function sendBundle(rpc, transactions) {
266
+ const encodedTransactions = transactions.map((tx) => (0, import_kit2.getBase64EncodedWireTransaction)(tx));
267
+ const bundleId = await rpc.sendBundle(encodedTransactions, {
268
+ encoding: "base64"
269
+ }).send();
270
+ if (!bundleId) throw new Error(`sendBundle method failed`);
271
+ const expiryTime = Date.now() + JITO_BUNDLE_EXPIRY_TIME;
272
+ while (Date.now() < expiryTime) {
273
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
274
+ const statuses = await rpc.getBundleStatuses([bundleId]).send();
275
+ const bundleStatus = statuses?.value?.[0];
276
+ if (!bundleStatus) continue;
277
+ if (bundleStatus.err && "Err" in bundleStatus.err) {
278
+ throw new Error(`Bundle failed`, { cause: { bundleId, error: bundleStatus.err.Err } });
279
+ } else {
280
+ const confirmation_status = bundleStatus.confirmation_status;
281
+ if (confirmation_status == "confirmed") {
282
+ return bundleId;
283
+ }
284
+ }
285
+ }
286
+ throw new Error(`Bundle expired`, { cause: { bundleId } });
164
287
  }
165
288
 
166
289
  // src/buildTransaction.ts
167
- async function buildTransaction(rpc, config, instructions, feePayer, lookupTableAccounts) {
290
+ async function buildTransaction(rpc, instructions, feePayer, config, lookupTableAccounts) {
168
291
  return buildTransactionMessage(
169
292
  rpc,
170
- config,
171
293
  instructions,
172
- !("address" in feePayer) ? (0, import_kit3.createNoopSigner)(feePayer) : feePayer,
294
+ !("address" in feePayer) ? (0, import_kit4.createNoopSigner)(feePayer) : feePayer,
295
+ config,
173
296
  lookupTableAccounts
174
297
  );
175
298
  }
176
- async function buildTransactionMessage(rpc, config, instructions, signer, lookupTableAccounts) {
177
- let message = await prepareTransactionMessage(instructions, rpc, signer);
299
+ async function buildTransactionMessage(rpc, instructions, signer, config, lookupTableAccounts) {
300
+ let blockhash = config.blockhash;
301
+ if (!blockhash) {
302
+ blockhash = (await rpc.getLatestBlockhash({
303
+ commitment: "confirmed"
304
+ }).send()).value;
305
+ }
306
+ let message = await prepareTransactionMessage(instructions, signer, blockhash);
178
307
  if (lookupTableAccounts?.length) {
179
308
  const tables = lookupTableAccounts.reduce(
180
309
  (prev, account) => {
181
310
  if (account.exists) {
182
- (0, import_kit3.assertAccountDecoded)(account);
311
+ (0, import_kit4.assertAccountDecoded)(account);
183
312
  prev[account.address] = account.data.addresses;
184
313
  }
185
314
  return prev;
186
315
  },
187
316
  {}
188
317
  );
189
- message = (0, import_kit3.compressTransactionMessageUsingAddressLookupTables)(message, tables);
318
+ message = (0, import_kit4.compressTransactionMessageUsingAddressLookupTables)(message, tables);
190
319
  }
191
320
  const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);
192
- return (0, import_kit3.signTransactionMessageWithSigners)(messageWithExtraInstructions);
321
+ return (0, import_kit4.signTransactionMessageWithSigners)(messageWithExtraInstructions);
193
322
  }
194
- async function prepareTransactionMessage(instructions, rpc, signer) {
195
- const { value: blockhash } = await rpc.getLatestBlockhash({
196
- commitment: "confirmed"
197
- }).send();
198
- return (0, import_kit3.pipe)(
199
- (0, import_kit3.createTransactionMessage)({ version: 0 }),
200
- (tx) => (0, import_kit3.setTransactionMessageLifetimeUsingBlockhash)(blockhash, tx),
201
- (tx) => (0, import_kit3.setTransactionMessageFeePayerSigner)(signer, tx),
202
- (tx) => (0, import_kit3.appendTransactionMessageInstructions)(instructions, tx)
323
+ async function prepareTransactionMessage(instructions, signer, blockhash) {
324
+ return (0, import_kit4.pipe)(
325
+ (0, import_kit4.createTransactionMessage)({ version: 0 }),
326
+ (tx) => (0, import_kit4.setTransactionMessageLifetimeUsingBlockhash)(blockhash, tx),
327
+ (tx) => (0, import_kit4.setTransactionMessageFeePayerSigner)(signer, tx),
328
+ (tx) => (0, import_kit4.appendTransactionMessageInstructions)(instructions, tx)
203
329
  );
204
330
  }
205
331
  async function addPriorityInstructions(rpc, message, signer, config) {
206
- if (config.jito.type !== "none") {
332
+ if (config.jito && config.jito.type !== "none") {
207
333
  message = await processJitoTipForTxMessage(message, signer, config);
208
334
  }
209
335
  let computeUnits = 14e5;
@@ -217,25 +343,19 @@ async function addPriorityInstructions(rpc, message, signer, config) {
217
343
  return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);
218
344
  }
219
345
  async function getComputeUnitsForTxMessage(rpc, txMessage) {
220
- return await (0, import_kit3.estimateComputeUnitLimitFactory)({ rpc })(txMessage);
346
+ return await (0, import_kit4.estimateComputeUnitLimitFactory)({ rpc })(txMessage);
221
347
  }
222
348
 
223
349
  // src/sendTransaction.ts
224
- var import_kit4 = require("@solana/kit");
350
+ var import_kit5 = require("@solana/kit");
225
351
  async function sendTransaction(rpc, instructions, payer, config, lookupTableAccounts, commitment = "confirmed") {
226
- const tx = await buildTransaction(
227
- rpc,
228
- config ?? DEFAULT_TRANSACTION_CONFIG,
229
- instructions,
230
- payer,
231
- lookupTableAccounts
232
- );
233
- return sendSignedTransaction(rpc, tx, config ?? DEFAULT_TRANSACTION_CONFIG, commitment);
352
+ const tx = await buildTransaction(rpc, instructions, payer, config ?? {}, lookupTableAccounts);
353
+ return sendSignedTransaction(rpc, tx, config?.skipSimulation ?? false, commitment);
234
354
  }
235
- async function sendSignedTransaction(rpc, transaction, config, commitment = "confirmed") {
355
+ async function sendSignedTransaction(rpc, transaction, skipSimulation = false, commitment = "confirmed") {
236
356
  const txSignature = getTxSignature(transaction);
237
- const encodedTransaction = (0, import_kit4.getBase64EncodedWireTransaction)(transaction);
238
- if (!config.skipSimulation) {
357
+ const encodedTransaction = (0, import_kit5.getBase64EncodedWireTransaction)(transaction);
358
+ if (!skipSimulation) {
239
359
  const simResult = await rpc.simulateTransaction(encodedTransaction, {
240
360
  encoding: "base64"
241
361
  }).send();
@@ -263,14 +383,21 @@ async function sendSignedTransaction(rpc, transaction, config, commitment = "con
263
383
  }
264
384
  function getTxSignature(transaction) {
265
385
  const [signature] = Object.values(transaction.signatures);
266
- return (0, import_kit4.getBase58Decoder)().decode(signature);
386
+ return (0, import_kit5.getBase58Decoder)().decode(signature);
267
387
  }
268
388
  // Annotate the CommonJS export names for ESM import in node:
269
389
  0 && (module.exports = {
270
390
  DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
271
- DEFAULT_TRANSACTION_CONFIG,
391
+ DEFAULT_JITO_BLOCK_ENGINE_URL,
392
+ JitoApiUrl,
272
393
  buildTransaction,
394
+ getTxSignature,
395
+ processJitoTipForTxMessage,
396
+ recentJitoTip,
397
+ sendBundle,
398
+ sendJitoBundle,
273
399
  sendSignedTransaction,
274
- sendTransaction
400
+ sendTransaction,
401
+ simulateBundle
275
402
  });
276
403
  //# sourceMappingURL=index.cjs.map
@@ -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 \"./sendTransaction\";\n","import {\n Address,\n appendTransactionMessageInstructions,\n assertAccountDecoded,\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 config: TransactionConfig,\n instructions: Instruction[],\n feePayer: TransactionSigner | Address,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n config,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n lookupTableAccounts,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n config: TransactionConfig,\n instructions: Instruction[],\n signer: TransactionSigner,\n lookupTableAccounts?: MaybeAccount<AddressLookupTable>[],\n) {\n let message = await prepareTransactionMessage(instructions, rpc, signer);\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 rpc: Rpc<SolanaRpcApi>,\n signer: TransactionSigner,\n) {\n const { value: blockhash } = await rpc\n .getLatestBlockhash({\n commitment: \"confirmed\",\n })\n .send();\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.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 priorityFee = config.priorityFee;\n const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;\n let priorityFeeMicroLamports = 0n;\n\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / BigInt(computeUnits);\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(computeUnits);\n\n priorityFeeMicroLamports =\n maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;\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: Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\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","/**\n * Default compute unit margin multiplier used to ensure sufficient compute budget.\n */\nexport const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;\n\n/**\n * Default prioritization settings, including priority fees and Jito tips.\n */\nexport const DEFAULT_TRANSACTION_CONFIG: TransactionConfig = {\n priorityFee: {\n type: \"none\",\n priorityFeePercentile: \"50\",\n },\n jito: {\n type: \"none\",\n priorityFeePercentile: \"50\",\n },\n computeUnitMarginMultiplier: DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,\n jitoBlockEngineUrl: \"https://bundles.jito.wtf\",\n skipSimulation: false,\n};\n\n/*\nasync function getChainIdFromGenesisHash(rpc: Rpc<SolanaRpcApi>): Promise<ChainId> {\n // not all rpc endpoints support getGenesisHash\n try {\n const genesisHash = await rpc.getGenesisHash().send();\n const genesisHashToChainId: Record<string, ChainId> = {\n \"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d\": \"solana\",\n EAQLJCV2mh23BsK2P9oYpV5CHVLDNHTxYss3URrNmg3s: \"eclipse\",\n EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG: \"solana-devnet\",\n CX4huckiV9QNAkKNVKi5Tj8nxzBive5kQimd94viMKsU: \"eclipse-testnet\",\n };\n return genesisHashToChainId[genesisHash] || \"unknown\";\n } catch (error) {\n console.warn(\"Error getting chain ID from genesis hash\", error);\n return \"unknown\";\n }\n}\n */\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\nexport type TransactionConfig = {\n jito: JitoFeeSetting;\n priorityFee: PriorityFeeSetting;\n computeUnitMarginMultiplier: number;\n jitoBlockEngineUrl: string;\n skipSimulation: boolean;\n};\n\n/**\n * Defines a percentile value for priority fee selection.\n */\nexport type Percentile = \"25\" | \"50\" | \"75\" | \"95\" | \"99\";\n\n/**\n * Represents a supported blockchain network chain ID.\n */\nexport type ChainId = \"solana\" | \"eclipse\" | \"solana-devnet\" | \"eclipse-testnet\" | \"unknown\";\n","import { Address, TransactionMessage, TransactionMessageWithFeePayer, TransactionSigner } from \"@solana/kit\";\nimport { address, lamports, prependTransactionMessageInstruction } from \"@solana/kit\";\nimport { getTransferSolInstruction } from \"@solana-program/system\";\n\nimport { type Percentile, TransactionConfig } from \"./config\";\n\nexport async function processJitoTipForTxMessage(\n message: TransactionMessage & TransactionMessageWithFeePayer,\n signer: TransactionSigner,\n config: TransactionConfig,\n) {\n let jitoTipLamports = BigInt(0);\n const jito = config.jito;\n\n if (jito.type === \"exact\") {\n jitoTipLamports = jito.amountLamports;\n } else if (jito.type === \"dynamic\") {\n jitoTipLamports = await recentJitoTip(config);\n }\n if (jitoTipLamports > 0) {\n return prependTransactionMessageInstruction(\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 response = await fetch(`${config.jitoBlockEngineUrl}/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.priorityFee.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\n // can cause local congestion.\n return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);\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 { DEFAULT_TRANSACTION_CONFIG, 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(\n rpc,\n config ?? DEFAULT_TRANSACTION_CONFIG,\n instructions,\n payer,\n lookupTableAccounts,\n );\n return sendSignedTransaction(rpc, tx, config ?? DEFAULT_TRANSACTION_CONFIG, 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 {TransactionConfig} config - The transaction config.\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 config: TransactionConfig,\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\n if (!config.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\nfunction 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","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 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 = BigInt(\n Math.min(\n 1_400_000,\n Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER)),\n ),\n );\n\n const priorityFee = config.priorityFee;\n if (priorityFee) {\n if (priorityFee.type === \"exact\") {\n priorityFeeMicroLamports = (priorityFee.amountLamports * 1_000_000n) / 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) / 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: computeUnits,\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"]}