To rely on Privy’s API to fill in the recentBlockhash field of the Solana transaction, pass in the
dummy value
11111111111111111111111111111111 for the recentBlockhash field.When using Privy’s server-side SDKs to send transactions, you can use the authorization context to
automatically sign requests. Learn more about signing on the
server.
- React
- React Native
- Swift
- Android
- Flutter
- NodeJS
- NodeJS (server-auth)
- Java
- REST API
- Rust
To send a transaction from a wallet using the React SDK, use the
signAndSendTransaction method from the useSignAndSendTransaction hook:Report incorrect code
Copy
Ask AI
signAndSendTransaction: (input: {
transaction: Uint8Array;
wallet: ConnectedStandardSolanaWallet;
chain?: SolanaChain;
options?: SolanaSignAndSendTransactionOptions & {
uiOptions?: SendTransactionModalUIOptions;
sponsor?: boolean;
};
}) => Promise<{ signature: Uint8Array }>
Usage
Report incorrect code
Copy
Ask AI
import {useSignAndSendTransaction, useWallets} from '@privy-io/react-auth/solana';
import {
pipe,
createSolanaRpc,
getTransactionEncoder,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
compileTransaction,
address,
createNoopSigner
} from '@solana/kit';
import {getTransferSolInstruction} from '@solana-program/system';
// Inside your component
const {signAndSendTransaction} = useSignAndSendTransaction();
const {wallets} = useWallets();
const selectedWallet = wallets[0];
const amount = 1;
const transferInstruction = getTransferSolInstruction({
amount: BigInt(parseFloat(amount) * 1_000_000_000), // Convert SOL to lamports
destination: address('RecipientAddressHere'),
source: createNoopSigner(address(selectedWallet.address))
});
// Configure your RPC connection to point to the correct Solana network
const {getLatestBlockhash} = createSolanaRpc('https://api.mainnet-beta.solana.com'); // Replace with your Solana RPC endpoint
const {value: latestBlockhash} = await getLatestBlockhash().send();
// Create a transaction using @solana/kit
const transaction = pipe(
createTransactionMessage({version: 0}),
(tx) => setTransactionMessageFeePayer(address(selectedWallet.address), tx), // Set the message fee payer
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set recent blockhash
(tx) => appendTransactionMessageInstructions([transferInstruction], tx), // Add your instructions to the transaction
(tx) => compileTransaction(tx), // Compile the transaction
(tx) => new Uint8Array(getTransactionEncoder().encode(tx)) // Finally encode the transaction
);
// Send the transaction
const result = await signAndSendTransaction({
transaction: transaction,
wallet: selectedWallet
});
console.log('Transaction sent with signature:', result.signature);
Parameters
Hide parameters
Hide parameters
The encoded transaction to be sent.
The Solana wallet to use for sending the transaction.
Type of all Solana chains supported by Privy.
options
SolanaSignAndSendTransactionOptions & {uiOptions?: SendTransactionModalUIOptions; sponsor?: boolean}
Additional options for sending the transaction.
Show child attributes
Show child attributes
Optional parameter to enable gas sponsorship for this transaction. Learn
more.
Returns
The signature of the transaction.
Sign and send all transactions
To sign and send multiple transactions in a single call, use thesignAndSendTransaction method with multiple inputs:Report incorrect code
Copy
Ask AI
signAndSendTransaction(...inputs: SignAndSendTransactionInput[]): Promise<SignAndSendTransactionOutput[]>
Usage
Report incorrect code
Copy
Ask AI
import {useSignAndSendTransaction, useWallets} from '@privy-io/react-auth/solana';
import {
pipe,
createSolanaRpc,
getTransactionEncoder,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
compileTransaction,
address,
createNoopSigner
} from '@solana/kit';
import {getTransferSolInstruction} from '@solana-program/system';
// Inside your component
const {signAndSendTransaction} = useSignAndSendTransaction();
const {wallets} = useWallets();
const selectedWallet = wallets[0];
const amount = 1; // Amount of SOL to send
const transferInstruction = getTransferSolInstruction({
amount: BigInt(amount * 1_000_000_000), // Convert SOL to lamports
destination: address('RecipientAddressHere'),
source: createNoopSigner(address(selectedWallet.address))
});
// Configure your RPC connection to point to the correct Solana network
const {getLatestBlockhash} = createSolanaRpc('https://api.mainnet-beta.solana.com'); // Replace with your Solana RPC endpoint
const {value: latestBlockhash} = await getLatestBlockhash().send();
// Create transactions using @solana/kit
const transactions = [
pipe(
createTransactionMessage({version: 0}),
(tx) => setTransactionMessageFeePayer(address(selectedWallet.address), tx), // Set the message fee payer
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set recent blockhash
(tx) => appendTransactionMessageInstructions([transferInstruction], tx), // Add your instructions to the transaction
(tx) => compileTransaction(tx), // Compile the transaction
(tx) => new Uint8Array(getTransactionEncoder().encode(tx)) // Finally encode the transaction
),
pipe(
createTransactionMessage({version: 0}),
(tx) => setTransactionMessageFeePayer(address(selectedWallet.address), tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx),
(tx) => compileTransaction(tx),
(tx) => new Uint8Array(getTransactionEncoder().encode(tx))
)
];
// Send multiple transactions
const results = await signAndSendTransaction(
{
transaction: transactions[0],
wallet: selectedWallet
},
{
transaction: transactions[1],
wallet: selectedWallet
}
);
console.log(
'Transactions sent with signatures:',
results.map((result) => result.signature.toString()).join(',')
);
Parameters
Hide parameters
Hide parameters
The encoded transaction to be sent.
The Solana wallet to use for sending the transaction.
Type of all Solana chains supported by Privy.
options
SolanaSignAndSendTransactionOptions & {uiOptions?: SendTransactionModalUIOptions; sponsor?: boolean}
Additional options for sending the transaction.
Show child attributes
Show child attributes
Optional parameter to enable gas sponsorship for this transaction. Learn
more.
UI options to customize the transaction request modal.
To send a transaction from a wallet using the React Native SDK, use the
request method from the wallet’s provider:Report incorrect code
Copy
Ask AI
request: (request: {
method: 'signAndSendTransaction',
params: {
transaction: Transaction | VersionedTransaction,
connection: Connection
}
}) => Promise<{ signature: string }>
The Expo SDK does not support built-in UIs for sending transactions.
The
signAndSendTransaction method gives you complete control over the experience and UI.Usage
Report incorrect code
Copy
Ask AI
import {Connection} from '@solana/web3.js';
import {useEmbeddedSolanaWallet} from '@privy-io/expo';
const { wallets } = useEmbeddedSolanaWallet();
const wallet = wallets[0];
// Get the provider
const provider = await wallet.getProvider();
// Create a connection to the Solana network
const connection = new Connection('insert-your-rpc-url-here');
// Create your transaction (either legacy Transaction or VersionedTransaction)
// transaction = ...
// Send the transaction
const { signature } = await provider.request({
method: 'signAndSendTransaction',
params: {
transaction: transaction,
connection: connection,
},
});
console.log("Transaction sent with signature:", signature);
Parameters
The RPC method executed with the wallet.
Parameters for the transaction.
Hide child attributes
Hide child attributes
The transaction to sign and send. This can be either a legacy Transaction or a VersionedTransaction object from @solana/web3.js.
Connection to an SVM (Solana) network.
Returns
The signature of the transaction.
Sending a Solana transaction will sign it using the embedded wallet and then submit it to the network.
Report incorrect code
Copy
Ask AI
public protocol EmbeddedSolanaWalletProvider {
func signAndSendTransaction(transaction: Data, cluster: SolanaCluster, options: SolanaSendOptions?) async throws -> String
}
A note on Solana clusters
When sending a transaction you must specify which cluster the transaction is being sent on. For it, the Privy SDK provides theSolanaCluster struct, with the following options:SolanaCluster.mainnetfor the Solana mainnet-beta.SolanaCluster.devnetfor the Solana devnet.SolanaCluster.testnetfor the Solana testnet.SolanaCluster.mainnet.with(rpcUrl: String)for using the Solana mainnet cluster but broadcasting to a different RPC URL than the default one.SolanaCluster(caip2: String, rpcUrl: String)for a fully custom Solana cluster.
Usage
In this example, we’re using theSolanaSwift SDK to build the transaction, to be sent on the mainnet cluster.
You can use whichever method you prefer for building and serializing the transaction before handing off to Privy.Report incorrect code
Copy
Ask AI
import SolanaSwift
// Get the provider for wallet (assumes wallet is already obtained)
let provider = wallet.provider
let cluster = SolanaCluster.mainnet
// Create a Solana RPC client
let solana = JSONRPCAPIClient(endpoint: URL(string: cluster.rpcUrl)!)
// Build the transaction using your preferred method
let latestBlockhash = try await solana.getLatestBlockhash()
// If your application is set to TEE execution, you can allow Privy to set the recent blockhash for
// you by passing in `11111111111111111111111111111111` as the blockhash.
// let latestBlockhash = "11111111111111111111111111111111"
let walletPK = try PublicKey(string: wallet.address)
var tx = Transaction()
tx.instructions.append(
SystemProgram.transferInstruction(
from: walletPK,
to: try PublicKey(string: "9NvE68JVWHHHGLp5NNELtM5fiBw6SXHrzqQJjUqaykC1"),
lamports: 100000000000000
)
)
tx.recentBlockhash = latestBlockhash
tx.feePayer = walletPK
// Sign and broadcast the transaction using the Privy Embedded Wallet
let txHash = try await provider.signAndSendTransaction(transaction: tx.serialize(), cluster: cluster)
print("Transaction sent with hash: \(txHash)")
Parameters
The serialized transaction to sign and send.
The cluster the transaction is being sent on.
This determines both the CAIP-2 formatted ID for the cluster, and the RPC URL to use for broadcasting the transaction.Note that the RPC URL set here is only used for applications running in on device execution mode.
Additional options for the RPC broadcast.
Hide child attributes
Hide child attributes
Disable the transaction verification step.
The preflight commitment level.
The maximum number of times for the RPC node to retry sending the transaction to the leader.
The minimum slot that the request can be evaluated at.
Returns
The hash of the broadcasted transaction.
Use the
signAndSendTransaction method to sign and submit a Solana transaction in a single call.Report incorrect code
Copy
Ask AI
public suspend fun signAndSendTransaction(
transaction: ByteArray,
cluster: SolanaCluster = SolanaCluster.MainNet,
rpcUrl: String? = null,
sendOptions: SendOptions? = null
): Result<String>
Usage
Report incorrect code
Copy
Ask AI
val solanaWallet = user.embeddedSolanaWallets.first()
// Fetch latest blockhash from network
val blockhash = fetchLatestBlockhash(SolanaCluster.DevNet).getOrThrow()
// For apps with TEE execution: use "11111111111111111111111111111111" instead - Privy auto-populates it
// Build the transaction
val fromPubkey = SolanaPublicKey.from(solanaWallet.address)
val instruction = SystemProgram.transfer(
fromPubkey = fromPubkey,
toPubkey = SolanaPublicKey.from(recipientAddress),
lamports = 1000000
)
val txMessage = Message.Builder()
.addInstruction(instruction)
.setRecentBlockhash(blockhash)
.build()
val transaction = Transaction(txMessage).serialize()
// Sign and send
val result = solanaWallet.provider.signAndSendTransaction(
transaction = transaction,
cluster = SolanaCluster.DevNet
)
result.fold(
onSuccess = { signature ->
println("Success: https://explorer.solana.com/tx/$signature?cluster=devnet")
},
onFailure = { error ->
println("Failed: ${error.message}")
}
)
With SendOptions
Report incorrect code
Copy
Ask AI
val result = solanaWallet.provider.signAndSendTransaction(
transaction = transaction,
cluster = SolanaCluster.DevNet,
sendOptions = SendOptions(
preflightCommitment = "confirmed",
maxRetries = 5
)
)
Parameters
The serialized transaction bytes to sign and send.
The Solana network cluster. Defaults to
SolanaCluster.MainNet.Optional custom RPC URL. If not provided, uses the default RPC for the specified cluster.
Optional configuration for transaction submission.
Show child attributes
Show child attributes
Whether to skip preflight transaction checks. Defaults to
false.Commitment level for preflight checks (e.g.,
"confirmed", "finalized").Maximum number of retry attempts for sending the transaction.
Minimum slot number at which the transaction can be evaluated.
The
cluster, rpcUrl, and sendOptions parameters are only valid for apps using on-device execution.Returns
A Result that, when successful, contains the transaction signature.
Use the
signAndSendTransaction method on the Solana wallet provider to sign a transaction and submit it to the network in a single call.Report incorrect code
Copy
Ask AI
Future<Result<String>> signAndSendTransaction({
required Uint8List transaction,
SolanaCluster? cluster,
String? rpcUrl,
SendOptions? sendOptions,
});
Usage
Report incorrect code
Copy
Ask AI
import 'dart:convert';
import 'package:solana/solana.dart';
// Retrieve the user's Solana wallet (assumes wallet is already obtained)
final solanaWallet = user.embeddedSolanaWallets.first;
// Create a Solana RPC client
final rpcClient = RpcClient('https://api.mainnet-beta.solana.com');
// Build the transaction
final walletPublicKey = Ed25519HDPublicKey.fromBase58(solanaWallet.address);
final recipientPublicKey = Ed25519HDPublicKey.fromBase58(recipientAddress);
final instruction = SystemInstruction.transfer(
fundingAccount: walletPublicKey,
recipientAccount: recipientPublicKey,
lamports: amount,
);
// Get recent blockhash
final recentBlockhash = await rpcClient.getLatestBlockhash();
// For apps with TEE execution: use "11111111111111111111111111111111" instead - Privy auto-populates it
// Create transaction
final transaction = Transaction.v0(
payer: walletPublicKey,
recentBlockhash: recentBlockhash.value.blockhash,
instructions: [instruction],
);
// Serialize transaction message
final serializedTransaction = transaction.serializeMessage();
// Sign and send the transaction
final result = await solanaWallet.provider.signAndSendTransaction(
transaction: serializedTransaction
);
// Handle the result
result.when(
success: (txHash) {
print('Transaction sent with hash: $txHash');
},
failure: (error) {
print('Failed to sign and send transaction: $error');
},
);
With SendOptions
Report incorrect code
Copy
Ask AI
final result = await solanaWallet.provider.signAndSendTransaction(
transaction: serializedTransaction,
cluster: SolanaCluster.devNet,
sendOptions: SendOptions(
preflightCommitment: 'confirmed',
maxRetries: 5,
),
);
Parameters
The serialized transaction message bytes to sign and send.
The Solana network cluster. Defaults to
SolanaCluster.MainNet.Optional custom RPC URL. If not provided, uses the default RPC for the specified cluster.
Optional configuration for transaction submission.
Show child attributes
Show child attributes
Whether to skip preflight transaction checks. Defaults to
false.Commitment level for preflight checks (e.g.,
"confirmed", "finalized").Maximum number of retry attempts for sending the transaction.
Minimum slot number at which the transaction can be evaluated.
The
cluster, rpcUrl, and sendOptions parameters are only valid for apps using on-device execution.Returns
A Result that, when successful, contains the transaction hash.
Use the
signAndSendTransaction method on the Solana interface to send a transaction with a Solana wallet.Usage
Report incorrect code
Copy
Ask AI
import {
PublicKey,
SystemProgram,
VersionedTransaction,
TransactionMessage,
} from '@solana/web3.js';
const walletPublicKey = new PublicKey(wallet.address);
const instruction = SystemProgram.transfer({
fromPubkey: walletPublicKey,
toPubkey: new PublicKey(recipientAddress),
lamports: amount,
});
const message = new TransactionMessage({
payerKey: walletPublicKey,
instructions: [instruction],
recentBlockhash,
});
const transaction = new VersionedTransaction(message.compileToV0Message());
const {hash} = await privy.wallets().solana().signAndSendTransaction('insert-wallet-id', {
caip2: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // Mainnet
transaction: Buffer.from(transaction.serialize()).toString('base64'),
sponsor: true,
});
Parameters and Returns
Check out the API reference for more details.The
@privy-io/server-auth library is deprecated. We recommend integrating @privy-io/node for
the latest features and support.signAndSendTransaction method on the Solana client to send a transaction with a Solana wallet.Report incorrect code
Copy
Ask AI
signAndSendTransaction: (input: SolanaSignAndSendTransactionInputType) => Promise<SolanaSignAndSendTransactionResponseType>
Usage
Report incorrect code
Copy
Ask AI
import {
PublicKey,
SystemProgram,
VersionedTransaction,
TransactionMessage,
} from '@solana/web3.js';
const walletPublicKey = new PublicKey(wallet.address);
const instruction = SystemProgram.transfer({
fromPubkey: walletPublicKey,
toPubkey: new PublicKey(recipientAddress),
lamports: amount,
});
const message = new TransactionMessage({
payerKey: walletPublicKey,
instructions: [instruction],
recentBlockhash,
});
const transaction = new VersionedTransaction(message.compileToV0Message());
const {hash} = await privy.walletApi.solana.signAndSendTransaction({
walletId: 'insert-wallet-id',
caip2: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // Mainnet
transaction: transaction,
sponsor: true,
});
Parameters
The ID of the wallet to send the transaction from.
The CAIP2 chain ID of the chain the transaction is being sent on.
The transaction to sign and send. This can be either a legacy Transaction or a VersionedTransaction object from @solana/web3.js.
Optional parameter to enable gas sponsorship for this transaction. Learn more.
Returns
The hash for the broadcasted transaction.
The CAIP2 chain ID of the chain the transaction was sent on.
To send a transaction from your wallet, use the
signAndSendTransaction method.
It will sign your transaction, broadcast it to the network, and return the transaction hash to you.Usage
Report incorrect code
Copy
Ask AI
try {
String caip2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"; // Solana Mainnet
// A base64 encoded serialized transaction to sign
String transaction = "insert-base-64-encoded-serialized-transaction";
// Example: If wallet's owner is an authorization private key
AuthorizationContext authorizationContext = AuthorizationContext.builder()
.addAuthorizationPrivateKey("authorization-key")
.build();
SolanaSignAndSendTransactionRpcResponseData response = privyClient.wallets().solana()
.signAndSendTransaction(
walletId,
caip2,
transaction,
authorizationContext,
true // sponsor
);
String transactionHash = response.hash();
} catch (APIException e) {
String errorBody = e.bodyAsString();
System.err.println(errorBody);
} catch (Exception e) {
System.err.println(e.getMessage());
}
Parameters
A base64 encoded serialized transaction to sign.
The CAIP2 chain ID of the chain the transaction is being sent on.
Optional parameter to enable gas sponsorship for this transaction. Learn more.
Returns
TheSolanaSignAndSendTransactionRpcResponseData object contains the following fields:The hash of the broadcasted transaction.
The CAIP2 chain ID of the chain the transaction was sent on.
The transaction ID of the broadcasted transaction.
To send a transaction make a POST request toA successful response will look like the following:
Report incorrect code
Copy
Ask AI
https://api.privy.io/v1/wallets/<wallet_id>/rpc
Usage
Report incorrect code
Copy
Ask AI
$ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
-u "<your-privy-app-id>:<your-privy-app-secret>" \
-H "privy-app-id: <your-privy-app-id>" \
-H "privy-authorization-signature: <authorization-signature-for-request>" \
-H 'Content-Type: application/json' \
-d '{
"method": "signAndSendTransaction",
"caip2": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
"sponsor": true,
"params": {
"transaction": "insert-base-64-encoded-serialized-transaction",
"encoding": "base64"
}
}'
Report incorrect code
Copy
Ask AI
{
"method": "signAndSendTransaction",
"data": {
"hash": "insert-transaction-hash",
"caip2": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
}
}
Parameters
The RPC method executed with the wallet.
The CAIP2 chain ID to broadcast the transaction on.
Optional parameter to enable gas sponsorship for this transaction. Learn more.
Returns
The RPC method executed with the wallet.
The hash for the broadcasted transaction.
The CAIP2 chain ID the transaction was submitted on.
Use the For transaction construction, use the
sign_and_send_transaction method on the Solana service to sign and broadcast a transaction. Use the solana_sdk crate to construct your transactions.Usage
Report incorrect code
Copy
Ask AI
use privy_rs::{AuthorizationContext, PrivyClient};
use solana_sdk::{pubkey::Pubkey, transaction::Transaction};
use base64::{engine::general_purpose::STANDARD, Engine};
use std::str::FromStr;
let client = PrivyClient::new("app_id".to_string(), "app_secret".to_string())?;
let solana_service = client.wallets().solana();
let auth_ctx = AuthorizationContext::new();
// Build transaction using solana_sdk and solana_system_interface
let from_pubkey = Pubkey::from_str("DTeASnDsQ1z9Le77MjuiPH4MyqLDWa9vB6R3ZZKRd8d3")?;
let to_pubkey = Pubkey::from_str("9NvE68JVWHHHGLp5NNELtM5fiBw6SXHrzqQJjUqaykC1")?;
let lamports = 1000000; // 0.001 SOL
let transaction = Transaction::new_with_payer(
&[solana_system_interface::instruction::transfer(
&from_pubkey,
&to_pubkey,
lamports,
)],
Some(&from_pubkey),
);
// Serialize and encode transaction as base64
let serialized_transaction = STANDARD.encode(bincode::serialize(&transaction)?);
let result = solana_service.sign_and_send_transaction(
&wallet_id,
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana devnet
&serialized_transaction,
&auth_ctx,
Some(true) // sponsor
).await?;
println!("Transaction sent successfully");
solana_sdk crate for core transaction types and the solana_system_interface crate for system instructions like transfers.Parameters and Returns
See the Rust SDK documentation for detailed parameter and return types, including embedded examples:- SolanaService::sign_and_send_transaction
- solana_sdk crate documentation
- solana_system_interface crate documentation
For complete examples of sending SOL and SPL tokens using Privy’s SDKs, check out the sending a
SOL transaction recipe and the sending SPL tokens
recipe.

