> ## 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 Solana Transactions

> Send SOL transactions with the Dynamic Android SDK.

## Overview

Build, sign, and send SOL transactions with blockhash management.

## Prerequisites

* Dynamic SDK initialized (see [Installation Guide](/kotlin/quickstart))
* User authenticated (see [Authentication Guide](/kotlin/authentication))
* Solana wallet available (see [Wallet Creation](/kotlin/wallet-creation))
* SolanaWeb3 library added to your project

## Send SOL Transaction

```kotlin theme={"system"}
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet
import com.solanaweb3.*
import org.sol4k.PublicKey

val sdk = DynamicSDK.getInstance()

suspend fun sendSOL(
    wallet: BaseWallet,
    recipient: String,
    amountInSOL: Double
): String {
    try {
        val connection = Connection(Cluster.DEVNET)
        val fromPubkey = PublicKey(wallet.address)
        val toPubkey = PublicKey(recipient)
        val lamports = (amountInSOL * 1_000_000_000).toLong()
        val blockhash = connection.getLatestBlockhash()

        val instruction = SystemProgram.transfer(fromPubkey, toPubkey, lamports)
        val transaction = Transaction.v0(fromPubkey, listOf(instruction), blockhash.blockhash)
        val base64Transaction = transaction.serializeUnsignedToBase64()
        val signature = sdk.solana.signAndSendTransaction(base64Transaction, wallet)

        println("Transaction sent!")
        println("Signature: $signature")
        return signature
    } catch (e: Exception) {
        println("Transaction failed: ${e.message}")
        throw e
    }
}
```

## Sign Transaction (Without Sending)

```kotlin theme={"system"}
suspend fun signTransactionOnly(wallet: BaseWallet, base64Transaction: String): String {
    try {
        val signedTransaction = sdk.solana.signTransaction(base64Transaction, wallet)
        println("Signed transaction: $signedTransaction")
        return signedTransaction
    } catch (e: Exception) {
        println("Failed to sign: ${e.message}")
        throw e
    }
}
```

## Lamports Conversion Helpers

```kotlin theme={"system"}
object SolanaUtils {
    const val LAMPORTS_PER_SOL = 1_000_000_000L

    fun solToLamports(sol: Double): Long {
        return (sol * LAMPORTS_PER_SOL).toLong()
    }

    fun lamportsToSol(lamports: Long): Double {
        return lamports.toDouble() / LAMPORTS_PER_SOL
    }

    fun formatSol(sol: Double): String {
        return String.format("%.9f SOL", sol)
    }

    fun formatLamports(lamports: Long): String {
        return String.format("%,d lamports", lamports)
    }
}

// Usage
val amount = 1.5
val lamports = SolanaUtils.solToLamports(amount)
println("${amount} SOL = ${SolanaUtils.formatLamports(lamports)}")
```

## Transaction Explorer Links

```kotlin theme={"system"}
fun getExplorerUrl(signature: String, cluster: Cluster = Cluster.DEVNET): String {
    val clusterParam = when (cluster) {
        Cluster.DEVNET -> "devnet"
        Cluster.TESTNET -> "testnet"
        Cluster.MAINNET_BETA -> "mainnet-beta"
        else -> "devnet"
    }
    return "https://explorer.solana.com/tx/$signature?cluster=$clusterParam"
}

// Usage in Compose
@Composable
fun ExplorerLink(signature: String, cluster: Cluster) {
    val url = getExplorerUrl(signature, cluster)
    Button(onClick = { /* Open URL in browser */ }) {
        Text("View on Solana Explorer")
    }
}
```

## Best Practices

* Get fresh blockhash immediately before sending (valid \~60 seconds)
* Validate addresses before creating transactions
* Check balance includes transaction fees (\~5000 lamports)
* Show transaction confirmations to users
* Display transaction status with explorer links

## Error Handling

### Common Transaction Errors

```kotlin theme={"system"}
sealed class SolanaTransactionError {
    data class InsufficientFunds(val message: String) : SolanaTransactionError()
    data class InvalidBlockhash(val message: String) : SolanaTransactionError()
    data class NetworkError(val message: String) : SolanaTransactionError()
    data class InvalidAddress(val message: String) : SolanaTransactionError()
    data class UserRejected(val message: String) : SolanaTransactionError()
    data class Unknown(val message: String) : SolanaTransactionError()
}

fun parseTransactionError(e: Exception): SolanaTransactionError {
    val errorMessage = e.message?.lowercase() ?: ""

    return when {
        errorMessage.contains("insufficient") || errorMessage.contains("balance") ->
            SolanaTransactionError.InsufficientFunds("Insufficient balance for transaction")
        errorMessage.contains("blockhash") ->
            SolanaTransactionError.InvalidBlockhash("Blockhash expired, please try again")
        errorMessage.contains("network") || errorMessage.contains("connection") ->
            SolanaTransactionError.NetworkError("Network error, check your connection")
        errorMessage.contains("invalid") && errorMessage.contains("address") ->
            SolanaTransactionError.InvalidAddress("Invalid recipient address")
        errorMessage.contains("rejected") || errorMessage.contains("denied") ->
            SolanaTransactionError.UserRejected("Transaction was rejected")
        else ->
            SolanaTransactionError.Unknown("Transaction failed: ${e.message}")
    }
}

// Usage in ViewModel
try {
    val signature = sdk.solana.signAndSendTransaction(base64Transaction, wallet)
    _transactionSignature.value = signature
} catch (e: Exception) {
    val error = parseTransactionError(e)
    _errorMessage.value = when (error) {
        is SolanaTransactionError.InsufficientFunds -> error.message
        is SolanaTransactionError.InvalidBlockhash -> error.message
        is SolanaTransactionError.NetworkError -> error.message
        is SolanaTransactionError.InvalidAddress -> error.message
        is SolanaTransactionError.UserRejected -> error.message
        is SolanaTransactionError.Unknown -> error.message
    }
}
```

## Troubleshooting

**Transaction not confirming**: Check transaction status on explorer

**Blockhash expired**: Get fresh blockhash immediately before sending, implement retry logic

**Network mismatch**: Use devnet for testing, mainnet for production

**Insufficient funds**: Get devnet SOL from faucet.solana.com for testing

## What's Next

* [Solana Connection](/kotlin/wallets/solana/connection) - RPC setup and configuration
* [Sign Solana Messages](/kotlin/wallets/solana/message-signing) - Sign messages with wallets
* [Token Balances](/kotlin/wallets/general/token-balances) - Query SOL and token balances
* [Network Management](/kotlin/wallets/general/network-management) - Switch between networks
