Get Native Token Balance
Retrieve the native token balance (ETH for EVM, SOL for Solana):Copy
Ask AI
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet
val sdk = DynamicSDK.getInstance()
// Get EVM wallet balance
val evmWallet: BaseWallet = sdk.wallets.userWallets.first { it.chain == "EVM" }
val ethBalance = sdk.wallets.getBalance(evmWallet)
println("ETH Balance: $ethBalance")
// Get Solana wallet balance
val solanaWallet: BaseWallet = sdk.wallets.userWallets.first { it.chain == "SOL" }
val solBalance = sdk.wallets.getBalance(solanaWallet)
println("SOL Balance: $solBalance")
Balance Display with UI
Create a balance display component:Copy
Ask AI
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class BalanceViewModel(private val wallet: BaseWallet) : ViewModel() {
private val sdk = DynamicSDK.getInstance()
private val _balance = MutableStateFlow<String?>(null)
val balance: StateFlow<String?> = _balance
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading
private val _errorMessage = MutableStateFlow<String?>(null)
val errorMessage: StateFlow<String?> = _errorMessage
init {
loadBalance()
}
fun loadBalance() {
viewModelScope.launch {
_isLoading.value = true
_errorMessage.value = null
try {
val balanceValue = sdk.wallets.getBalance(wallet)
_balance.value = balanceValue
} catch (e: Exception) {
_errorMessage.value = "Failed to load balance: ${e.message}"
}
_isLoading.value = false
}
}
fun refresh() {
loadBalance()
}
}
Jetpack Compose UI
Copy
Ask AI
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun BalanceScreen(viewModel: BalanceViewModel, wallet: BaseWallet) {
val balance by viewModel.balance.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
val errorMessage by viewModel.errorMessage.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Wallet Balance",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(8.dp))
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.size(32.dp))
} else if (balance != null) {
Text(
text = formatBalance(balance!!, wallet.chain),
style = MaterialTheme.typography.headlineLarge
)
Text(
text = getNativeTokenSymbol(wallet.chain),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.primary
)
} else {
Text(
text = "No balance",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.height(16.dp))
// Wallet address
Text(
text = wallet.address,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1
)
Spacer(modifier = Modifier.height(16.dp))
// Refresh button
Button(
onClick = { viewModel.refresh() },
enabled = !isLoading
) {
Icon(Icons.Default.Refresh, contentDescription = "Refresh")
Spacer(modifier = Modifier.width(8.dp))
Text("Refresh Balance")
}
}
}
errorMessage?.let { error ->
Spacer(modifier = Modifier.height(16.dp))
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.errorContainer
)
) {
Text(
text = error,
modifier = Modifier.padding(16.dp),
color = MaterialTheme.colorScheme.onErrorContainer
)
}
}
}
}
fun formatBalance(balance: String, chain: String): String {
return try {
val balanceValue = balance.toDoubleOrNull() ?: 0.0
String.format("%.4f", balanceValue)
} catch (e: Exception) {
balance
}
}
fun getNativeTokenSymbol(chain: String): String {
return when (chain.uppercase()) {
"EVM" -> "ETH"
"SOL" -> "SOL"
else -> "TOKEN"
}
}
Multiple Wallet Balances
Display balances for all user wallets:Copy
Ask AI
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
data class WalletWithBalance(
val wallet: BaseWallet,
val balance: String?,
val isLoading: Boolean = false
)
class WalletBalancesViewModel : ViewModel() {
private val sdk = DynamicSDK.getInstance()
private val _walletBalances = MutableStateFlow<List<WalletWithBalance>>(emptyList())
val walletBalances: StateFlow<List<WalletWithBalance>> = _walletBalances
init {
loadAllBalances()
}
private fun loadAllBalances() {
viewModelScope.launch {
val wallets = sdk.wallets.userWallets
_walletBalances.value = wallets.map { wallet ->
WalletWithBalance(wallet, null, true)
}
// Load each balance
wallets.forEach { wallet ->
launch {
try {
val balance = sdk.wallets.getBalance(wallet)
updateWalletBalance(wallet.address, balance, false)
} catch (e: Exception) {
updateWalletBalance(wallet.address, null, false)
}
}
}
}
}
private fun updateWalletBalance(address: String, balance: String?, isLoading: Boolean) {
_walletBalances.value = _walletBalances.value.map { item ->
if (item.wallet.address == address) {
item.copy(balance = balance, isLoading = isLoading)
} else {
item
}
}
}
fun refresh() {
loadAllBalances()
}
}
@Composable
fun AllWalletsBalanceScreen(viewModel: WalletBalancesViewModel) {
val walletBalances by viewModel.walletBalances.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "My Wallets",
style = MaterialTheme.typography.headlineMedium
)
IconButton(onClick = { viewModel.refresh() }) {
Icon(Icons.Default.Refresh, contentDescription = "Refresh")
}
}
Spacer(modifier = Modifier.height(16.dp))
walletBalances.forEach { item ->
WalletBalanceCard(item)
Spacer(modifier = Modifier.height(8.dp))
}
}
}
@Composable
fun WalletBalanceCard(item: WalletWithBalance) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = item.wallet.chain.uppercase(),
style = MaterialTheme.typography.titleMedium
)
if (item.isLoading) {
CircularProgressIndicator(modifier = Modifier.size(24.dp))
} else if (item.balance != null) {
Text(
text = "${formatBalance(item.balance, item.wallet.chain)} ${getNativeTokenSymbol(item.wallet.chain)}",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary
)
} else {
Text(
text = "Error",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = item.wallet.address,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1
)
}
}
}
Converting Wei to ETH
For EVM wallets, balances are often returned in Wei. Convert to ETH:Copy
Ask AI
import java.math.BigDecimal
import java.math.BigInteger
fun weiToEth(wei: String): String {
return try {
val weiValue = BigInteger(wei)
val ethValue = BigDecimal(weiValue).divide(BigDecimal("1000000000000000000"))
String.format("%.4f", ethValue.toDouble())
} catch (e: Exception) {
"0.0000"
}
}
// Usage
val balanceWei = sdk.wallets.getBalance(wallet)
val balanceEth = weiToEth(balanceWei)
println("Balance: $balanceEth ETH")
Best Practices
1. Cache Balances
Avoid excessive API calls by caching balances:Copy
Ask AI
private var lastBalanceUpdate = 0L
private var cachedBalance: String? = null
fun getBalanceWithCache(wallet: BaseWallet): String? {
val now = System.currentTimeMillis()
if (cachedBalance != null && now - lastBalanceUpdate < 30000) {
return cachedBalance
}
cachedBalance = sdk.wallets.getBalance(wallet)
lastBalanceUpdate = now
return cachedBalance
}
2. Handle Loading States
Always show loading indicators when fetching balances:Copy
Ask AI
_isLoading.value = true
try {
val balance = sdk.wallets.getBalance(wallet)
_balance.value = balance
} catch (e: Exception) {
_error.value = e.message
} finally {
_isLoading.value = false
}
3. Refresh on Network Switch
Update balances when switching networks:Copy
Ask AI
fun switchNetwork(chainId: Int) {
viewModelScope.launch {
sdk.wallets.switchNetwork(wallet, Network(JsonPrimitive(chainId)))
loadBalance() // Refresh balance after network switch
}
}
What’s Next
- Network Management - Switch between networks
- Send ETH - Send transactions
- ERC-20 Transfers - Transfer tokens