UNPKG

@macalinao/grill

Version:

Modern Solana development kit for React applications with automatic account batching, caching, and transaction notifications

144 lines 5.87 kB
import { compressTransactionMessageUsingAddressLookupTables, signAndSendTransactionMessageWithSigners, } from "@solana/kit"; import { createTransaction } from "gill"; import { getSignatureFromBytes } from "../get-signature-from-bytes.js"; import { pollConfirmTransaction } from "../poll-confirm-transaction.js"; /** * Creates a function to send transactions using the modern @solana/kit API * while maintaining compatibility with the wallet adapter. */ export const createSendTX = ({ signer, rpc, refetchAccounts, onTransactionStatusEvent, getExplorerLink, }) => { return async (name, ixs, options = {}) => { const txId = Math.random().toString(36).substring(2, 15); const baseEvent = { id: txId, title: name, }; if (!signer) { onTransactionStatusEvent({ ...baseEvent, type: "error-wallet-not-connected", }); throw new Error("Wallet not connected"); } onTransactionStatusEvent({ ...baseEvent, type: "preparing", }); const { value: latestBlockhash } = await rpc.getLatestBlockhash().send(); const transactionMessage = createTransaction({ version: 0, feePayer: signer, instructions: [...ixs], latestBlockhash, // the compute budget values are HIGHLY recommend to be set in order to maximize your transaction landing rate computeUnitLimit: options.computeUnitLimit === null ? undefined : (options.computeUnitLimit ?? 1_400_000), computeUnitPrice: options.computeUnitPrice === null ? undefined : (options.computeUnitPrice ?? 100000n), }); // Apply address lookup tables if provided to compress the transaction const addressLookupTables = options.lookupTables ?? {}; const finalTransactionMessage = Object.keys(addressLookupTables).length > 0 ? compressTransactionMessageUsingAddressLookupTables(transactionMessage, addressLookupTables) : transactionMessage; onTransactionStatusEvent({ ...baseEvent, type: "awaiting-wallet-signature", }); // Send transaction using wallet adapter let sigBytes; try { sigBytes = await signAndSendTransactionMessageWithSigners(finalTransactionMessage); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Failed to send transaction"; onTransactionStatusEvent({ ...baseEvent, type: "error-transaction-send-failed", errorMessage, }); throw error; } const sig = getSignatureFromBytes(sigBytes); const sentTxEvent = { ...baseEvent, sig, explorerLink: getExplorerLink({ transaction: sig }), }; onTransactionStatusEvent({ ...sentTxEvent, type: "waiting-for-confirmation", }); try { const result = await pollConfirmTransaction({ signature: sig, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, rpc, }); onTransactionStatusEvent({ ...sentTxEvent, type: "confirmed", }); // Reload the accounts that were written to const writableAccounts = result.transaction.message.accountKeys .filter((key) => key.writable) .map((k) => k.pubkey); if (writableAccounts.length > 0) { const waitForAccountRefetch = options.waitForAccountRefetch ?? true; if (waitForAccountRefetch) { await refetchAccounts(writableAccounts); } else { // Refetch in background without waiting refetchAccounts(writableAccounts).catch((error) => { console.warn("Failed to refetch accounts in background:", error); }); } } if (result.meta?.logMessages) { console.log(name, result.meta.logMessages.join("\n")); } // Return the signature as a base58 string return sig; } catch (error) { // Log error details for debugging console.error(`${name} transaction failed:`, error); // Extract error logs const extractErrorLogs = (err) => { if (err && typeof err === "object" && "logs" in err && Array.isArray(err.logs)) { return err.logs; } if (err && typeof err === "object" && "context" in err && typeof err.context === "object" && err.context.logs && Array.isArray(err.context.logs)) { return err.context.logs; } return []; }; const errorLogs = extractErrorLogs(error); if (errorLogs.length > 0) { console.log("Transaction logs:"); for (const log of errorLogs) { console.log(" ", log); } } const errorMessage = error instanceof Error ? error.message : "Transaction failed."; onTransactionStatusEvent({ ...sentTxEvent, type: "error-transaction-failed", errorMessage, }); throw error; } }; }; //# sourceMappingURL=create-send-tx.js.map