Overview

A Solana transaction is a list of instructions that are executed in order. This allows developers to batch multiple instructions into a single transaction, reducing the number of transactions required to complete a complex multi-step process.

Prerequisites

It is assumed you have already completed the Quickstart guide.

Create and send transaction with multiple instructions

In this example, we will:

  • Create a Solana account
  • Construct multiple instructions to be executed in the transaction
  • Sign the transaction with the Solana account
  • Send the transaction to the Solana network
import {
  Connection,
  PublicKey,
  SystemProgram,
  Transaction,
} from "@solana/web3.js";
import { CdpClient } from "@coinbase/cdp-sdk";
import dotenv from "dotenv";

dotenv.config();

const cdp = new CdpClient();

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

async function createAccount() {
  const account = await cdp.solana.createAccount();
  console.log(`Created account: ${account.address}`);
  return account;
}

async function requestFaucet(address: string) {
  await cdp.solana.requestFaucet({
    address,
    token: "sol",
  });
}

async function waitForBalance(address: string) {
  let balance = 0;
  let attempts = 0;
  const maxAttempts = 30;

  while (balance === 0 && attempts < maxAttempts) {
    balance = await connection.getBalance(new PublicKey(address));
    if (balance === 0) {
      console.log("Waiting for funds...");
      await new Promise(resolve => setTimeout(resolve, 1000));
      attempts++;
    } else {
      console.log("Account funded with", balance / 1e9, "SOL");
    }
  }

  if (balance === 0) {
    throw new Error("Account not funded after multiple attempts");
  }
}

async function sendTransaction(address: string) {
  // Amount of lamports to send (default: 1000 = 0.000001 SOL)
  const lamportsToSend = 1000;
  const fromAddress = new PublicKey(address)
  const destinations = [
    "ANVUJaJoVaJZELtV2AvRp7V5qPV1B84o29zAwDhPj1c2",
    "EeVPcnRE1mhcY85wAh3uPJG1uFiTNya9dCJjNUPABXzo",
    "4PkiqJkUvxr9P8C1UsMqGN8NJsUcep9GahDRLfmeu8UK",
  ]

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

  // Create instructions for each destination
  const instructions = destinations.map((toAddress) => {
    return SystemProgram.transfer({
      fromPubkey: fromAddress,
      toPubkey: new PublicKey(toAddress),
      lamports: lamportsToSend,
    })
  })

  // Create a single transaction with all instructions
  const transaction = new Transaction();
  transaction.add(...instructions);

  transaction.recentBlockhash = blockhash;
  transaction.feePayer = fromAddress;

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

  const { signature: txSignature } = await cdp.solana.signTransaction({
    address,
    transaction: serializedTx,
  });
  const decodedSignedTx = Buffer.from(txSignature, "base64");

  console.log("Sending transaction...");
  const txSendSignature = await connection.sendRawTransaction(decodedSignedTx);

  const latestBlockhash = await connection.getLatestBlockhash();

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

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

  console.log(`Sent SOL: https://explorer.solana.com/tx/${txSendSignature}?cluster=devnet`);
}

async function main() {
  const account = await createAccount();
  await requestFaucet(account.address);
  await waitForBalance(account.address);
  await sendTransaction(account.address);
}

main().catch(console.error)

After running the above snippet, you should see output similar to the following:

Created account: Af8cVHK2DZXcT4WhK6VDZ3h2zFxbEfgamsRkrB7dUcfF
Waiting for funds...
Account funded with 0.00125 SOL (1250000 lamports)
Sending transaction...
Waiting for transaction to be confirmed...
Sent SOL: https://explorer.solana.com/tx/56oRrY2nHSbncysmrW6vtBaUoyvWnRrMqN1joGNzaY3TNmPSTM653skDjbj2jDEdMA4QqFo9c4GY4hTnRhScgJk5?cluster=devnet