Skip to main content
The CDP SDK provides flexible methods for sending transactions on both EVM and Solana networks. You can send pre-built transactions, construct custom transactions, or use high-level convenience methods.

EVM Transactions

Sending with EIP-1559 Parameters

Send a transaction with automatic gas estimation:
import { CdpClient } from "@coinbase/cdp-sdk";

const cdp = new CdpClient();
const account = await cdp.evm.getOrCreateAccount({ name: "Sender" });

const txHash = await account.sendTransaction({
  transaction: {
    to: "0x1234567890123456789012345678901234567890",
    value: 1000000000000000n, // 0.001 ETH
    data: "0x" // Empty for simple ETH transfer
  },
  network: "base-sepolia"
});

console.log(`Transaction hash: ${txHash}`);
When you omit gas, maxFeePerGas, and maxPriorityFeePerGas, CDP automatically estimates these values based on current network conditions.

Contract Interactions

Call a smart contract function:
import { encodeFunctionData, erc20Abi } from "viem";

// Encode an ERC-20 transfer
const data = encodeFunctionData({
  abi: erc20Abi,
  functionName: "transfer",
  args: [
    "0xRecipientAddress...",
    1000000n // 1 USDC (6 decimals)
  ]
});

const txHash = await account.sendTransaction({
  transaction: {
    to: "0xUSDCContractAddress...",
    value: 0n,
    data: data
  },
  network: "base-sepolia"
});

Manual Gas Parameters

Specify gas parameters manually for more control:
const txHash = await account.sendTransaction({
  transaction: {
    to: "0x1234...",
    value: 1000000000000000n,
    data: "0x",
    gas: 21000n,
    maxFeePerGas: 2000000000n, // 2 gwei
    maxPriorityFeePerGas: 1000000000n // 1 gwei
  },
  network: "base-sepolia"
});

Sending RLP-Encoded Transactions

Send a pre-signed, RLP-encoded transaction:
const txHash = await account.sendTransaction({
  transaction: "0x02f8...", // RLP-encoded transaction hex
  network: "base-sepolia"
});

Idempotent Transactions

Use idempotency keys to safely retry failed requests:
const txHash = await account.sendTransaction({
  transaction: {
    to: "0x1234...",
    value: 1000000000000000n,
    data: "0x"
  },
  network: "base-sepolia",
  idempotencyKey: "tx-unique-id-123"
});

Solana Transactions

Signing and Sending Transactions

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

const cdp = new CdpClient();
const account = await cdp.solana.getOrCreateAccount({ 
  name: "SolanaSender" 
});

// Sign a base64-encoded Solana transaction
const signedTx = await account.signTransaction({
  transaction: "base64-encoded-transaction",
  idempotencyKey: "tx-sol-123"
});

console.log(`Signed transaction: ${signedTx.signedTransaction}`);

Building Solana Transactions

Build a Solana transaction using Solana libraries:
import { 
  Connection, 
  Transaction, 
  SystemProgram,
  PublicKey 
} from "@solana/web3.js";

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

// Create a transfer transaction
const tx = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(account.address),
    toPubkey: new PublicKey("DestinationAddress..."),
    lamports: 1000000 // 0.001 SOL
  })
);

// Get recent blockhash
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.feePayer = new PublicKey(account.address);

// Serialize and encode
const serialized = tx.serialize({ requireAllSignatures: false });
const base64Tx = serialized.toString("base64");

// Sign with CDP
const signed = await account.signTransaction({
  transaction: base64Tx
});

Batch Transactions (Smart Accounts Only)

Smart accounts can execute multiple operations atomically:
import { encodeFunctionData, erc20Abi } from "viem";

const owner = await cdp.evm.createAccount();
const smartAccount = await cdp.evm.createSmartAccount({ owner });

const userOp = await smartAccount.sendUserOperation({
  calls: [
    {
      to: "0xTokenA...",
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "approve",
        args: ["0xSpender...", 1000000n]
      })
    },
    {
      to: "0xTokenB...",
      value: 0n,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "approve",
        args: ["0xSpender...", 2000000n]
      })
    }
  ],
  network: "base-sepolia"
});

console.log(`Batch user operation: ${userOp.userOpHash}`);

Waiting for Transaction Confirmation

EVM Transactions

Use a library like Viem or Web3.py to wait for confirmation:
import { createPublicClient, http } from "viem";
import { baseSepolia } from "viem/chains";

const publicClient = createPublicClient({
  chain: baseSepolia,
  transport: http()
});

const txHash = await account.sendTransaction({
  transaction: {
    to: "0x1234...",
    value: 1000000000000000n,
    data: "0x"
  },
  network: "base-sepolia"
});

console.log("Waiting for confirmation...");
const receipt = await publicClient.waitForTransactionReceipt({
  hash: txHash
});

console.log(`Status: ${receipt.status}`);
console.log(`Block: ${receipt.blockNumber}`);
console.log(`Gas used: ${receipt.gasUsed}`);

Smart Account User Operations

const userOp = await smartAccount.sendUserOperation({
  calls: [{ to: "0x1234...", value: 0n, data: "0x" }],
  network: "base-sepolia"
});

const confirmed = await smartAccount.waitForUserOperation(
  userOp.userOpHash,
  { timeoutSeconds: 30 }
);

console.log(`User op status: ${confirmed.status}`);
console.log(`Transaction hash: ${confirmed.transactionHash}`);

Transaction Fields Reference

EIP-1559 Transaction Fields

to
string
required
Destination address (20-byte hex string with 0x prefix)
value
bigint | number
default:"0"
Amount of ETH to send in wei
data
string
default:"0x"
Contract call data (hex string with 0x prefix)
gas
bigint | number
Gas limit (estimated by CDP if not provided)
maxFeePerGas
bigint | number
Maximum fee per gas unit (estimated by CDP if not provided)
maxPriorityFeePerGas
bigint | number
Maximum priority fee per gas unit (estimated by CDP if not provided)
nonce
number
Transaction nonce (managed by CDP if not provided)

Troubleshooting

Transaction Reverted

If a transaction reverts:
  1. Check the revert reason in the transaction receipt
  2. Verify contract function parameters are correct
  3. Ensure the account has sufficient token balances
  4. Confirm gas limits are adequate for complex operations

Insufficient Funds for Gas

Ensure the account has ETH/SOL for transaction fees:
// Request testnet tokens
await cdp.evm.requestFaucet({
  address: account.address,
  network: "base-sepolia",
  token: "eth"
});

Nonce Too Low/High

Let CDP manage nonces automatically by omitting the nonce field. If you manage nonces manually, track them carefully.

Transaction Stuck

For EVM transactions stuck in the mempool:
  • Increase maxFeePerGas and maxPriorityFeePerGas
  • Send a replacement transaction with the same nonce but higher gas price
  • Wait for network congestion to clear

Next Steps

Build docs developers (and LLMs) love