Overview

This guide shows you how to sign Solana transactions using Dynamic’s Node SDK. You’ll learn how to create, sign, and send Solana transactions.

Prerequisites

Step 1: Install Dependencies

bun add @solana/web3.js

Step 2: Create and Sign a Transaction

The approach for signing transactions depends on how you created your wallet: If you created your wallet with backUpToClientShareService: true, you can sign directly without retrieving key shares:
import { DynamicSvmWalletClient } from '@dynamic-labs-wallet/node-svm';
import { Connection, PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';

// Create authenticated client
export const authenticatedSvmClient = async () => {
  const client = new DynamicSvmWalletClient({
    authToken: process.env.DYNAMIC_AUTH_TOKEN!,
    environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
  });

  await client.authenticateApiToken(process.env.DYNAMIC_AUTH_TOKEN!);
  return client;
};

const svmClient = await authenticatedSvmClient();

// Create a simple SOL transfer transaction
const fromPubkey = new PublicKey('YourSolanaWalletAddress');
const toPubkey = new PublicKey('11111111111111111111111111111112');
const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey,
    toPubkey,
    lamports: LAMPORTS_PER_SOL * 0.001, // 0.001 SOL
  })
);

// ✅ Simple signing - no externalServerKeyShares needed
const signedTransaction = await svmClient.signTransaction({
  senderAddress: 'YourSolanaWalletAddress',
  transaction: transaction,
});

console.log('Transaction signed successfully');

With Manual Backup

If you created your wallet with backUpToClientShareService: false, you must retrieve and provide external key shares:
// ⚠️ First, get external server key shares (required for manual backup)
const keyShares = await svmClient.getExternalServerKeyShares({
  accountAddress: 'YourSolanaWalletAddress',
});

// Or retrieve your stored encrypted key shares
// const keyShares = await retrieveStoredKeyShares('YourSolanaWalletAddress');

console.log('Key shares retrieved:', keyShares.length);

// Sign the transaction with external key shares
const signedTransaction = await svmClient.signTransaction({
  senderAddress: 'YourSolanaWalletAddress',
  externalServerKeyShares: keyShares, // Required for manual backup!
  transaction: transaction,
  password: 'your-password', // Only if wallet was created with password
});

console.log('Transaction signed successfully');
Password Handling Notes:
  • If your wallet was created without a password, omit the password parameter
  • If your wallet was created with a password, you must provide it for all operations
  • The password parameter is always optional in the API, but required if the wallet is password-protected

Step 3: Send the Transaction

import { Connection, sendAndConfirmTransaction } from '@solana/web3.js';

const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
const txHash = await sendAndConfirmTransaction(connection, signedTransaction);
console.log('Transaction hash:', txHash);

Complete Example: Send SOL

export const sendSol = async ({
  fromAddress,
  toAddress,
  amount,
}: {
  fromAddress: string;
  toAddress: string;
  amount: number; // Amount in SOL
}) => {
  const svmClient = await authenticatedSvmClient();

  // Create transaction
  const fromPubkey = new PublicKey(fromAddress);
  const toPubkey = new PublicKey(toAddress);
  const transaction = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey,
      toPubkey,
      lamports: LAMPORTS_PER_SOL * amount,
    })
  );

  // Sign transaction
  // Note: If using manual backup (backUpToClientShareService: false),
  // you'll need to provide externalServerKeyShares here
  const signedTransaction = await svmClient.signTransaction({
    senderAddress: fromAddress,
    transaction,
  });

  // Send transaction
  const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
  const txHash = await sendAndConfirmTransaction(connection, signedTransaction);

  return txHash;
};

// Usage
const txHash = await sendSol({
  fromAddress: 'YourSolanaWalletAddress',
  toAddress: 'RecipientAddress',
  amount: 0.001,
});

console.log('SOL sent:', txHash);

Common Transaction Types

SOL Transfer

const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey('YourAddress'),
    toPubkey: new PublicKey('RecipientAddress'),
    lamports: LAMPORTS_PER_SOL * 0.1,
  })
);

SPL Token Transfer

import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';

const transaction = new Transaction().add(
  Token.createTransferInstruction(
    TOKEN_PROGRAM_ID,
    fromTokenAccount,
    toTokenAccount,
    fromPubkey,
    [],
    amount
  )
);

Next Steps