Skip to main content
Wallets are automatically created after authentication when enabled in your Dynamic dashboard.

Prerequisites

  • SDK initialized
  • User authenticated
  • Embedded wallets enabled in dashboard

Listening for Wallet Creation

Use the userWalletsChanges Flow to know when wallets are ready:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class WalletManager : ViewModel() {
    private val sdk = DynamicSDK.getInstance()
    private var walletCreationTimer: Job? = null

    private val _wallets = MutableStateFlow<List<BaseWallet>>(emptyList())
    val wallets: StateFlow<List<BaseWallet>> = _wallets.asStateFlow()

    private val _isCreatingWallets = MutableStateFlow(false)
    val isCreatingWallets: StateFlow<Boolean> = _isCreatingWallets.asStateFlow()

    init {
        startListening()
    }

    private fun startListening() {
        // Get current wallets
        _wallets.value = sdk.wallets.userWallets

        // If user is authenticated but no wallets yet, they're being created
        if (sdk.auth.isAuthenticated() && _wallets.value.isEmpty()) {
            _isCreatingWallets.value = true

            // Set a timeout for wallet creation
            walletCreationTimer = viewModelScope.launch {
                delay(15000) // 15 seconds
                if (_wallets.value.isEmpty()) {
                    _isCreatingWallets.value = false
                }
            }
        }

        // Listen for wallet updates
        viewModelScope.launch {
            sdk.wallets.userWalletsChanges.collect { newWallets ->
                _wallets.value = newWallets

                if (newWallets.isNotEmpty()) {
                    _isCreatingWallets.value = false
                    walletCreationTimer?.cancel()
                }
            }
        }
    }
}

Displaying Wallets

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.dynamic.sdk.android.Models.BaseWallet

@Composable
fun WalletsScreen(viewModel: WalletManager) {
    val wallets by viewModel.wallets.collectAsState()
    val isCreatingWallets by viewModel.isCreatingWallets.collectAsState()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(
            text = "My Wallets",
            style = MaterialTheme.typography.headlineMedium
        )

        Spacer(modifier = Modifier.height(16.dp))

        when {
            isCreatingWallets -> {
                Row(
                    horizontalArrangement = Arrangement.spacedBy(8.dp),
                    verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
                ) {
                    CircularProgressIndicator()
                    Text("Creating wallets...")
                }
            }
            wallets.isEmpty() -> {
                Text("No wallets available")
            }
            else -> {
                LazyColumn {
                    items(wallets) { wallet ->
                        WalletCard(wallet)
                    }
                }
            }
        }
    }
}

@Composable
fun WalletCard(wallet: BaseWallet) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 8.dp)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
            ) {
                Text(
                    text = wallet.walletName ?: "Wallet",
                    style = MaterialTheme.typography.titleMedium
                )
                Surface(
                    color = MaterialTheme.colorScheme.primaryContainer,
                    shape = MaterialTheme.shapes.small
                ) {
                    Text(
                        text = wallet.chain.uppercase(),
                        modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.onPrimaryContainer
                    )
                }
            }

            Spacer(modifier = Modifier.height(8.dp))

            Text(
                text = wallet.address,
                style = MaterialTheme.typography.bodyMedium,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                maxLines = 1
            )
        }
    }
}

Wallet Types

The SDK supports multiple wallet types:

EVM Wallets

For Ethereum and EVM-compatible chains (Polygon, Base, Arbitrum, etc.):
val evmWallets = sdk.wallets.userWallets.filter {
    it.chain.uppercase() == "EVM"
}

Solana Wallets

For Solana blockchain:
val solanaWallets = sdk.wallets.userWallets.filter {
    it.chain.uppercase() == "SOL"
}

Wallet Properties

Each BaseWallet has the following properties:
val wallet: BaseWallet

// Wallet address
val address = wallet.address  // "0x..." for EVM, base58 for Solana

// Chain type
val chain = wallet.chain  // "EVM" or "SOL"

// Wallet name (optional)
val name = wallet.walletName  // e.g., "turnkey"

// Wallet ID (for API operations)
val id = wallet.id  // Used for setPrimary, etc.

Setting Primary Wallet

You can set a wallet as the user’s primary wallet:
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.Models.BaseWallet

val sdk = DynamicSDK.getInstance()

fun setPrimaryWallet(wallet: BaseWallet) {
    val walletId = wallet.id ?: return

    try {
        sdk.wallets.setPrimary(walletId)
        println("Primary wallet set successfully")
    } catch (e: Exception) {
        println("Failed to set primary wallet: ${e.message}")
    }
}

Multi-Chain Support

When you have both EVM and Solana enabled in your dashboard, users will automatically get wallets for both chains:
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.dynamic.sdk.android.Models.BaseWallet

@Composable
fun MultiChainWalletsScreen(wallets: List<BaseWallet>) {
    val evmWallets = wallets.filter { it.chain.uppercase() == "EVM" }
    val solanaWallets = wallets.filter { it.chain.uppercase() == "SOL" }

    LazyColumn(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        // EVM Wallets Section
        if (evmWallets.isNotEmpty()) {
            item {
                Text(
                    text = "EVM Wallets",
                    style = MaterialTheme.typography.titleLarge,
                    modifier = Modifier.padding(vertical = 8.dp)
                )
            }
            items(evmWallets) { wallet ->
                WalletCard(wallet)
            }
        }

        // Solana Wallets Section
        if (solanaWallets.isNotEmpty()) {
            item {
                Spacer(modifier = Modifier.height(16.dp))
                Text(
                    text = "Solana Wallets",
                    style = MaterialTheme.typography.titleLarge,
                    modifier = Modifier.padding(vertical = 8.dp)
                )
            }
            items(solanaWallets) { wallet ->
                WalletCard(wallet)
            }
        }
    }
}

@Composable
fun WalletCard(wallet: BaseWallet) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 8.dp)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = wallet.walletName ?: "Wallet",
                style = MaterialTheme.typography.titleMedium
            )
            Text(
                text = wallet.address,
                style = MaterialTheme.typography.bodyMedium,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        }
    }
}

Next Steps

After wallets are created, you can: