Skip to content

Hierarchical deterministic (HD) wallets

Privy's Solana embedded wallets are hierarchical deterministic (HD) wallets. An HD wallet allows you to generate multiple Solana addresses and private keys from a shared source of entropy: the wallet seed (or equivalently, a BIP-39 mnemonic encoding the seed, known as a seed phrase).

In kind, Privy can be used to provision multiple Solana embedded wallets for a single user. Read more below to learn how!

Read more about how HD wallets work.

HD wallets use a shared source of entropy to derive the wallet seed; this entropy is protected by the Privy cryptosystem.

Each wallet is generated from the seed and a unique path parameter, which has the format:

m / purpose' / coin_type' / account' / change / address_index

For Privy's Solana embedded wallets, the path used for the i-th wallet is:

m/44'/501'/i/0'

where i is 0-indexed. An HD wallet is said to have an index of i if it is derived from the i-th path above. You can read more about these derivation paths here.

Creating multiple HD wallets

To create multiple Solana wallets for a user, use the create method from the useEmbeddedSolanaWallet hook:

tsx
import {useEmbeddedSolanaWallet} from '@privy-io/expo';
...
const {create} = useEmbeddedSolanaWallet();

As an optional parameter to create, you may pass an object containing the following fields:

PropTypeDescription
createAdditionalbooleanIf true, will allow the user to create a Solana wallet regardless if it is their first Solana wallet or an additional Solana wallet. If false, createWallet will succeed only if the use is creating their first wallet. Defaults to false.

Once invoked, create will return a Promise that resolves to the provider for the wallet created for the user, if it was successful. This method will reject with an error if:

  • the user is not authenticated
  • the user already has an embedded Solana wallet and createAdditional was not set to true
  • if there is another error during wallet creation, such as the user exiting prematurely

Creating the user's first wallet

If this is the first wallet you are creating for the user (e.g. the 0th index), you may call create with no parameters:

tsx
// Creating the first wallet for a user
const provider = await create();

Creating additional wallets

If the user already has an embedded wallet, and you are creating an additional embedded wallet, you must call create with createAdditional set to true:

tsx
// Creating additional embedded wallets for the user
// You can also create the first wallet for the user using this syntax
const provider = await create({createAdditional: true});

Using multiple HD wallets

Once a user has one or more embedded wallets, the wallets are added to the wallets array returned by useEmbeddedSolanaWallet:

tsx
import {useEmbeddedSolanaWallet} from '@privy-io/expo';
...
const {wallets} = useEmbeddedSolanaWallet();

Each entry in the wallets array is an object with the following fields:

FieldTypeDescription
addressstringThe address (base58-encoded public key) for the wallet.
publicKeystringThe address (base58-encoded public key) for the wallet.
walletIndexnumberThe HD index for the wallet.
getProvider() => Promise<PrivyEmbeddedSolanaWalletProvider>Method to get a provider for the wallet for requesting signatures and transactions.

Getting a specific embedded wallet

To find a specific embedded wallet for the user, search the wallets array for a wallet with the address that matches your desired address:

tsx
const desiredAddress = 'insert-your-desired-wallet-address';
const {wallets} = useEmbeddedSolanaWallet();
const desiredWallet = wallets.find((wallet) => wallet.address === desiredAddress);

You can alternatively search the wallets array by your desired HD index:

tsx
// Replace this with your desired HD index
const desiredHdIndex = 0;
const {wallets} = useEmbeddedSolanaWallet();
const desiredWallet = wallets.find((wallet) => wallet.walletIndex === desiredHdIndex);

Requesting signatures and transactions

To request a signature or transaction from a specific embedded wallet, first find the corresponding wallet object from the wallets array:

tsx
const desiredAddress = 'insert-your-desired-wallet-address';
const {wallets} = useEmbeddedSolanaWallet();
const wallet = wallets.find((wallet) => wallet.address === desiredAddress);

Then, call the object's getProvider method to get a provider for the wallet:

tsx
const provider = await wallet.getProvider();

You can then easily request signatures from the provider using its request method, like so:

tsx
const message = 'Hello world';
const {signature} = await provider.request({
  method: 'signMessage',
  params: {
    message: message,
  },
});