> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cdp.coinbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send Transactions

CDP Wallets provide a `sendTransaction` feature that simplifies sending onchain transactions.
For EVM, it handles **gas estimation**, **nonce management**, **signing**, and **broadcasting** automatically.
For Solana, it handles **signing** and **broadcasting**, and sets the required **priority fees** for optimal transaction pricing.

## EVM

<Tip>
  `sendTransaction` is supported on Base, Ethereum, Avalanche, Polygon, Optimism, and Arbitrum. For other chains, use the sign transaction feature.
</Tip>

<Tabs>
  <Tab title="React">
    After the user logs in, use `useSendEvmTransaction` from `cdp-hooks` to send EVM transactions from the user's wallet.

    ```tsx theme={null}
    import { useSendEvmTransaction, useEvmAddress } from "@coinbase/cdp-hooks";

    function SendTransaction() {
      const { sendEvmTransaction } = useSendEvmTransaction();
      const { evmAddress } = useEvmAddress();

      const handleSend = async () => {
        if (!evmAddress) return;
        const result = await sendEvmTransaction({
          transaction: {
            to: evmAddress,
            value: 1000000000000n,  // 0.000001 ETH in wei
            gas: 21000n,
            chainId: 84532,         // Base Sepolia
            type: "eip1559",
          },
          evmAccount: evmAddress,
          network: "base-sepolia",
        });
        console.log("Transaction hash:", result.transactionHash);
      };

      return <button onClick={handleSend}>Send Transaction</button>;
    }
    ```
  </Tab>

  <Tab title="Node (TypeScript)">
    ```typescript theme={null}
    import { parseEther } from "viem";

    const result = await cdp.evm.sendTransaction({
      address: account.address,
      network: "base-sepolia",
      transaction: {
        to: "0x4252e0c9A3da5A2700e7d91cb50aEf522D0C6Fe8",
        value: parseEther("0.001"),
      },
    });
    console.log("Transaction hash:", result.transactionHash);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from cdp.evm_transaction_types import TransactionRequestEIP1559
    from web3 import Web3

    tx_hash = await cdp.evm.send_transaction(
        address=account.address,
        transaction=TransactionRequestEIP1559(
            to="0x4252e0c9A3da5A2700e7d91cb50aEf522D0C6Fe8",
            value=Web3.to_wei(0.001, "ether"),
        ),
        network="base-sepolia",
    )
    print(f"Transaction hash: {tx_hash}")
    ```
  </Tab>
</Tabs>

### Network-scoped accounts

Use `useNetwork()` to scope an account to a specific network once, avoiding the need to pass `network` on every call. When scoped to Base or Base Sepolia, the SDK automatically uses CDP's managed RPC endpoints.

```typescript Node (TypeScript) theme={null}
// Without useNetwork — network required on every call
await cdp.evm.sendTransaction({ address, network: "base", transaction: { ... } });
await cdp.evm.sendTransaction({ address, network: "base", transaction: { ... } });

// With useNetwork — scope once, use everywhere
const baseAccount = await account.useNetwork("base");
await baseAccount.sendTransaction({ transaction: { to: "0x...", value: 0n } });
await baseAccount.waitForTransactionReceipt(result); // uses CDP Node RPC automatically
```

To use a custom RPC endpoint or a network not natively supported by CDP, pass the RPC URL directly:

```typescript Node (TypeScript) theme={null}
const polygonAccount = await account.useNetwork(
  "https://polygon-mainnet.rpc-provider.com/YOUR_API_KEY"
);

const result = await polygonAccount.sendTransaction({
  transaction: { to: "0x...", value: 0n },
});
const receipt = await polygonAccount.waitForTransactionReceipt(result);
```

## Solana

Solana transactions require building and serializing a transaction before sending. CDP injects the latest blockhash before broadcasting, so use the placeholder blockhash shown below.

