How to sign messages and send transactions on Solana

If you’re not using React, use the @account-kit/signer package to create smart wallets on Solana, sign messages, sign transactions, and sponsor transaction fees.

If you’re using React, get started with Solana wallets here.

Create a Solana signer

Once you’ve authenticated users, convert the AlchemyWebSigner to a Solana compatible signer using either of these methods:

import { 
import signer
signer
} from "./signer";
import {
class SolanaSigner

The SolanaSigner class is used to sign transactions and messages for the Solana blockchain. It provides methods to add signatures to transactions and sign messages.

SolanaSigner
} from "@account-kit/signer";
const
const solanaSigner: any
solanaSigner
=
import signer
signer
.
any
toSolanaSigner
();
// OR const
const solanaSigner2: SolanaSigner
solanaSigner2
= new
new SolanaSigner(client: BaseSignerClient): SolanaSigner

Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3

SolanaSigner
(
import signer
signer
);
import { 
class AlchemyWebSigner

A SmartAccountSigner that can be used with any SmartContractAccount

AlchemyWebSigner
} from "@account-kit/signer";
export const
const signer: AlchemyWebSigner
signer
= new
new AlchemyWebSigner(params: AlchemySignerParams): AlchemyWebSigner

Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.

AlchemyWebSigner
({
client: ({ connection: { apiKey: string; rpcUrl?: undefined; jwt?: undefined; } | { jwt: string; rpcUrl?: undefined; apiKey?: undefined; } | { rpcUrl: string; apiKey?: undefined; jwt?: undefined; } | { rpcUrl: string; jwt: string; apiKey?: undefined; }; ... 4 more ...; enablePopupOauth?: boolean | undefined; } | AlchemySignerWebClient) & (AlchemySignerWebClient | ... 1 more ... | undefined)
client
: {
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "API_KEY",
},
iframeConfig: { iframeContainerId: string; }
iframeConfig
: {
iframeContainerId: string
iframeContainerId
: "alchemy-signer-iframe-container",
}, }, });

Sign Message

To sign either a string or byte array with your Solana wallet use the signMessage method. The method accepts a UInt8Array as input:

import { 
import signer
signer
} from "./signer";
import {
function toBytes(value: string | bigint | number | boolean | Hex, opts?: ToBytesParameters): ByteArray

Encodes a UTF-8 string, hex value, bigint, number or boolean to a byte array.

Docs: https://viem.sh/docs/utilities/toBytes Example: https://viem.sh/docs/utilities/toBytes#usage

toBytes
} from "viem";
const
const solanaSigner: any
solanaSigner
=
import signer
signer
.
any
toSolanaSigner
();
const
const signedMessage: any
signedMessage
= await
const solanaSigner: any
solanaSigner
.
any
signMessage
(
function toBytes(value: string | bigint | number | boolean | Hex, opts?: ToBytesParameters): ByteArray

Encodes a UTF-8 string, hex value, bigint, number or boolean to a byte array.

Docs: https://viem.sh/docs/utilities/toBytes Example: https://viem.sh/docs/utilities/toBytes#usage

toBytes
("Message as a string converted into UInt8Array"),
);
import { 
class AlchemyWebSigner

A SmartAccountSigner that can be used with any SmartContractAccount

AlchemyWebSigner
} from "@account-kit/signer";
export const
const signer: AlchemyWebSigner
signer
= new
new AlchemyWebSigner(params: AlchemySignerParams): AlchemyWebSigner

Initializes an instance with the provided Alchemy signer parameters after parsing them with a schema.

AlchemyWebSigner
({
client: ({ connection: { apiKey: string; rpcUrl?: undefined; jwt?: undefined; } | { jwt: string; rpcUrl?: undefined; apiKey?: undefined; } | { rpcUrl: string; apiKey?: undefined; jwt?: undefined; } | { rpcUrl: string; jwt: string; apiKey?: undefined; }; ... 4 more ...; enablePopupOauth?: boolean | undefined; } | AlchemySignerWebClient) & (AlchemySignerWebClient | ... 1 more ... | undefined)
client
: {
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "API_KEY",
},
iframeConfig: { iframeContainerId: string; }
iframeConfig
: {
iframeContainerId: string
iframeContainerId
: "alchemy-signer-iframe-container",
}, }, });

Sign Transaction

To sign a prepared transaction with your Solana wallet use the addSignature method. The following example demonstrates signing a transfer transaction:

signing-transaction-solana-signer.tsx
1import { Connection, PublicKey, SystemProgram } from "@solana/web3.js";
2
3async function signTransaction(
4 signer: SolanaSigner,
5 toAddress: string,
6 value: number,
7) {
8 const instructions = [
9 SystemProgram.transfer({
10 fromPubkey: new PublicKey(signer.address),
11 toPubkey: new PublicKey(params.transfer.toAddress),
12 lamports: params.transfer.amount,
13 }),
14 ];
15
16 // Construct transaction with the provided instructions
17 const transaction = await signer.createTransfer(instructions, connection);
18
19 // Sign the transaction using the Solana wallet
20 await signer.addSignature(transaction);
21
22 return transaction;
23}
24
25const signedTransaction = await signTransaction(signer, "<ToAddress>", 1234);
26// Broadcast the signed transaction to the network using @solana/web3.js
27const connection = new Connection(
28 "https://solana-devnet.g.alchemy.com/v2/<API_KEY>",
29);
30await connection.sendTransaction(signedTransaction);

Sponsor transaction fees

To sponsor transaction fees on Solana:

  1. Set up your sponsorship policy in the dashboard to retrieve a policy ID
  2. Add sponsorship to the preparred transaction before signing and sending
sponsored-solana-transaction-signer.tsx
1import { Connection, PublicKey, SystemProgram } from "@solana/web3.js";
2
3async function signTransaction(
4 signer: SolanaSigner,
5 toAddress: string,
6 value: number,
7) {
8 const instructions = [
9 SystemProgram.transfer({
10 fromPubkey: new PublicKey(signer.address),
11 toPubkey: new PublicKey(params.transfer.toAddress),
12 lamports: params.transfer.amount,
13 }),
14 ];
15
16 // First - add sponsorship to the preparred transaction
17 const transaction = await signer.addSponsorship(
18 instructions,
19 connection,
20 "<policyId>", // Replace with your solana sponsorship policy ID: https://dashboard.alchemy.com/services/gas-manager/configuration
21 );
22
23 // Sign the transaction using the Solana wallet
24 await signer.addSignature(transaction);
25
26 return transaction;
27}
28
29const signedTransaction = await signTransaction(signer, "<ToAddress>", 1234);
30
31// Broadcast the signed transaction to the network using @solana/web3.js
32const connection = new Connection(
33 "https://solana-devnet.g.alchemy.com/v2/<API_KEY>", // Replace with your Alchemy API key
34);
35
36await connection.sendTransaction(signedTransaction);