@unio-aggregator/unio-tx-sender 1.0.0

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/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Unio Aggregator Transaction Sender Library
2
+
3
+ A TypeScript package for building and sending Solana transactions with support for priority fees and Jito tips.
4
+
5
+ ## Key Features
6
+
7
+ - Main entry point `sendTransaction()` handles transaction building, signing, and confirmation
8
+ - Built-in support for priority fees and Jito MEV tips
9
+ - Configurable compute unit margin multiplier to ensure sufficient compute budget
10
+
11
+ ## Example
12
+
13
+ ```ts
14
+ import {createKeyPairFromBytes, createSolanaRpc, createSignerFromKeyPair} from "@solana/kit";
15
+ import {sendTransaction} from "@unio-aggregator/unio-tx-sender";
16
+
17
+ const kp = await createKeyPairFromBytes(new Uint8Array([1, 2, 3, 4, ...]));
18
+ const signer = await createSignerFromKeyPair(kp);
19
+
20
+ // Initialize RPC connection
21
+ export const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
22
+
23
+ const txHash = await sendTransaction(
24
+ rpc,
25
+ [instruction1, instruction2],
26
+ keypairSigner
27
+ );
28
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,273 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.ts
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER: () => DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
23
+ DEFAULT_TRANSACTION_CONFIG: () => DEFAULT_TRANSACTION_CONFIG,
24
+ buildTransaction: () => buildTransaction,
25
+ sendSignedTransaction: () => sendSignedTransaction,
26
+ sendTransaction: () => sendTransaction
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/buildTransaction.ts
31
+ var import_kit3 = require("@solana/kit");
32
+ var import_address_lookup_table = require("@solana-program/address-lookup-table");
33
+
34
+ // src/computeBudget.ts
35
+ var import_kit = require("@solana/kit");
36
+ var import_compute_budget = require("@solana-program/compute-budget");
37
+
38
+ // src/config.ts
39
+ var DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;
40
+ var DEFAULT_TRANSACTION_CONFIG = {
41
+ priorityFee: {
42
+ type: "none",
43
+ priorityFeePercentile: "50"
44
+ },
45
+ jito: {
46
+ type: "none",
47
+ priorityFeePercentile: "50"
48
+ },
49
+ computeUnitMarginMultiplier: DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
50
+ jitoBlockEngineUrl: "https://bundles.jito.wtf"
51
+ };
52
+
53
+ // src/computeBudget.ts
54
+ async function processComputeBudgetForTxMessage(rpc, message, computeUnits, config) {
55
+ const priorityFee = config.priorityFee;
56
+ const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;
57
+ 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;
71
+ }
72
+ }
73
+ if (priorityFeeMicroLamports > 0) {
74
+ message = (0, import_kit.prependTransactionMessageInstruction)(
75
+ (0, import_compute_budget.getSetComputeUnitPriceInstruction)({
76
+ microLamports: priorityFeeMicroLamports
77
+ }),
78
+ message
79
+ );
80
+ }
81
+ message = (0, import_kit.prependTransactionMessageInstruction)(
82
+ (0, import_compute_budget.getSetComputeUnitLimitInstruction)({
83
+ units: Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER))
84
+ }),
85
+ message
86
+ );
87
+ return message;
88
+ }
89
+ function getWritableAccounts(ixs) {
90
+ const writable = /* @__PURE__ */ new Set();
91
+ ixs.forEach((ix) => {
92
+ if (ix.accounts) {
93
+ ix.accounts.forEach((acc) => {
94
+ if ((0, import_kit.isWritableRole)(acc.role)) writable.add(acc.address);
95
+ });
96
+ }
97
+ });
98
+ return Array.from(writable);
99
+ }
100
+ async function calculateDynamicPriorityFees(rpc, instructions, percentile) {
101
+ const writableAccounts = getWritableAccounts(instructions);
102
+ const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();
103
+ const nonZero = recent.filter((pf) => pf.prioritizationFee > 0).map((pf) => pf.prioritizationFee);
104
+ const sorted = nonZero.sort((a, b) => Number(a - b));
105
+ return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);
106
+ }
107
+
108
+ // src/jito.ts
109
+ var import_kit2 = require("@solana/kit");
110
+ var import_system = require("@solana-program/system");
111
+ async function processJitoTipForTxMessage(message, signer, config) {
112
+ let jitoTipLamports = BigInt(0);
113
+ const jito = config.jito;
114
+ if (jito.type === "exact") {
115
+ jitoTipLamports = jito.amountLamports;
116
+ } else if (jito.type === "dynamic") {
117
+ jitoTipLamports = await recentJitoTip(config);
118
+ }
119
+ if (jitoTipLamports > 0) {
120
+ return (0, import_kit2.prependTransactionMessageInstruction)(
121
+ (0, import_system.getTransferSolInstruction)({
122
+ source: signer,
123
+ destination: getJitoTipAddress(),
124
+ amount: jitoTipLamports
125
+ }),
126
+ message
127
+ );
128
+ } else {
129
+ return message;
130
+ }
131
+ }
132
+ async function recentJitoTip(config) {
133
+ const response = await fetch(`${config.jitoBlockEngineUrl}/api/v1/bundles/tip_floor`);
134
+ if (!response.ok) {
135
+ return BigInt(0);
136
+ }
137
+ const data = await response.json().then((res) => res[0]);
138
+ const percentileToKey = {
139
+ "25": "landed_tips_25th_percentile",
140
+ "50": "landed_tips_50th_percentile",
141
+ "75": "landed_tips_75th_percentile",
142
+ "95": "landed_tips_95th_percentile",
143
+ "99": "landed_tips_99th_percentile",
144
+ "50ema": "ema_landed_tips_50th_percentile"
145
+ };
146
+ const key = percentileToKey[config.priorityFee.priorityFeePercentile ?? "50"];
147
+ if (!key || !data[key]) {
148
+ return BigInt(0);
149
+ }
150
+ return (0, import_kit2.lamports)(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
151
+ }
152
+ var jitoTipAddresses = [
153
+ "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
154
+ "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe",
155
+ "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY",
156
+ "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49",
157
+ "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh",
158
+ "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt",
159
+ "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL",
160
+ "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
161
+ ];
162
+ function getJitoTipAddress() {
163
+ return (0, import_kit2.address)(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
164
+ }
165
+
166
+ // src/buildTransaction.ts
167
+ async function buildTransaction(rpc, config, instructions, feePayer, lookupTableAddresses) {
168
+ return buildTransactionMessage(
169
+ rpc,
170
+ config,
171
+ instructions,
172
+ !("address" in feePayer) ? (0, import_kit3.createNoopSigner)(feePayer) : feePayer,
173
+ lookupTableAddresses
174
+ );
175
+ }
176
+ async function buildTransactionMessage(rpc, config, instructions, signer, lookupTableAddresses) {
177
+ let message = await prepareTransactionMessage(instructions, rpc, signer);
178
+ if (lookupTableAddresses?.length) {
179
+ const lookupTableAccounts = await (0, import_address_lookup_table.fetchAllMaybeAddressLookupTable)(rpc, lookupTableAddresses);
180
+ const tables = lookupTableAccounts.reduce(
181
+ (prev, account) => {
182
+ if (account.exists) {
183
+ (0, import_kit3.assertAccountDecoded)(account);
184
+ prev[account.address] = account.data.addresses;
185
+ }
186
+ return prev;
187
+ },
188
+ {}
189
+ );
190
+ message = (0, import_kit3.compressTransactionMessageUsingAddressLookupTables)(message, tables);
191
+ }
192
+ const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);
193
+ return (0, import_kit3.signTransactionMessageWithSigners)(messageWithExtraInstructions);
194
+ }
195
+ async function prepareTransactionMessage(instructions, rpc, signer) {
196
+ const { value: blockhash } = await rpc.getLatestBlockhash({
197
+ commitment: "confirmed"
198
+ }).send();
199
+ return (0, import_kit3.pipe)(
200
+ (0, import_kit3.createTransactionMessage)({ version: 0 }),
201
+ (tx) => (0, import_kit3.setTransactionMessageLifetimeUsingBlockhash)(blockhash, tx),
202
+ (tx) => (0, import_kit3.setTransactionMessageFeePayerSigner)(signer, tx),
203
+ (tx) => (0, import_kit3.appendTransactionMessageInstructions)(instructions, tx)
204
+ );
205
+ }
206
+ async function addPriorityInstructions(rpc, message, signer, config) {
207
+ if (config.jito.type !== "none") {
208
+ message = await processJitoTipForTxMessage(message, signer, config);
209
+ }
210
+ let computeUnits = 14e5;
211
+ try {
212
+ computeUnits = await getComputeUnitsForTxMessage(rpc, message);
213
+ } catch {
214
+ console.warn("Transaction simulation failed, using 1,400,000 compute units");
215
+ }
216
+ return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);
217
+ }
218
+ async function getComputeUnitsForTxMessage(rpc, txMessage) {
219
+ return await (0, import_kit3.estimateComputeUnitLimitFactory)({ rpc })(txMessage);
220
+ }
221
+
222
+ // src/sendTransaction.ts
223
+ var import_kit4 = require("@solana/kit");
224
+ async function sendTransaction(rpc, instructions, payer, config, lookupTableAddresses, commitment = "confirmed") {
225
+ const tx = await buildTransaction(
226
+ rpc,
227
+ config ?? DEFAULT_TRANSACTION_CONFIG,
228
+ instructions,
229
+ payer,
230
+ lookupTableAddresses
231
+ );
232
+ return sendSignedTransaction(rpc, tx, commitment);
233
+ }
234
+ async function sendSignedTransaction(rpc, transaction, commitment = "confirmed") {
235
+ const txSignature = getTxSignature(transaction);
236
+ const encodedTransaction = (0, import_kit4.getBase64EncodedWireTransaction)(transaction);
237
+ const simResult = await rpc.simulateTransaction(encodedTransaction, {
238
+ encoding: "base64"
239
+ }).send();
240
+ if (simResult.value.err) {
241
+ throw new Error(`Transaction simulation failed`, { cause: simResult.value });
242
+ }
243
+ const expiryTime = Date.now() + 6e4;
244
+ while (Date.now() < expiryTime) {
245
+ await rpc.sendTransaction(encodedTransaction, {
246
+ maxRetries: BigInt(0),
247
+ skipPreflight: true,
248
+ encoding: "base64"
249
+ }).send();
250
+ const { value } = await rpc.getSignatureStatuses([txSignature]).send();
251
+ const status = value[0];
252
+ if (status?.confirmationStatus === commitment) {
253
+ if (status.err) {
254
+ throw new Error(`Transaction failed`, { cause: status.err });
255
+ }
256
+ return txSignature;
257
+ }
258
+ }
259
+ throw new Error("Transaction expired");
260
+ }
261
+ function getTxSignature(transaction) {
262
+ const [signature] = Object.values(transaction.signatures);
263
+ return (0, import_kit4.getBase58Decoder)().decode(signature);
264
+ }
265
+ // Annotate the CommonJS export names for ESM import in node:
266
+ 0 && (module.exports = {
267
+ DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
268
+ DEFAULT_TRANSACTION_CONFIG,
269
+ buildTransaction,
270
+ sendSignedTransaction,
271
+ sendTransaction
272
+ });
273
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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 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 { fetchAllMaybeAddressLookupTable } 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)[]} [lookupTableAddresses] - Optional array of address lookup table addresses 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 lookupTableAddresses?: Address[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n config,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n lookupTableAddresses,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n config: TransactionConfig,\n instructions: Instruction[],\n signer: TransactionSigner,\n lookupTableAddresses?: Address[],\n) {\n let message = await prepareTransactionMessage(instructions, rpc, signer);\n\n if (lookupTableAddresses?.length) {\n const lookupTableAccounts = await fetchAllMaybeAddressLookupTable(rpc, lookupTableAddresses);\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 try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, message);\n } catch {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units\");\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};\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};\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 Address,\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\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[]} [lookupTableAddresses] - Optional array of address lookup table addresses 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 lookupTableAddresses?: Address[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(\n rpc,\n config ?? DEFAULT_TRANSACTION_CONFIG,\n instructions,\n payer,\n lookupTableAddresses,\n );\n return sendSignedTransaction(rpc, tx, 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 {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 commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\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 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"]}
@@ -0,0 +1,114 @@
1
+ import { Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, SendableTransaction, Transaction, TransactionWithLifetime, Commitment, Signature, KeyPairSigner } from '@solana/kit';
2
+
3
+ /**
4
+ * Default compute unit margin multiplier used to ensure sufficient compute budget.
5
+ */
6
+ declare const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;
7
+ /**
8
+ * Default prioritization settings, including priority fees and Jito tips.
9
+ */
10
+ declare const DEFAULT_TRANSACTION_CONFIG: TransactionConfig;
11
+ type FeeSetting = {
12
+ type: "dynamic";
13
+ maxCapLamports?: bigint;
14
+ } | {
15
+ type: "exact";
16
+ amountLamports: bigint;
17
+ } | {
18
+ type: "none";
19
+ };
20
+ /**
21
+ * Configuration for transaction fees, including Jito and priority fee settings.
22
+ */
23
+ type JitoFeeSetting = FeeSetting & {
24
+ priorityFeePercentile?: Percentile | "50ema";
25
+ };
26
+ type PriorityFeeSetting = FeeSetting & {
27
+ priorityFeePercentile?: Percentile;
28
+ };
29
+ type TransactionConfig = {
30
+ jito: JitoFeeSetting;
31
+ priorityFee: PriorityFeeSetting;
32
+ computeUnitMarginMultiplier: number;
33
+ jitoBlockEngineUrl: string;
34
+ };
35
+ /**
36
+ * Defines a percentile value for priority fee selection.
37
+ */
38
+ type Percentile = "25" | "50" | "75" | "95" | "99";
39
+ /**
40
+ * Represents a supported blockchain network chain ID.
41
+ */
42
+ type ChainId = "solana" | "eclipse" | "solana-devnet" | "eclipse-testnet" | "unknown";
43
+
44
+ /**
45
+ * Builds and signs a transaction from the given instructions and configuration.
46
+ *
47
+ * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.
48
+ * @param {TransactionConfig} config - The transaction config.
49
+ * @param {Instruction[]} instructions - Array of instructions to include in the transaction
50
+ * @param {TransactionSigner} feePayer - The signer that will pay for the transaction
51
+ * @param {(Address | string)[]} [lookupTableAddresses] - Optional array of address lookup table addresses to compress the transaction
52
+ *
53
+ * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction
54
+ *
55
+ * @example
56
+ * const instructions = [createATAix, createTransferSolInstruction];
57
+ * const feePayer = wallet.publicKey;
58
+ * const message = await buildTransaction(
59
+ * rpc,
60
+ * instructions,
61
+ * feePayer,
62
+ * );
63
+ */
64
+ declare function buildTransaction(rpc: Rpc<SolanaRpcApi>, config: TransactionConfig, instructions: Instruction[], feePayer: TransactionSigner | Address, lookupTableAddresses?: Address[]): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>;
65
+
66
+ /**
67
+ * Builds and sends a transaction with the given instructions, signers, and commitment level.
68
+ *
69
+ * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.
70
+ * @param {Instruction[]} instructions - Array of instructions to include in the transaction.
71
+ * @param {KeyPairSigner} payer - The fee payer for the transaction.
72
+ * @param {TransactionConfig} config - The transaction config.
73
+ * @param {Address[]} [lookupTableAddresses] - Optional array of address lookup table addresses to use.
74
+ * @param {Commitment} [commitment="confirmed"] - The commitment level for transaction confirmation.
75
+ *
76
+ * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
77
+ *
78
+ * @throws {Error} If transaction building or sending fails.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const signature = await sendTransaction(
83
+ * instructions,
84
+ * keypairSigner,
85
+ * DEFAULT_TRANSACTION_CONFIG,
86
+ * lookupTables,
87
+ * "finalized"
88
+ * );
89
+ * ```
90
+ */
91
+ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instruction[], payer: KeyPairSigner, config?: TransactionConfig, lookupTableAddresses?: Address[], commitment?: Commitment): Promise<Signature>;
92
+ /**
93
+ * Sends a signed transaction message to the Solana network with a specified commitment level.
94
+ *
95
+ * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.
96
+ * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.
97
+ * @param {Commitment} [commitment="confirmed"] - The commitment level for transaction confirmation.
98
+ *
99
+ * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
100
+ *
101
+ * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const signature = await sendSignedTransaction(
106
+ * rpc,
107
+ * signedTransaction,
108
+ * "finalized"
109
+ * );
110
+ * ```
111
+ */
112
+ declare function sendSignedTransaction(rpc: Rpc<SolanaRpcApi>, transaction: SendableTransaction & Transaction & TransactionWithLifetime, commitment?: Commitment): Promise<Signature>;
113
+
114
+ export { type ChainId, DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER, DEFAULT_TRANSACTION_CONFIG, type JitoFeeSetting, type Percentile, type PriorityFeeSetting, type TransactionConfig, buildTransaction, sendSignedTransaction, sendTransaction };
@@ -0,0 +1,114 @@
1
+ import { Rpc, SolanaRpcApi, Instruction, TransactionSigner, Address, SendableTransaction, Transaction, TransactionWithLifetime, Commitment, Signature, KeyPairSigner } from '@solana/kit';
2
+
3
+ /**
4
+ * Default compute unit margin multiplier used to ensure sufficient compute budget.
5
+ */
6
+ declare const DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;
7
+ /**
8
+ * Default prioritization settings, including priority fees and Jito tips.
9
+ */
10
+ declare const DEFAULT_TRANSACTION_CONFIG: TransactionConfig;
11
+ type FeeSetting = {
12
+ type: "dynamic";
13
+ maxCapLamports?: bigint;
14
+ } | {
15
+ type: "exact";
16
+ amountLamports: bigint;
17
+ } | {
18
+ type: "none";
19
+ };
20
+ /**
21
+ * Configuration for transaction fees, including Jito and priority fee settings.
22
+ */
23
+ type JitoFeeSetting = FeeSetting & {
24
+ priorityFeePercentile?: Percentile | "50ema";
25
+ };
26
+ type PriorityFeeSetting = FeeSetting & {
27
+ priorityFeePercentile?: Percentile;
28
+ };
29
+ type TransactionConfig = {
30
+ jito: JitoFeeSetting;
31
+ priorityFee: PriorityFeeSetting;
32
+ computeUnitMarginMultiplier: number;
33
+ jitoBlockEngineUrl: string;
34
+ };
35
+ /**
36
+ * Defines a percentile value for priority fee selection.
37
+ */
38
+ type Percentile = "25" | "50" | "75" | "95" | "99";
39
+ /**
40
+ * Represents a supported blockchain network chain ID.
41
+ */
42
+ type ChainId = "solana" | "eclipse" | "solana-devnet" | "eclipse-testnet" | "unknown";
43
+
44
+ /**
45
+ * Builds and signs a transaction from the given instructions and configuration.
46
+ *
47
+ * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.
48
+ * @param {TransactionConfig} config - The transaction config.
49
+ * @param {Instruction[]} instructions - Array of instructions to include in the transaction
50
+ * @param {TransactionSigner} feePayer - The signer that will pay for the transaction
51
+ * @param {(Address | string)[]} [lookupTableAddresses] - Optional array of address lookup table addresses to compress the transaction
52
+ *
53
+ * @returns {Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>} A signed and encoded transaction
54
+ *
55
+ * @example
56
+ * const instructions = [createATAix, createTransferSolInstruction];
57
+ * const feePayer = wallet.publicKey;
58
+ * const message = await buildTransaction(
59
+ * rpc,
60
+ * instructions,
61
+ * feePayer,
62
+ * );
63
+ */
64
+ declare function buildTransaction(rpc: Rpc<SolanaRpcApi>, config: TransactionConfig, instructions: Instruction[], feePayer: TransactionSigner | Address, lookupTableAddresses?: Address[]): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>>;
65
+
66
+ /**
67
+ * Builds and sends a transaction with the given instructions, signers, and commitment level.
68
+ *
69
+ * @param {Rpc<SolanaRpcApi>} rpc - Solana Rpc client.
70
+ * @param {Instruction[]} instructions - Array of instructions to include in the transaction.
71
+ * @param {KeyPairSigner} payer - The fee payer for the transaction.
72
+ * @param {TransactionConfig} config - The transaction config.
73
+ * @param {Address[]} [lookupTableAddresses] - Optional array of address lookup table addresses to use.
74
+ * @param {Commitment} [commitment="confirmed"] - The commitment level for transaction confirmation.
75
+ *
76
+ * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
77
+ *
78
+ * @throws {Error} If transaction building or sending fails.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const signature = await sendTransaction(
83
+ * instructions,
84
+ * keypairSigner,
85
+ * DEFAULT_TRANSACTION_CONFIG,
86
+ * lookupTables,
87
+ * "finalized"
88
+ * );
89
+ * ```
90
+ */
91
+ declare function sendTransaction(rpc: Rpc<SolanaRpcApi>, instructions: Instruction[], payer: KeyPairSigner, config?: TransactionConfig, lookupTableAddresses?: Address[], commitment?: Commitment): Promise<Signature>;
92
+ /**
93
+ * Sends a signed transaction message to the Solana network with a specified commitment level.
94
+ *
95
+ * @param {Rpc<SolanaRpcApi>} rpc - Rpc client.
96
+ * @param {SendableTransaction & Transaction & TransactionWithLifetime} transaction - The fully signed transaction to send.
97
+ * @param {Commitment} [commitment="confirmed"] - The commitment level for transaction confirmation.
98
+ *
99
+ * @returns {Promise<Signature>} A promise that resolves to the transaction signature.
100
+ *
101
+ * @throws {Error} If transaction sending fails, the RPC connection fails, or the transaction expires.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const signature = await sendSignedTransaction(
106
+ * rpc,
107
+ * signedTransaction,
108
+ * "finalized"
109
+ * );
110
+ * ```
111
+ */
112
+ declare function sendSignedTransaction(rpc: Rpc<SolanaRpcApi>, transaction: SendableTransaction & Transaction & TransactionWithLifetime, commitment?: Commitment): Promise<Signature>;
113
+
114
+ export { type ChainId, DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER, DEFAULT_TRANSACTION_CONFIG, type JitoFeeSetting, type Percentile, type PriorityFeeSetting, type TransactionConfig, buildTransaction, sendSignedTransaction, sendTransaction };
package/dist/index.js ADDED
@@ -0,0 +1,257 @@
1
+ // src/buildTransaction.ts
2
+ import {
3
+ appendTransactionMessageInstructions,
4
+ assertAccountDecoded,
5
+ compressTransactionMessageUsingAddressLookupTables,
6
+ createNoopSigner,
7
+ createTransactionMessage,
8
+ estimateComputeUnitLimitFactory,
9
+ pipe,
10
+ setTransactionMessageFeePayerSigner,
11
+ setTransactionMessageLifetimeUsingBlockhash,
12
+ signTransactionMessageWithSigners
13
+ } from "@solana/kit";
14
+ import { fetchAllMaybeAddressLookupTable } from "@solana-program/address-lookup-table";
15
+
16
+ // src/computeBudget.ts
17
+ import { isWritableRole, prependTransactionMessageInstruction } from "@solana/kit";
18
+ import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from "@solana-program/compute-budget";
19
+
20
+ // src/config.ts
21
+ var DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER = 1.15;
22
+ var DEFAULT_TRANSACTION_CONFIG = {
23
+ priorityFee: {
24
+ type: "none",
25
+ priorityFeePercentile: "50"
26
+ },
27
+ jito: {
28
+ type: "none",
29
+ priorityFeePercentile: "50"
30
+ },
31
+ computeUnitMarginMultiplier: DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
32
+ jitoBlockEngineUrl: "https://bundles.jito.wtf"
33
+ };
34
+
35
+ // src/computeBudget.ts
36
+ async function processComputeBudgetForTxMessage(rpc, message, computeUnits, config) {
37
+ const priorityFee = config.priorityFee;
38
+ const computeUnitMarginMultiplier = config.computeUnitMarginMultiplier;
39
+ let priorityFeeMicroLamports = 0n;
40
+ if (priorityFee.type === "exact") {
41
+ priorityFeeMicroLamports = priorityFee.amountLamports * 1000000n / BigInt(computeUnits);
42
+ } else if (priorityFee.type === "dynamic") {
43
+ const estimatedPriorityFee = await calculateDynamicPriorityFees(
44
+ rpc,
45
+ message.instructions,
46
+ priorityFee.priorityFeePercentile ?? "50"
47
+ );
48
+ if (!priorityFee.maxCapLamports) {
49
+ priorityFeeMicroLamports = estimatedPriorityFee;
50
+ } else {
51
+ const maxCapMicroLamports = priorityFee.maxCapLamports * 1000000n / BigInt(computeUnits);
52
+ priorityFeeMicroLamports = maxCapMicroLamports > estimatedPriorityFee ? estimatedPriorityFee : maxCapMicroLamports;
53
+ }
54
+ }
55
+ if (priorityFeeMicroLamports > 0) {
56
+ message = prependTransactionMessageInstruction(
57
+ getSetComputeUnitPriceInstruction({
58
+ microLamports: priorityFeeMicroLamports
59
+ }),
60
+ message
61
+ );
62
+ }
63
+ message = prependTransactionMessageInstruction(
64
+ getSetComputeUnitLimitInstruction({
65
+ units: Math.ceil(computeUnits * (computeUnitMarginMultiplier ?? DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER))
66
+ }),
67
+ message
68
+ );
69
+ return message;
70
+ }
71
+ function getWritableAccounts(ixs) {
72
+ const writable = /* @__PURE__ */ new Set();
73
+ ixs.forEach((ix) => {
74
+ if (ix.accounts) {
75
+ ix.accounts.forEach((acc) => {
76
+ if (isWritableRole(acc.role)) writable.add(acc.address);
77
+ });
78
+ }
79
+ });
80
+ return Array.from(writable);
81
+ }
82
+ async function calculateDynamicPriorityFees(rpc, instructions, percentile) {
83
+ const writableAccounts = getWritableAccounts(instructions);
84
+ const recent = await rpc.getRecentPrioritizationFees(writableAccounts).send();
85
+ const nonZero = recent.filter((pf) => pf.prioritizationFee > 0).map((pf) => pf.prioritizationFee);
86
+ const sorted = nonZero.sort((a, b) => Number(a - b));
87
+ return sorted[Math.floor(sorted.length * (parseInt(percentile) / 100))] || BigInt(0);
88
+ }
89
+
90
+ // src/jito.ts
91
+ import { address, lamports, prependTransactionMessageInstruction as prependTransactionMessageInstruction2 } from "@solana/kit";
92
+ import { getTransferSolInstruction } from "@solana-program/system";
93
+ async function processJitoTipForTxMessage(message, signer, config) {
94
+ let jitoTipLamports = BigInt(0);
95
+ const jito = config.jito;
96
+ if (jito.type === "exact") {
97
+ jitoTipLamports = jito.amountLamports;
98
+ } else if (jito.type === "dynamic") {
99
+ jitoTipLamports = await recentJitoTip(config);
100
+ }
101
+ if (jitoTipLamports > 0) {
102
+ return prependTransactionMessageInstruction2(
103
+ getTransferSolInstruction({
104
+ source: signer,
105
+ destination: getJitoTipAddress(),
106
+ amount: jitoTipLamports
107
+ }),
108
+ message
109
+ );
110
+ } else {
111
+ return message;
112
+ }
113
+ }
114
+ async function recentJitoTip(config) {
115
+ const response = await fetch(`${config.jitoBlockEngineUrl}/api/v1/bundles/tip_floor`);
116
+ if (!response.ok) {
117
+ return BigInt(0);
118
+ }
119
+ const data = await response.json().then((res) => res[0]);
120
+ const percentileToKey = {
121
+ "25": "landed_tips_25th_percentile",
122
+ "50": "landed_tips_50th_percentile",
123
+ "75": "landed_tips_75th_percentile",
124
+ "95": "landed_tips_95th_percentile",
125
+ "99": "landed_tips_99th_percentile",
126
+ "50ema": "ema_landed_tips_50th_percentile"
127
+ };
128
+ const key = percentileToKey[config.priorityFee.priorityFeePercentile ?? "50"];
129
+ if (!key || !data[key]) {
130
+ return BigInt(0);
131
+ }
132
+ return lamports(BigInt(Math.floor(Number(data[key]) * 10 ** 9))).valueOf();
133
+ }
134
+ var jitoTipAddresses = [
135
+ "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
136
+ "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe",
137
+ "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY",
138
+ "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49",
139
+ "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh",
140
+ "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt",
141
+ "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL",
142
+ "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
143
+ ];
144
+ function getJitoTipAddress() {
145
+ return address(jitoTipAddresses[Math.floor(Math.random() * jitoTipAddresses.length)]);
146
+ }
147
+
148
+ // src/buildTransaction.ts
149
+ async function buildTransaction(rpc, config, instructions, feePayer, lookupTableAddresses) {
150
+ return buildTransactionMessage(
151
+ rpc,
152
+ config,
153
+ instructions,
154
+ !("address" in feePayer) ? createNoopSigner(feePayer) : feePayer,
155
+ lookupTableAddresses
156
+ );
157
+ }
158
+ async function buildTransactionMessage(rpc, config, instructions, signer, lookupTableAddresses) {
159
+ let message = await prepareTransactionMessage(instructions, rpc, signer);
160
+ if (lookupTableAddresses?.length) {
161
+ const lookupTableAccounts = await fetchAllMaybeAddressLookupTable(rpc, lookupTableAddresses);
162
+ const tables = lookupTableAccounts.reduce(
163
+ (prev, account) => {
164
+ if (account.exists) {
165
+ assertAccountDecoded(account);
166
+ prev[account.address] = account.data.addresses;
167
+ }
168
+ return prev;
169
+ },
170
+ {}
171
+ );
172
+ message = compressTransactionMessageUsingAddressLookupTables(message, tables);
173
+ }
174
+ const messageWithExtraInstructions = await addPriorityInstructions(rpc, message, signer, config);
175
+ return signTransactionMessageWithSigners(messageWithExtraInstructions);
176
+ }
177
+ async function prepareTransactionMessage(instructions, rpc, signer) {
178
+ const { value: blockhash } = await rpc.getLatestBlockhash({
179
+ commitment: "confirmed"
180
+ }).send();
181
+ return pipe(
182
+ createTransactionMessage({ version: 0 }),
183
+ (tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
184
+ (tx) => setTransactionMessageFeePayerSigner(signer, tx),
185
+ (tx) => appendTransactionMessageInstructions(instructions, tx)
186
+ );
187
+ }
188
+ async function addPriorityInstructions(rpc, message, signer, config) {
189
+ if (config.jito.type !== "none") {
190
+ message = await processJitoTipForTxMessage(message, signer, config);
191
+ }
192
+ let computeUnits = 14e5;
193
+ try {
194
+ computeUnits = await getComputeUnitsForTxMessage(rpc, message);
195
+ } catch {
196
+ console.warn("Transaction simulation failed, using 1,400,000 compute units");
197
+ }
198
+ return processComputeBudgetForTxMessage(rpc, message, computeUnits, config);
199
+ }
200
+ async function getComputeUnitsForTxMessage(rpc, txMessage) {
201
+ return await estimateComputeUnitLimitFactory({ rpc })(txMessage);
202
+ }
203
+
204
+ // src/sendTransaction.ts
205
+ import {
206
+ getBase58Decoder,
207
+ getBase64EncodedWireTransaction
208
+ } from "@solana/kit";
209
+ async function sendTransaction(rpc, instructions, payer, config, lookupTableAddresses, commitment = "confirmed") {
210
+ const tx = await buildTransaction(
211
+ rpc,
212
+ config ?? DEFAULT_TRANSACTION_CONFIG,
213
+ instructions,
214
+ payer,
215
+ lookupTableAddresses
216
+ );
217
+ return sendSignedTransaction(rpc, tx, commitment);
218
+ }
219
+ async function sendSignedTransaction(rpc, transaction, commitment = "confirmed") {
220
+ const txSignature = getTxSignature(transaction);
221
+ const encodedTransaction = getBase64EncodedWireTransaction(transaction);
222
+ const simResult = await rpc.simulateTransaction(encodedTransaction, {
223
+ encoding: "base64"
224
+ }).send();
225
+ if (simResult.value.err) {
226
+ throw new Error(`Transaction simulation failed`, { cause: simResult.value });
227
+ }
228
+ const expiryTime = Date.now() + 6e4;
229
+ while (Date.now() < expiryTime) {
230
+ await rpc.sendTransaction(encodedTransaction, {
231
+ maxRetries: BigInt(0),
232
+ skipPreflight: true,
233
+ encoding: "base64"
234
+ }).send();
235
+ const { value } = await rpc.getSignatureStatuses([txSignature]).send();
236
+ const status = value[0];
237
+ if (status?.confirmationStatus === commitment) {
238
+ if (status.err) {
239
+ throw new Error(`Transaction failed`, { cause: status.err });
240
+ }
241
+ return txSignature;
242
+ }
243
+ }
244
+ throw new Error("Transaction expired");
245
+ }
246
+ function getTxSignature(transaction) {
247
+ const [signature] = Object.values(transaction.signatures);
248
+ return getBase58Decoder().decode(signature);
249
+ }
250
+ export {
251
+ DEFAULT_COMPUTE_UNIT_MARGIN_MULTIPLIER,
252
+ DEFAULT_TRANSACTION_CONFIG,
253
+ buildTransaction,
254
+ sendSignedTransaction,
255
+ sendTransaction
256
+ };
257
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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 compressTransactionMessageUsingAddressLookupTables,\n createNoopSigner,\n createTransactionMessage,\n estimateComputeUnitLimitFactory,\n Instruction,\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 { fetchAllMaybeAddressLookupTable } 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)[]} [lookupTableAddresses] - Optional array of address lookup table addresses 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 lookupTableAddresses?: Address[],\n): Promise<Readonly<SendableTransaction & Transaction & TransactionWithLifetime>> {\n return buildTransactionMessage(\n rpc,\n config,\n instructions,\n !(\"address\" in feePayer) ? createNoopSigner(feePayer) : feePayer,\n lookupTableAddresses,\n );\n}\n\nasync function buildTransactionMessage(\n rpc: Rpc<SolanaRpcApi>,\n config: TransactionConfig,\n instructions: Instruction[],\n signer: TransactionSigner,\n lookupTableAddresses?: Address[],\n) {\n let message = await prepareTransactionMessage(instructions, rpc, signer);\n\n if (lookupTableAddresses?.length) {\n const lookupTableAccounts = await fetchAllMaybeAddressLookupTable(rpc, lookupTableAddresses);\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 try {\n computeUnits = await getComputeUnitsForTxMessage(rpc, message);\n } catch {\n console.warn(\"Transaction simulation failed, using 1,400,000 compute units\");\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};\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};\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 Address,\n Commitment,\n getBase58Decoder,\n getBase64EncodedWireTransaction,\n Instruction,\n KeyPairSigner,\n Rpc,\n SendableTransaction,\n Signature,\n SolanaRpcApi,\n Transaction,\n TransactionWithLifetime,\n} from \"@solana/kit\";\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[]} [lookupTableAddresses] - Optional array of address lookup table addresses 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 lookupTableAddresses?: Address[],\n commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const tx = await buildTransaction(\n rpc,\n config ?? DEFAULT_TRANSACTION_CONFIG,\n instructions,\n payer,\n lookupTableAddresses,\n );\n return sendSignedTransaction(rpc, tx, 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 {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 commitment: Commitment = \"confirmed\",\n): Promise<Signature> {\n const txSignature = getTxSignature(transaction);\n const encodedTransaction = getBase64EncodedWireTransaction(transaction);\n\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 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":";AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,OAOK;AACP,SAAS,uCAAuC;;;ACdhD,SAAS,gBAAgB,4CAA4C;AACrE,SAAS,mCAAmC,yCAAyC;;;ACN9E,IAAM,yCAAyC;AAK/C,IAAM,6BAAgD;AAAA,EAC3D,aAAa;AAAA,IACX,MAAM;AAAA,IACN,uBAAuB;AAAA,EACzB;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,uBAAuB;AAAA,EACzB;AAAA,EACA,6BAA6B;AAAA,EAC7B,oBAAoB;AACtB;;;ADLA,eAAsB,iCACpB,KACA,SACA,cACA,QACA;AACA,QAAM,cAAc,OAAO;AAC3B,QAAM,8BAA8B,OAAO;AAC3C,MAAI,2BAA2B;AAE/B,MAAI,YAAY,SAAS,SAAS;AAChC,+BAA4B,YAAY,iBAAiB,WAAc,OAAO,YAAY;AAAA,EAC5F,WAAW,YAAY,SAAS,WAAW;AACzC,UAAM,uBAAuB,MAAM;AAAA,MACjC;AAAA,MACA,QAAQ;AAAA,MACR,YAAY,yBAAyB;AAAA,IACvC;AAEA,QAAI,CAAC,YAAY,gBAAgB;AAC/B,iCAA2B;AAAA,IAC7B,OAAO;AACL,YAAM,sBAAuB,YAAY,iBAAiB,WAAc,OAAO,YAAY;AAE3F,iCACE,sBAAsB,uBAAuB,uBAAuB;AAAA,IACxE;AAAA,EACF;AAEA,MAAI,2BAA2B,GAAG;AAChC,cAAU;AAAA,MACR,kCAAkC;AAAA,QAChC,eAAe;AAAA,MACjB,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AAEA,YAAU;AAAA,IACR,kCAAkC;AAAA,MAChC,OAAO,KAAK,KAAK,gBAAgB,+BAA+B,uCAAuC;AAAA,IACzG,CAAC;AAAA,IACD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAA6B;AACxD,QAAM,WAAW,oBAAI,IAAa;AAClC,MAAI,QAAQ,QAAM;AAChB,QAAI,GAAG,UAAU;AACf,SAAG,SAAS,QAAQ,SAAO;AACzB,YAAI,eAAe,IAAI,IAAI,EAAG,UAAS,IAAI,IAAI,OAAO;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,SAAO,MAAM,KAAK,QAAQ;AAC5B;AAEA,eAAe,6BACb,KACA,cACA,YACA;AACA,QAAM,mBAAmB,oBAAoB,YAAY;AACzD,QAAM,SAAS,MAAM,IAAI,4BAA4B,gBAAgB,EAAE,KAAK;AAC5E,QAAM,UAAU,OAAO,OAAO,QAAM,GAAG,oBAAoB,CAAC,EAAE,IAAI,QAAM,GAAG,iBAAiB;AAC5F,QAAM,SAAS,QAAQ,KAAK,CAAC,GAAG,MAAM,OAAO,IAAI,CAAC,CAAC;AACnD,SAAO,OAAO,KAAK,MAAM,OAAO,UAAU,SAAS,UAAU,IAAI,IAAI,CAAC,KAAK,OAAO,CAAC;AACrF;;;AEnFA,SAAS,SAAS,UAAU,wCAAAA,6CAA4C;AACxE,SAAS,iCAAiC;AAI1C,eAAsB,2BACpB,SACA,QACA,QACA;AACA,MAAI,kBAAkB,OAAO,CAAC;AAC9B,QAAM,OAAO,OAAO;AAEpB,MAAI,KAAK,SAAS,SAAS;AACzB,sBAAkB,KAAK;AAAA,EACzB,WAAW,KAAK,SAAS,WAAW;AAClC,sBAAkB,MAAM,cAAc,MAAM;AAAA,EAC9C;AACA,MAAI,kBAAkB,GAAG;AACvB,WAAOA;AAAA,MACL,0BAA0B;AAAA,QACxB,QAAQ;AAAA,QACR,aAAa,kBAAkB;AAAA,QAC/B,QAAQ;AAAA,MACV,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAGA,eAAsB,cAAc,QAA2B;AAC7D,QAAM,WAAW,MAAM,MAAM,GAAG,OAAO,kBAAkB,2BAA2B;AACpF,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,OAAO,CAAC;AAAA,EACjB;AACA,QAAM,OAAO,MAAM,SAAS,KAAK,EAAE,KAAK,SAAO,IAAI,CAAC,CAAC;AAErD,QAAM,kBAAwD;AAAA,IAC5D,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAEA,QAAM,MAAM,gBAAgB,OAAO,YAAY,yBAAyB,IAAI;AAC5E,MAAI,CAAC,OAAO,CAAC,KAAK,GAAG,GAAG;AACtB,WAAO,OAAO,CAAC;AAAA,EACjB;AACA,SAAO,SAAS,OAAO,KAAK,MAAM,OAAO,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ;AAC3E;AAMA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,oBAA6B;AAGpC,SAAO,QAAQ,iBAAiB,KAAK,MAAM,KAAK,OAAO,IAAI,iBAAiB,MAAM,CAAC,CAAC;AACtF;;;AH5BA,eAAsB,iBACpB,KACA,QACA,cACA,UACA,sBACgF;AAChF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,aAAa,YAAY,iBAAiB,QAAQ,IAAI;AAAA,IACxD;AAAA,EACF;AACF;AAEA,eAAe,wBACb,KACA,QACA,cACA,QACA,sBACA;AACA,MAAI,UAAU,MAAM,0BAA0B,cAAc,KAAK,MAAM;AAEvE,MAAI,sBAAsB,QAAQ;AAChC,UAAM,sBAAsB,MAAM,gCAAgC,KAAK,oBAAoB;AAC3F,UAAM,SAAS,oBAAoB;AAAA,MACjC,CAAC,MAAM,YAAY;AACjB,YAAI,QAAQ,QAAQ;AAClB,+BAAqB,OAAO;AAC5B,eAAK,QAAQ,OAAO,IAAI,QAAQ,KAAK;AAAA,QACvC;AACA,eAAO;AAAA,MACT;AAAA,MACA,CAAC;AAAA,IACH;AACA,cAAU,mDAAmD,SAAS,MAAM;AAAA,EAC9E;AAEA,QAAM,+BAA+B,MAAM,wBAAwB,KAAK,SAAS,QAAQ,MAAM;AAE/F,SAAO,kCAAkC,4BAA4B;AACvE;AAEA,eAAe,0BACb,cACA,KACA,QACA;AACA,QAAM,EAAE,OAAO,UAAU,IAAI,MAAM,IAChC,mBAAmB;AAAA,IAClB,YAAY;AAAA,EACd,CAAC,EACA,KAAK;AAER,SAAO;AAAA,IACL,yBAAyB,EAAE,SAAS,EAAE,CAAC;AAAA,IACvC,QAAM,4CAA4C,WAAW,EAAE;AAAA,IAC/D,QAAM,oCAAoC,QAAQ,EAAE;AAAA,IACpD,QAAM,qCAAqC,cAAc,EAAE;AAAA,EAC7D;AACF;AAEA,eAAe,wBACb,KACA,SACA,QACA,QAC8D;AAC9D,MAAI,OAAO,KAAK,SAAS,QAAQ;AAC/B,cAAU,MAAM,2BAA2B,SAAS,QAAQ,MAAM;AAAA,EACpE;AAEA,MAAI,eAAe;AAEnB,MAAI;AACF,mBAAe,MAAM,4BAA4B,KAAK,OAAO;AAAA,EAC/D,QAAQ;AACN,YAAQ,KAAK,8DAA8D;AAAA,EAC7E;AAEA,SAAO,iCAAiC,KAAK,SAAS,cAAc,MAAM;AAC5E;AAEA,eAAe,4BACb,KACA,WACA;AACA,SAAO,MAAM,gCAAgC,EAAE,IAAI,CAAC,EAAE,SAAS;AACjE;;;AI1IA;AAAA,EAGE;AAAA,EACA;AAAA,OASK;AA8BP,eAAsB,gBACpB,KACA,cACA,OACA,QACA,sBACA,aAAyB,aACL;AACpB,QAAM,KAAK,MAAM;AAAA,IACf;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,sBAAsB,KAAK,IAAI,UAAU;AAClD;AAsBA,eAAsB,sBACpB,KACA,aACA,aAAyB,aACL;AACpB,QAAM,cAAc,eAAe,WAAW;AAC9C,QAAM,qBAAqB,gCAAgC,WAAW;AAGtE,QAAM,YAAY,MAAM,IACrB,oBAAoB,oBAAoB;AAAA,IACvC,UAAU;AAAA,EACZ,CAAC,EACA,KAAK;AAER,MAAI,UAAU,MAAM,KAAK;AACvB,UAAM,IAAI,MAAM,iCAAiC,EAAE,OAAO,UAAU,MAAM,CAAC;AAAA,EAC7E;AAEA,QAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,SAAO,KAAK,IAAI,IAAI,YAAY;AAC9B,UAAM,IACH,gBAAgB,oBAAoB;AAAA,MACnC,YAAY,OAAO,CAAC;AAAA,MACpB,eAAe;AAAA,MACf,UAAU;AAAA,IACZ,CAAC,EACA,KAAK;AAER,UAAM,EAAE,MAAM,IAAI,MAAM,IAAI,qBAAqB,CAAC,WAAW,CAAC,EAAE,KAAK;AACrE,UAAM,SAAS,MAAM,CAAC;AACtB,QAAI,QAAQ,uBAAuB,YAAY;AAC7C,UAAI,OAAO,KAAK;AACd,cAAM,IAAI,MAAM,sBAAsB,EAAE,OAAO,OAAO,IAAI,CAAC;AAAA,MAC7D;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,qBAAqB;AACvC;AAEA,SAAS,eAAe,aAA0B;AAChD,QAAM,CAAC,SAAS,IAAI,OAAO,OAAO,YAAY,UAAU;AACxD,SAAO,iBAAiB,EAAE,OAAO,SAAU;AAC7C;","names":["prependTransactionMessageInstruction"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@unio-aggregator/unio-tx-sender",
3
+ "description": "A TypeScript package for building and sending Solana transactions with support for priority fees and Jito tips.",
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "exports": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.cts",
19
+ "require": "./dist/index.cjs"
20
+ }
21
+ },
22
+ "sideEffects": false,
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsup src/index.ts --format cjs,esm --dts --sourcemap",
29
+ "lint": "pnpm eslint && pnpm type-check",
30
+ "eslint": "eslint \"**/*.ts*\" --fix",
31
+ "type-check": "tsc -p .",
32
+ "clean": "rimraf dist"
33
+ },
34
+ "dependencies": {
35
+ "@solana-program/address-lookup-table": "^0.11.0",
36
+ "@solana-program/compute-budget": "^0.15.0",
37
+ "@solana-program/system": "^0.11.0",
38
+ "@solana/kit": "^6.9.0",
39
+ "@solana/rpc": "^6.9.0",
40
+ "@solana/rpc-api": "^6.9.0"
41
+ },
42
+ "devDependencies": {
43
+ "@unio-aggregator/prettier-config": "^1.0.1",
44
+ "@unio-aggregator/typescript-config": "^1.0.1",
45
+ "@eslint/eslintrc": "^3.3.5",
46
+ "@eslint/js": "^10.0.1",
47
+ "@typescript-eslint/eslint-plugin": "^8.62.1",
48
+ "@typescript-eslint/parser": "^8.62.1",
49
+ "tsup": "^8.3.5",
50
+ "typescript": "5.8.3",
51
+ "rimraf": "^6.1.3",
52
+ "eslint": "^10.6.0",
53
+ "eslint-plugin-prettier": "^5.5.6",
54
+ "eslint-plugin-simple-import-sort": "^13.0.0"
55
+ }
56
+ }