Skip to main content

Overview

Connect to Solana networks to query accounts, check balances, and prepare transactions.

Prerequisites

Get Solana Wallets

import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet

val sdk = DynamicSDK.getInstance()

// Get all Solana wallets
val solanaWallets = sdk.wallets.userWallets.filter {
    it.chain.uppercase() == "SOL"
}

// Use first Solana wallet
val wallet = solanaWallets.firstOrNull()
if (wallet != null) {
    println("Solana Address: ${wallet.address}")
}

Create Solana Connection

import com.solanaweb3.Connection
import com.solanaweb3.Cluster

val connection = Connection(Cluster.DEVNET)
val mainnetConnection = Connection(Cluster.MAINNET_BETA)
val customConnection = Connection("https://api.mainnet-beta.solana.com")

Query Account Balance

import com.solanaweb3.Connection
import com.solanaweb3.Cluster
import org.sol4k.PublicKey

suspend fun getBalance(address: String): Long {
    return try {
        val connection = Connection(Cluster.DEVNET)
        val publicKey = PublicKey(address)
        connection.getBalance(publicKey)
    } catch (e: Exception) {
        println("Failed to get balance: ${e.message}")
        0L
    }
}

Get Latest Blockhash

import com.solanaweb3.Connection
import com.solanaweb3.Cluster

suspend fun getLatestBlockhash(): String {
    return try {
        val connection = Connection(Cluster.DEVNET)
        val blockhashResult = connection.getLatestBlockhash()
        blockhashResult.blockhash
    } catch (e: Exception) {
        println("Failed to get blockhash: ${e.message}")
        throw e
    }
}

// Usage
val blockhash = getLatestBlockhash()
println("Latest blockhash: $blockhash")

Lamports Conversion

fun solToLamports(sol: Double): Long = (sol * 1_000_000_000).toLong()
fun lamportsToSol(lamports: Long): Double = lamports / 1_000_000_000.0

Solana Network Configuration

import com.solanaweb3.Cluster

enum class SolanaNetwork(val cluster: Cluster, val displayName: String) {
    DEVNET(Cluster.DEVNET, "Devnet"),
    TESTNET(Cluster.TESTNET, "Testnet"),
    MAINNET(Cluster.MAINNET_BETA, "Mainnet Beta");

    fun createConnection(): Connection {
        return Connection(cluster)
    }
}

// Usage
val network = SolanaNetwork.DEVNET
val connection = network.createConnection()

Best Practices

  • Handle network errors gracefully
  • Cache connection instances to avoid repeated creation
  • Validate public key format before use
  • Use devnet for testing, mainnet for production
  • Monitor balance changes periodically if needed

Error Handling

sealed class SolanaConnectionError {
    data class NetworkError(val message: String) : SolanaConnectionError()
    data class InvalidAddress(val message: String) : SolanaConnectionError()
    data class RpcError(val message: String) : SolanaConnectionError()
    data class Unknown(val message: String) : SolanaConnectionError()
}

fun parseSolanaError(e: Exception): SolanaConnectionError {
    val errorMessage = e.message?.lowercase() ?: ""

    return when {
        errorMessage.contains("network") || errorMessage.contains("connection") ->
            SolanaConnectionError.NetworkError("Network connection failed")
        errorMessage.contains("invalid") && errorMessage.contains("address") ->
            SolanaConnectionError.InvalidAddress("Invalid Solana address")
        errorMessage.contains("rpc") ->
            SolanaConnectionError.RpcError("RPC request failed")
        else ->
            SolanaConnectionError.Unknown(e.message ?: "Unknown error")
    }
}

// Usage in ViewModel
try {
    val balance = connection.getBalance(publicKey)
    _balance.value = balance
} catch (e: Exception) {
    val error = parseSolanaError(e)
    _errorMessage.value = when (error) {
        is SolanaConnectionError.NetworkError -> error.message
        is SolanaConnectionError.InvalidAddress -> error.message
        is SolanaConnectionError.RpcError -> error.message
        is SolanaConnectionError.Unknown -> error.message
    }
}

Troubleshooting

Connection timeout: Use reliable RPC endpoint or implement retry logic with exponential backoff Invalid blockhash: Fetch blockhash immediately before creating transaction (valid ~60 seconds) Rate limiting: Add delays between requests or use rate limiting wrapper

What’s Next