Solana Transactions: Durable Nonces (2023)
When submitting a transaction on Solana as a developer, you need to fetch the latest blockhash via the Solana RPC. This crucial step helps mitigate replay attacks, ensuring that once a transaction is signed and submitted using a particular blockhash, no one can use the same hash to replay or resubmit that transaction.
Imagine needing to submit a transaction that requires a signature from an offline cold storage or hardware wallet like Ledger. However, blockhashes expire quickly, potentially rendering your transaction invalid. This is where durable nonces come in, enabling secure offline transactions.
By the end of this guide, you will understand:
- What a durable nonce is.
- The purpose of a durable nonce.
- How to use durable nonces in transactions.
Before getting started, make sure you have:
- NodeJS installed.
- Solana CLI Installed.
- Git installed
- Clone our example repository with existing utils:
- Navigate into project folder and install npm:
- Navigate to the wallets folder inside of nonce folder, this will house our local keys for testing and navigate into it:
- With Solana CLI installed, create one wallet for the paying keypair:
- Now set this as your wallet on the CLI to airdrop Solana:
- Now you can airdrop Solana to this address by running the following:
- We also need to create and fund another wallet for the nonce authority:
- For this public key produced, we can use a faucet site to airdrop 1 SOL to it, here.
Now that we have our environment set up, we can move on to our next steps.
What is a Durable Nonce?
A durable nonce account on Solana can be seen as a safety deposit box. When you initiate this account, Solana assigns it a unique, stable code called a "durable nonce." Unlike typical nonces that change with every transaction, this one remains steady, serving as a consistent reference.
This is particularly useful for "offline" transactions. When crafting a transaction, you reference this nonce from your account. Solana validates it against the stored value, and if there's a match, the transaction gets the green light. Therefore, a durable nonce account is both a storage and validation mechanism, ensuring transactional authenticity while accommodating the rapid pace and offline scenarios of the Solana network.
Durable nonce’s can be used in various use cases, such as:
- Scheduled transactions: You can set up transactions to occur at a specified time in the future. Durable nonces ensure that these scheduled transactions are securely executed.
- Multisig wallets: In the context of multisignature wallets, durable nonces provide an additional layer of security and coordination among multiple signers.
- Programs needing future interaction: Some programs on Solana require interactions with other programs or services at specific intervals. Durable nonces help maintain the integrity of these interactions.
- Interacting with other blockchains: When Solana interacts with other blockchains, durable nonces play a role in ensuring the validity of cross-chain transactions.
Now, we can get started on our example build.
Solana Transactions: Steps to Build
Step 1: Set Up Dependencies and Constants
In this step, you'll import necessary modules and utilities, and define constants and keypairs for the example. These dependencies and constants will be used throughout the transaction process.
Step 2: Create the sendTransaction Function
The sendTransaction function orchestrates the process of sending a transaction using a durable nonce. This function handles nonce creation, confirmation, and transaction execution.
Step 3: Create the nonce Function
The nonce function is responsible for creating and initializing the durable nonce account. This involves calculating the rent required for the account, fetching the latest blockhash, and constructing transactions to both create and initialize the nonce account.
- Before creating the nonce account, we need to calculate the rent required for the account data storage and fetch the latest blockhash.
- Now, we'll construct a transaction to create the nonce account. This involves using the SystemProgram.createAccount instruction to allocate space for the nonce account.
- We'll sign the transaction with the authority keypairs, and send it to the Solana network. This transaction creates the durable nonce account.
- After sending the transaction, we'll confirm its status to ensure the nonce account creation was successful.
- To fully utilize the nonce account, we need to initialize its value. We'll create a new transaction to execute the SystemProgram.nonceInitialize instruction.
- Similar to the previous step, we'll sign the transaction and send it to the network to initialize the nonce account.
- Finally, we'll confirm the status of the initialization transaction to ensure the nonce account is properly initialized.
The entire function should look similar to this:
Step 4: Create the getNonce Function
Define the getNonce function, responsible for fetching the nonce value from the created nonce account.
Step 5: Create the createTx Function
Define the createTx function, which creates a sample transaction containing both the advance nonce instruction and a transfer instruction. It uses the previously fetched nonce to ensure transaction authenticity.
Step 6: Create the signOffline Function
Define the signOffline function, responsible for signing the transaction offline. It simulates an offline delay before signing the transaction with both the sender and nonce authority keypairs.
Step 7: Create the executeTx Function
The executeTx function is responsible for sending the signed transaction to the Solana network for execution. This is the final step in the transaction process, where the transaction is broadcast to the network.
Step 8: Create the fetchNonceInfo Function
The fetchNonceInfo function fetches nonce information from the created nonce account, retrying up to three times if necessary. This helps ensure that the nonce used in the transaction is up-to-date and valid.
Step 9: Call the sendTransaction Function
Finally, call the sendTransaction function to initiate the transaction process. This function brings together all the previously defined steps to create, sign, and execute a transaction using a durable nonce.
Running sendTransaction will populate a transaction signature for a successful transaction. This signature is a critical piece of information for tracking and verifying the transaction on the Solana network.
You have now used a durable nonce in a successful transaction!
Solana Transactions: Using Helius RPCs
Helius can act as a powerful intermediary for interacting with Solana's RPCs, simplifying the process of fetching blockhash information needed for durable nonces. Through Helius, you can manage the lifecycle of your Solana transactions more reliably, especially for offline scenarios. It can provide streamlined access to blockhashes, helping developers make their applications more robust against transaction expirations.
In summary, durable nonces in Solana transactions offer a secure and reliable way to handle offline transactions and ensure the authenticity of transactions. By following the steps outlined in this guide, developers can implement durable nonces in their Solana applications, enhancing security and flexibility.