Overview

This guide covers the fundamentals of signing and sending transactions on Solana using the CDP v2 Wallet API. You will learn how to construct transactions, sign them with CDP-managed keys, and submit them to the Solana network.

With CDP, signing keys are securely managed in the platform’s infrastructure. While EVM transactions benefit from a single API that supports signing and broadcasting, Solana requires explicit handling of the transaction lifecycle:

  1. Create transaction: Build a transaction with one or more instructions
  2. Set recent blockhash: Add a recent blockhash for transaction expiry
  3. Sign transaction: Use CDP to sign the serialized transaction
  4. Send transaction: Submit the signed transaction to the network
  5. Confirm transaction: Wait for network confirmation

Prerequisites

It is assumed you have:

  • Completed the Quickstart guide
  • Basic understanding of Solana accounts
  • Installed dependencies:
    • For TypeScript: @solana/web3.js, @coinbase/cdp-sdk, and dotenv
    • For Python: solana, solders, cdp-sdk, and python-dotenv

The following steps break down the transaction flow into digestible pieces. If you prefer to see the full working code immediately, skip to the Complete example section below.

1. Create a Solana account

First, create or retrieve a Solana account using CDP. The below example uses solana-devnet and will source SOL from CDP faucet to transfer.

import { CdpClient } from "@coinbase/cdp-sdk";
import "dotenv/config";

const cdp = new CdpClient();

const account = await cdp.solana.createAccount({
  name: "test-sol-account",
});

let fromAddress: string;
fromAddress = account.address;
console.log("Successfully created new SOL account:", fromAddress);

// Request SOL from faucet
const faucetResp = await cdp.solana.requestFaucet({
  address: fromAddress,
  token: "sol",
});
console.log(
  "Successfully requested SOL from faucet:",
  faucetResp.signature
);

2. Build the transaction

Prepare a transaction with one or more instructions. Here is a simple SOL transfer (note that we fetch the latest blockhash from the network, which is required for transaction expiry):

import { Connection, PublicKey, SystemProgram, Transaction } from "@solana/web3.js";

const connection = new Connection("https://api.devnet.solana.com");

// Required: Destination address to send SOL to (replace with your recipient)
const destinationAddress = "3KzDtddx4i53FBkvCzuDmRbaMozTZoJBb1TToWhz3JfE";

// Amount of lamports to send (default: 1000 = 0.000001 SOL)
const lamportsToSend = 1000;

// Assumes fromAddress is defined from step 1
let fromAddress: string; // Your Solana account address

const { blockhash } = await connection.getLatestBlockhash();

const transaction = new Transaction();
transaction.add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(fromAddress),
    toPubkey: new PublicKey(destinationAddress),
    lamports: lamportsToSend,
  })
);

3. Set blockhash and serialize

Add a recent blockhash and serialize the transaction for signing:

transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(fromAddress);

const serializedTx = Buffer.from(
  transaction.serialize({ requireAllSignatures: false })
).toString("base64");

console.log("Transaction serialized successfully");

4. Sign the transaction

Use CDP to sign the serialized transaction:

import { CdpClient } from "@coinbase/cdp-sdk";

// Assumes cdp client is initialized from step 1
const cdp = new CdpClient();

const signedTxResponse = await cdp.solana.signTransaction({
  address: fromAddress,
  transaction: serializedTx,
});

const decodedSignedTx = Buffer.from(signedTxResponse.signature, "base64");

5. Send and confirm

Submit the signed transaction to the network and wait for confirmation:

const signature = await connection.sendRawTransaction(decodedSignedTx);
console.log("Solana transaction hash:", signature);

console.log("Waiting for transaction to be confirmed");
const latestBlockhash = await connection.getLatestBlockhash();
const confirmation = await connection.confirmTransaction({
  signature,
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
});

if (confirmation.value.err) {
  throw new Error(
    `Transaction failed: ${confirmation.value.err.toString()}`
  );
}

console.log(
  "Transaction confirmed:",
  confirmation.value.err ? "failed" : "success"
);
console.log(
  `Transaction explorer link: https://explorer.solana.com/tx/${signature}?cluster=devnet`
);

Complete example

More code samples are available in our TypeScript and Python SDK repositories.