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

# Send SVM Transactions

> Sign and broadcast Solana transactions in a single call with Dynamic's Java SDK

## Overview

`DynamicSvmWalletClient::sendTransaction` signs the serialized message of a Solana transaction with the MPC ceremony **and** broadcasts it via Solana JSON-RPC in one call. Returns the transaction signature (base58) — the standard Solana tx ID.

`sendTransaction` is the recommended path for most apps. Reach for [`signTransaction`](/java/svm/sign-transaction) only if you need to assemble the wire envelope yourself.

## Prerequisites

* [Created an SVM wallet](/java/svm/create-wallet)
* A Solana JSON-RPC endpoint (mainnet, devnet, or your own validator)

## Sign + Broadcast in One Call

```java theme={"system"}
import xyz.dynamic.waas.svm.opts.SendTransactionOpts;

byte[] messageBytes = /* bytes(transaction.message) — see Sign SVM Transactions */;

String txSig = client.sendTransaction(SendTransactionOpts.builder()
    .messageBytes(messageBytes)
    .walletProperties(walletProperties)
    .externalServerKeyShares(externalServerKeyShares)
    .rpcUrl("https://api.devnet.solana.com")
    .sponsor(false)        // true to take the sponsorship path
    .build()
).join();

System.out.println("Submitted tx: " + txSig);
System.out.println("Explorer: https://explorer.solana.com/tx/" + txSig + "?cluster=devnet");
```

A fresh JSON-RPC client is constructed per call. For high-throughput scenarios, compose [`signTransaction`](/java/svm/sign-transaction) with your own pooled RPC client.

## Gas Sponsorship

Setting `.sponsor(true)` routes the broadcast through Dynamic's sponsor path — Dynamic pays the SOL transaction fee and you don't need to fund the wallet's lamports balance. Gas sponsorship must be enabled for your environment in the Dynamic dashboard.

```java theme={"system"}
String sponsoredTxSig = client.sendTransaction(SendTransactionOpts.builder()
    .messageBytes(messageBytes)
    .walletProperties(walletProperties)
    .externalServerKeyShares(externalServerKeyShares)
    .rpcUrl("https://api.mainnet-beta.solana.com")
    .sponsor(true)
    .build()
).join();
```

See [Sponsor Transactions](/java/svm/sponsor-transaction) for the lower-level building block (`sponsorTransaction` returns the sponsor-signed wire envelope without broadcasting).

## Building the Message

Use [`sava-core`](https://github.com/sava-software/sava) (or any other JVM Solana SDK) to assemble the unsigned transaction, fetch the latest blockhash, and serialize **just the message portion**:

```java theme={"system"}
import software.sava.core.tx.Transaction;
import software.sava.rpc.json.http.client.SolanaRpcClient;

SolanaRpcClient rpc = SolanaRpcClient.createClient(java.net.URI.create("https://api.devnet.solana.com"));
String blockhash    = rpc.getLatestBlockhash().join().blockhash();

Transaction tx = Transaction.createTx(
    walletPubkey,
    List.of(/* SystemProgram.transfer(...), etc. */),
    blockhash
);
byte[] messageBytes = tx.serializedMessage();
```

## Error Handling

```java theme={"system"}
import java.util.concurrent.CompletionException;
import xyz.dynamic.waas.core.exceptions.DynamicSdkException;

try {
    String txSig = client.sendTransaction(opts).join();
    log.info("Submitted: {}", txSig);
} catch (CompletionException ce) {
    if (ce.getCause() instanceof DynamicSdkException dse) {
        log.error("Send failed: {}", dse.getMessage(), dse);
    } else {
        throw ce;
    }
}
```

If the broadcast itself fails (`blockhash not found`, sponsor pool exhausted, etc.), the error message surfaces verbatim — refresh the blockhash and retry.

## Next Steps

* [Sign transactions](/java/svm/sign-transaction) — get the raw signature without broadcasting
* [Sponsor transactions](/java/svm/sponsor-transaction) — lower-level sponsor primitive
* [Sign messages](/java/svm/sign-messages)
* [Delegated access](/java/svm/delegated-access)
