Appearance
Using Solana wallets
Getting the address
Once a user has created their embedded Solana wallet, you can get the user's address by inspecting the publicKey
field of the wallet
interface returned by useEmbeddedSolanaWallet
:
tsx
// This assumes you have already created a Solana wallet for the user
const wallet = useEmbeddedSolanaWallet();
console.log(wallet.publicKey);
// 4tFqt2qzaNsnZqcpjPiyqYw9LdRzxaZdX2ewPncYEWLA
Getting a wallet provider
To send signature and transaction requests to a user's Solana wallet, you must first get a provider instance for their wallet. This serves as a standardized abstraction to communicate requests from your app to the user's wallet.
To get a provider for the user's Solana wallet, call the getProvider
method on the wallet
interface returned by useEmbeddedSolanaWallet
:
tsx
// This assumes you have already created a Solana wallet for the user
const wallet = useEmbeddedSolanaWallet();
const provider = await wallet.getProvider();
The returned provider
implements a method called request
that allows your app to send arbitrary signature requests to the wallet. As a parameter to request
, you should pass an object with the following fields:
Field | Type | Description |
---|---|---|
method | 'signMessage' | The JSON-RPC method for the Solana wallet to execute. Currently, only 'signMessage' is supported as a method . |
params | any | The parameters that the wallet should use to execute the method . |
INFO
Privy's provider interface for the embedded Solana wallet is designed to have the same shape as Phantom's widely used PhantomProvider
. As Privy expands Solana functionality, our Solana provider will over time support the full set of methods as the PhantomProvider
.
Requesting a signature
To request a signature from a user's Solana wallet, first get a provider instance for the wallet:
tsx
// This assumes you have already created a Solana wallet for the user
const wallet = useEmbeddedSolanaWallet();
const provider = await wallet.getProvider();
Then, using the provider's request
method, send a request to the wallet with following fields in the request object:
method
:'signMessage'
params
: a JSON object containing amessage
to be signed.- If the message is a
string
, you should pass thestring
as themessage
directly. - If the message is an array of bytes (
Uint8Array
), you should base64-encode the array as astring
before passing it tomessage
.
- If the message is a
As an example, you might request a signature from a user's Solana wallet like so:
tsx
const message = 'Hello world';
const {signature} = await provider.request({
method: 'signMessage',
params: {
message: message,
},
});
The request will then return an object containing an Ed25519 signature
over the message
, as a base64-encoded string
. You can verify the signature as follows:
tsx
import bs58 from 'bs58';
import {Buffer} from 'buffer';
import nacl from 'tweetnacl';
// This assumes the `message` was originally a string
const result = nacl.sign.detached.verify(
Buffer.from(message, 'base64'),
Buffer.from(signature, 'base64'),
bs58.decode(solanaWallet.publicKey),
);
Sending a transaction
In addition to signing messages, you can use Privy embedded wallets to sign and send transactions on the Solana blockchain.
At a high-level, this involves preparing and serializing your Solana transaction, requesting a signature from the Privy embedded wallet, and submitting your signed transaction to the network.
As an example, you can send a transaction on Solana with Privy embedded wallets like so:
tsx
import {PublicKey, Transaction, Connection, SystemProgram} from '@solana/web3.js';
import {useEmbeddedSolanaWallet} from '@privy-io/expo';
...
// The rest of this code must be placed within a React component
// Get Solana wallet
const solanaWallet = useEmbeddedSolanaWallet();
if (solanaWallet.status !== 'connected') return;
// The `transaction` below is a legacy `Transaction` object from `@solana/web3.js`
// https://solana-labs.github.io/solana-web3.js/classes/Transaction.html
const serializedTransaction = transaction.serializeMessage();
// Sign the serialized transaction using Privy's signMessage
const provider = await solanaWallet.getProvider();
const {signature} = await provider.request({
method: "signMessage",
params: {
// Base64-encode serialized transaction before passing to Privy
message: serializedTransaction.toString('base64'),
},
});
// Add the signature to the transaction. Make sure to base64 decode the signature.
transaction.addSignature(sender, Buffer.from(signature, 'base64'));
if (!transaction.verifySignatures()) {
throw new Error('Invalid signature.');
}
// Serialize the transaction again with the signature, and send it to the network
const signedTransaction = transaction.serialize();
const txHash = await connection.sendRawTransaction(signedTransaction);
await connection.confirmTransaction(txHash);
TIP
Privy is building out a more native interface for sending Solana transactions. In the interim, we recommend using the flow above to sign Solana transactions and send them using @solana/web3.js
.