<Tabs>
  <Tab title="React">
    Use `useSendSolanaTransaction` for programmatic control, or `SendSolanaTransactionButton` for a pre-built UI button with built-in loading and error states.

    ```tsx theme={null}
    import { useSendSolanaTransaction, useSolanaAddress } from "@coinbase/cdp-hooks";
    import {
      PublicKey,
      SystemProgram,
      Transaction,
      SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
    } from "@solana/web3.js";
    import { Buffer } from "buffer";

    function SendTransaction() {
      const { sendSolanaTransaction } = useSendSolanaTransaction();
      const { solanaAddress } = useSolanaAddress();

      const handleSend = async () => {
        if (!solanaAddress) return;

        const tx = new Transaction().add(
          SystemProgram.transfer({
            fromPubkey: new PublicKey(solanaAddress),
            toPubkey: new PublicKey("recipient-address"),
            lamports: 1000,
          })
        );
        tx.recentBlockhash = SYSVAR_RECENT_BLOCKHASHES_PUBKEY.toBase58();
        tx.feePayer = new PublicKey(solanaAddress);

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

        const result = await sendSolanaTransaction({
          transaction: serialized,
          solanaAccount: solanaAddress,
          network: "solana-devnet",
        });
        console.log("Signature:", result.transactionSignature);
      };

      return <button onClick={handleSend}>Send</button>;
    }
    ```
  </Tab>

  <Tab title="Node (TypeScript)">
    ```typescript theme={null}
    import {
      Connection,
      PublicKey,
      SystemProgram,
      Transaction,
      SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
    } from "@solana/web3.js";

    const tx = new Transaction().add(
      SystemProgram.transfer({
        fromPubkey: new PublicKey(account.address),
        toPubkey: new PublicKey("3KzDtddx4i53FBkvCzuDmRbaMozTZoJBb1TToWhz3JfE"),
        lamports: 1000,
      })
    );
    tx.recentBlockhash = SYSVAR_RECENT_BLOCKHASHES_PUBKEY.toBase58();
    tx.feePayer = new PublicKey(account.address);

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

    const result = await cdp.solana.sendTransaction({
      network: "solana-devnet",
      transaction: serialized,
    });
    const { signature } = result;
    console.log("Signature:", signature);

    // Confirm
    const connection = new Connection("https://api.devnet.solana.com");
    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}`);
    }
    console.log(`Explorer: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import base64
    from solders.pubkey import Pubkey as PublicKey
    from solders.system_program import TransferParams, transfer
    from solders.message import Message
    from solders.hash import Hash
    from solana.rpc.api import Client as SolanaClient
    from solders.signature import Signature

    source = PublicKey.from_string(account.address)
    dest = PublicKey.from_string("3KzDtddx4i53FBkvCzuDmRbaMozTZoJBb1TToWhz3JfE")

    message = Message.new_with_blockhash(
        [transfer(TransferParams(from_pubkey=source, to_pubkey=dest, lamports=1000))],
        source,
        Hash.from_string("SysvarRecentB1ockHashes11111111111111111111"),
    )

    tx_bytes = bytes([1]) + bytes(64) + bytes(message)
    serialized = base64.b64encode(tx_bytes).decode("utf-8")

    result = await cdp.solana.send_transaction(
        network="solana-devnet",
        transaction=serialized,
    )
    signature = result.transaction_signature
    print(f"Signature: {signature}")

    # Confirm
    connection = SolanaClient("https://api.devnet.solana.com")
    confirmation = connection.confirm_transaction(
        Signature.from_string(signature), commitment="processed"
    )

    if hasattr(confirmation, "err") and confirmation.err:
        raise ValueError(f"Transaction failed: {confirmation.err}")

    print(f"Explorer: https://explorer.solana.com/tx/{signature}?cluster=devnet")
    ```
  </Tab>
</Tabs>

### Bring your own node

Use `signTransaction` to sign with CDP and broadcast via a custom RPC node:

<Tabs>
  <Tab title="Node (TypeScript)">
    ```typescript theme={null}
    const { blockhash } = await connection.getLatestBlockhash();
    tx.recentBlockhash = blockhash;

    const signedTx = await cdp.solana.signTransaction({
      address: account.address,
      transaction: serialized,
    });

    const decoded = Buffer.from(signedTx.signature, "base64");
    const signature = await connection.sendRawTransaction(decoded);
    console.log("Signature:", signature);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from solana.rpc.types import TxOpts

    response = await cdp.solana.sign_transaction(
        address=account.address,
        transaction=serialized,
    )

    decoded = base64.b64decode(response.signed_transaction)
    tx_resp = connection.send_raw_transaction(
        decoded,
        opts=TxOpts(skip_preflight=False, preflight_commitment="processed"),
    )
    print(f"Signature: {tx_resp.value}")
    ```
  </Tab>
</Tabs>

### Priority fees

The priority fee increases the likelihood of your transaction being included in the next block.

**Priority fee** = Compute unit limit × Compute unit price

<Tip>
  CDP automatically adds compute unit limit and price instructions if they are not already present in your transaction.
</Tip>

<Tabs>
  <Tab title="Node (TypeScript)">
    ```typescript theme={null}
    import { ComputeBudgetProgram, Transaction } from "@solana/web3.js";

    const tx = new Transaction().add(
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 5000 }),
      ComputeBudgetProgram.setComputeUnitLimit({ units: 300000 }),
      // ...your other instructions
    );
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from solana.transaction import Transaction
    from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit

    tx = Transaction().add(
        set_compute_unit_price(5000),
        set_compute_unit_limit(300000),
        # ...your other instructions
    )
    ```
  </Tab>
</Tabs>

### Fee sponsorship

CDP can pay the Solana network fee on behalf of your wallet. Pass `useCdpSponsor: true` when calling `sendTransaction`.

<Note>
  Fee sponsorship is in private preview and available to enterprise-scale integrations only. To opt in, [apply for access](https://docs.google.com/forms/d/e/1FAIpQLSdMG0DDGkLDV73H1QNVQ50hrjVRBtNgfBPwVVW_f8RAASoWgQ/viewform).
</Note>

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    import { useSendSolanaTransaction, useSolanaAddress } from "@coinbase/cdp-hooks";

    function SendSponsoredTransaction() {
      const { sendSolanaTransaction } = useSendSolanaTransaction();
      const { solanaAddress } = useSolanaAddress();

      const handleSend = async () => {
        if (!solanaAddress) return;
        const result = await sendSolanaTransaction({
          solanaAccount: solanaAddress,
          network: "solana-mainnet",
          transaction: serializedTx,
          useCdpSponsor: true,
        });
        console.log("Signature:", result.transactionSignature);
      };

      return <button onClick={handleSend}>Send (sponsored)</button>;
    }
    ```
  </Tab>

  <Tab title="Node (TypeScript)">
    ```typescript theme={null}
    const result = await cdp.solana.sendTransaction({
      network: "solana-mainnet",
      transaction: serializedTx,
      useCdpSponsor: true,
    });
    console.log("Signature:", result.transactionSignature);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = await cdp.solana.send_transaction(
        network="solana-mainnet",
        transaction=serialized_tx,
        use_cdp_sponsor=True,
    )
    print(f"Signature: {response.transaction_signature}")
    ```
  </Tab>
</Tabs>

## Send USDC

USDC uses 6 decimal places, so `1000000` atomic units equals 1 USDC.

<Tabs>
  <Tab title="React">
    The `useSendUsdc` hook from `@coinbase/cdp-hooks` works across all account types (EOA, Smart Account, Solana) and handles contract addresses, decimal conversion, and Associated Token Account creation automatically.

    ```tsx theme={null}
    import { useSendUsdc } from "@coinbase/cdp-hooks";

    function SendUsdcComponent() {
      const { sendUsdc, data, error, status } = useSendUsdc();

      const handleSend = async () => {
        const result = await sendUsdc({
          to: "0x1234567890123456789012345678901234567890",
          amount: "25.50", // human-readable, not atomic units
          network: "base-sepolia",
        });

        if (result.type === "evm-eoa") {
          console.log("EOA Transaction:", result.transactionHash);
        } else if (result.type === "evm-smart") {
          console.log("Smart Account UserOp:", result.userOpHash);
        } else if (result.type === "solana") {
          console.log("Solana Transaction:", result.transactionSignature);
        }
      };

      return (
        <button onClick={handleSend} disabled={status === "pending"}>
          {status === "pending" ? "Sending..." : "Send 25.50 USDC"}
        </button>
      );
    }
    ```

    For Smart Accounts, pass `useCdpPaymaster: true` for gasless transactions. For Solana, pass `createRecipientAta: true` to create the recipient's token account if it doesn't exist.

    See the full parameter reference in the [CDP Web SDK docs](/sdks/cdp-sdks-v2/frontend).
  </Tab>

  <Tab title="Node (TypeScript)">
    Use `cdp.evm.sendTransaction` with an encoded ERC-20 `transfer` call. The USDC contract address varies by network — use the correct one for your target network.

    ```typescript theme={null}
    import { CdpClient } from "@coinbase/cdp-sdk";
    import { encodeFunctionData, parseUnits } from "viem";

    const cdp = new CdpClient();

    // USDC contract addresses
    const USDC = {
      "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "base": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    };

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

    const data = encodeFunctionData({
      abi: [{
        name: "transfer",
        type: "function",
        inputs: [
          { name: "to", type: "address" },
          { name: "amount", type: "uint256" },
        ],
        outputs: [{ type: "bool" }],
      }],
      functionName: "transfer",
      args: [
        "0xRecipientAddress",
        parseUnits("25.50", 6), // 25.50 USDC in atomic units
      ],
    });

    const { transactionHash } = await cdp.evm.sendTransaction({
      address: account.address,
      network: "base-sepolia",
      transaction: {
        to: USDC["base-sepolia"],
        data,
      },
    });
    console.log("USDC sent:", transactionHash);
    ```
  </Tab>

  <Tab title="Python">
    Use `cdp.evm.send_transaction` with ABI-encoded ERC-20 calldata.

    ```python theme={null}
    from cdp import CdpClient
    from cdp.evm_transaction_types import TransactionRequestEIP1559
    from web3 import Web3

    w3 = Web3()

    USDC_ABI = [{
        "name": "transfer",
        "type": "function",
        "inputs": [
            {"name": "to", "type": "address"},
            {"name": "amount", "type": "uint256"},
        ],
        "outputs": [{"type": "bool"}],
    }]

    # USDC contract addresses
    USDC = {
        "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
        "base": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    }

    async def send_usdc():
        async with CdpClient() as cdp:
            account = await cdp.evm.get_or_create_account(name="MyAccount")

            contract = w3.eth.contract(abi=USDC_ABI)
            amount = 25_500_000  # 25.50 USDC (6 decimals)
            data = contract.encodeABI(
                fn_name="transfer",
                args=["0xRecipientAddress", amount],
            )

            tx_hash = await cdp.evm.send_transaction(
                address=account.address,
                transaction=TransactionRequestEIP1559(
                    to=USDC["base-sepolia"],
                    data=data,
                ),
                network="base-sepolia",
            )
            print(f"USDC sent: {tx_hash}")
    ```
  </Tab>
</Tabs>

## Webhooks

Subscribe to transaction lifecycle events using [CDP Wallet Webhooks](/webhooks/wallets). The `wallet.transaction.*` events let you track each transaction from creation through confirmation or failure in real time.
