Use Nonce Account
Use a durable nonce for offline and delayed transactions
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
pipe,
setTransactionMessageFeePayerSigner,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
createKeyPairSignerFromBytes,
address,
lamports,
setTransactionMessageLifetimeUsingDurableNonce,
} from "@solana/kit";
import { getAdvanceNonceAccountInstruction, getTransferSolInstruction } from "@solana-program/system";
import wallet from '../wallet.json';
const rpc = createSolanaRpc(`http://localhost:8899`);
const rpcSubscriptions = createSolanaRpcSubscriptions(`ws://localhost:8900`);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
const useNonceAccount = async () => {
const keypairSigner = await createKeyPairSignerFromBytes(new Uint8Array(wallet));
const nonceAccountAddress = address("NONCE_ACCOUNT_ADDRESS");
const destination = address("DESTINATION_ADDRESS");
// Fetch the nonce account to get the current nonce value
const nonceAccount = await rpc.getAccountInfo(nonceAccountAddress, {
encoding: "jsonParsed",
}).send();
if (!nonceAccount.value) {
throw new Error("Nonce account not found");
}
const parsed = nonceAccount.value.data as any;
const currentNonce = parsed.parsed.info.blockhash;
const transaction = pipe(
createTransactionMessage({ version: 0 }),
m => setTransactionMessageFeePayerSigner(keypairSigner, m),
m => setTransactionMessageLifetimeUsingDurableNonce({
nonce: currentNonce,
nonceAccountAddress,
nonceAuthority: keypairSigner,
}, m),
m => appendTransactionMessageInstructions(
[
getTransferSolInstruction({
source: keypairSigner,
destination,
amount: lamports(1_000_000n),
}),
],
m,
),
);
const signedTransaction = await signTransactionMessageWithSigners(transaction);
try {
await sendAndConfirmTransaction(signedTransaction, {
commitment: 'processed',
skipPreflight: true,
});
const signature = getSignatureFromTransaction(signedTransaction);
console.log(`Transaction sent with durable nonce. Signature: ${signature}`);
} catch (error) {
console.error('Transaction failed:', error);
throw error;
}
};
useNonceAccount();
Old Way
import {
clusterApiUrl,
Connection,
Keypair,
LAMPORTS_PER_SOL,
NonceAccount,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import walletSecret from '../wallet.json';
(async () => {
const wallet = Keypair.fromSecretKey(new Uint8Array(walletSecret));
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const nonceAccountPubkey = new PublicKey("NONCE_ACCOUNT_ADDRESS");
const destination = new PublicKey("DESTINATION_ADDRESS");
// Fetch the nonce account info
const accountInfo = await connection.getAccountInfo(nonceAccountPubkey);
if (!accountInfo) {
throw new Error("Nonce account not found");
}
const nonceAccount = NonceAccount.fromAccountData(accountInfo.data);
const transaction = new Transaction();
transaction.recentBlockhash = nonceAccount.nonce;
transaction.feePayer = wallet.publicKey;
// Must include advance nonce instruction as the first instruction
transaction.add(
SystemProgram.nonceAdvance({
noncePubkey: nonceAccountPubkey,
authorizedPubkey: wallet.publicKey,
})
);
transaction.add(
SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: destination,
lamports: LAMPORTS_PER_SOL * 0.001,
})
);
const txId = await sendAndConfirmTransaction(connection, transaction, [
wallet,
]);
console.log(`Transaction sent with durable nonce. Tx Id: ${txId}`);
})();