Skip to main content

Overview

The Dynamic Kotlin SDK provides a comprehensive API for building Web3-enabled Android applications. This reference documents all the modules, functions, and types available in the SDK.

Requirements

  • Android API Level 26+
  • Kotlin 1.9+
  • Gradle 8.0+

Installation

// build.gradle.kts
dependencies {
    implementation("com.dynamic:android-sdk:VERSION")
}

SDK Architecture

The SDK uses a singleton pattern with modular access to different functionalities:
import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.DynamicSDKConfig

// Initialize at app launch (in Application or MainActivity)
DynamicSDK.initialize(
    context = applicationContext,
    config = DynamicSDKConfig(
        environmentId = "YOUR_ENV_ID"
    )
)

// Access SDK instance
val sdk = DynamicSDK.getInstance()

// Access modules
sdk.auth       // Authentication
sdk.wallets    // Wallet management
sdk.evm        // EVM chain operations
sdk.solana     // Solana operations
sdk.networks   // Available networks
sdk.mfa        // Multi-factor authentication
sdk.passkeys   // Passkey management
sdk.ui         // Built-in UI components

Core Modules

Initialization

// Initialize SDK (call once at app launch)
DynamicSDK.initialize(
    context = applicationContext,
    config = DynamicSDKConfig(
        environmentId = "YOUR_ENV_ID"
    )
)

// Get SDK instance
val sdk = DynamicSDK.getInstance()

Authentication (sdk.auth)

// Current user
val user = sdk.auth.authenticatedUser

// Auth token
val token = sdk.auth.token

// Reactive flows (Kotlin Coroutines)
sdk.auth.authenticatedUserChanges  // StateFlow<UserProfile?>
sdk.auth.tokenChanges              // StateFlow<String?>

// Logout
sdk.auth.logout()

// Email OTP
sdk.auth.email.sendOTP("[email protected]")
sdk.auth.email.verifyOTP("123456")
sdk.auth.email.resendOTP()

// SMS OTP
val phoneData = PhoneData(dialCode = "+1", iso2 = "US", phone = "5551234567")
sdk.auth.sms.sendOTP(phoneData)
sdk.auth.sms.verifyOTP("123456")
sdk.auth.sms.resendOTP()

// Social authentication
sdk.auth.social.connect(SocialAuthModule.SocialProvider.GOOGLE)
sdk.auth.social.connect(SocialAuthModule.SocialProvider.APPLE)
sdk.auth.social.connect(SocialAuthModule.SocialProvider.FARCASTER)

// Passkey authentication
sdk.auth.passkey.signIn()

// External JWT
sdk.auth.externalAuth.signInWithExternalJwt(
    SignInWithExternalJwtParams(jwt = "your-jwt")
)

Wallets (sdk.wallets)

// Current wallets
val wallets = sdk.wallets.userWallets  // List<BaseWallet>

// Reactive flow (Kotlin Coroutines)
sdk.wallets.userWalletsChanges  // StateFlow<List<BaseWallet>>

// Get balance
val balance = sdk.wallets.getBalance(wallet)

// Get current network
val network = sdk.wallets.getNetwork(wallet)

// Switch network
sdk.wallets.switchNetwork(wallet, targetNetwork)

// Set primary wallet
sdk.wallets.setPrimary(walletId)

// Sign message
val signature = sdk.wallets.signMessage(wallet, "Hello")

// Sign typed data (EIP-712)
val signature = sdk.wallets.signTypedData(wallet, typedDataJson)

// Verify signature
val isValid = sdk.wallets.verifySignature(
    wallet = wallet,
    message = "Hello",
    signature = signature
)

EVM Operations (sdk.evm)

// Create public client for chain
val client = sdk.evm.createPublicClient(chainId = 1)

// Get gas price
val gasPrice = client.getGasPrice()

// Send transaction
val transaction = EthereumTransaction(
    to = "0x...",
    value = "1000000000000000",  // Wei as String
    gasLimit = 21000,
    maxFeePerGas = gasPrice,
    maxPriorityFeePerGas = gasPrice
)
val txHash = sdk.evm.sendTransaction(wallet, transaction)

// Sign transaction (without sending)
val signedTx = sdk.evm.signTransaction(wallet, transaction)

// Write to contract
val input = WriteContractInput(
    address = "0x...",
    functionName = "transfer",
    args = listOf(recipient, amount),
    abi = listOf(/* ABI maps */)
)
val txHash = sdk.evm.writeContract(wallet, input)

Solana Operations (sdk.solana)

// Create connection
val connection = sdk.solana.createConnection()

// Get latest blockhash
val blockhashResult = connection.getLatestBlockhash()
val blockhash = blockhashResult.blockhash

// Create signer
val signer = sdk.solana.createSigner(wallet)

// Sign message
val signature = signer.signMessage("Hello")

// Sign transaction
val signedTx = signer.signEncodedTransaction(base64Transaction)

// Sign and send transaction
val signature = signer.signAndSendEncodedTransaction(base64Transaction)

Networks (sdk.networks)

// Available EVM networks
val evmNetworks = sdk.networks.evm  // List<GenericNetwork>

// Available Solana networks
val solanaNetworks = sdk.networks.solana  // List<GenericNetwork>

// Network properties
network.name        // String
network.chainId     // For EVM
network.networkId   // For Solana

MFA (sdk.mfa)

// Get user devices
val devices = sdk.mfa.getUserDevices()

// Add TOTP device (returns MfaAddDevice with secret)
val device = sdk.mfa.addDevice("totp")

// Verify device
sdk.mfa.verifyDevice("123456", "totp")

// Authenticate device to get MFA token
val token = sdk.mfa.authenticateDevice(
    MfaAuthenticateDevice(
        code = "123456",
        deviceId = deviceId,
        createMfaToken = MfaCreateToken(singleUse = true)
    )
)

// Delete device (requires MFA token)
sdk.mfa.deleteUserDevice(deviceId, mfaAuthToken = token)

// Recovery codes
val codes = sdk.mfa.getRecoveryCodes(generateNewCodes = false)
sdk.mfa.acknowledgeRecoveryCodes()  // Mark codes as shown to user
sdk.mfa.authenticateRecoveryCode(recoveryCode)

Passkeys (sdk.passkeys)

// Get user's passkeys
val passkeys = sdk.passkeys.getPasskeys()

// Register new passkey
sdk.passkeys.registerPasskey()

// Authenticate with passkey for MFA
val response = sdk.passkeys.authenticatePasskeyMFA(
    createMfaToken = MfaCreateToken(singleUse = true),
    relatedOriginRpId = null
)

// Delete passkey
sdk.passkeys.deletePasskey(
    DeletePasskeyRequest(passkeyId = passkeyId)
)

// Passkey properties
passkey.id              // String - Unique identifier
passkey.createdAt       // String - Creation timestamp (ISO format)
passkey.lastUsedAt      // String? - Last authentication time
passkey.isDefault       // Boolean? - Whether this is the default passkey

Built-in UI (sdk.ui)

// Show authentication UI
sdk.ui.showAuth()

// Show user profile
sdk.ui.showUserProfile()

Data Types

DynamicSDKConfig

DynamicSDKConfig(
    environmentId: String      // Required
)

BaseWallet

wallet.address      // String - Wallet address
wallet.chain        // String - "EVM" or "SOL"
wallet.walletName   // String? - Wallet name
wallet.id           // String? - Wallet ID for API operations

UserProfile

user.userId         // String?
user.email          // String?
user.phoneNumber    // String?
// Additional properties available

PhoneData

PhoneData(
    dialCode: String,   // e.g., "+1"
    iso2: String,       // e.g., "US"
    phone: String       // Phone number without country code
)

WriteContractInput

WriteContractInput(
    address: String,
    functionName: String,
    args: List<Any>,
    abi: List<Map<String, Any>>
)

GenericNetwork

network.name            // String
network.chainId         // For EVM networks
network.networkId       // For Solana networks

Error Handling

All SDK functions can throw exceptions. Use Kotlin’s native error handling:
try {
    sdk.auth.email.verifyOTP(code)
} catch (e: Exception) {
    Log.e("Auth", "Error: ${e.message}")
}
For coroutine-based code:
viewModelScope.launch {
    try {
        sdk.auth.email.sendOTP(email)
    } catch (e: Exception) {
        errorMessage.value = "Failed: ${e.message}"
    }
}

Quick Reference Example

import com.dynamic.sdk.android.DynamicSDK
import com.dynamic.sdk.android.DynamicSDKConfig
import android.app.Application

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        DynamicSDK.initialize(
            context = applicationContext,
            config = DynamicSDKConfig(
                environmentId = "YOUR_ENV_ID"
            )
        )
    }
}

// In your MainActivity
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MyApp()
        }
    }
}

@Composable
fun MyApp() {
    val sdk = DynamicSDK.getInstance()
    var isAuthenticated by remember {
        mutableStateOf(sdk.auth.authenticatedUser != null)
    }

    LaunchedEffect(Unit) {
        sdk.auth.authenticatedUserChanges.collect { user ->
            isAuthenticated = user != null
        }
    }

    if (isAuthenticated) {
        HomeScreen()
    } else {
        LoginScreen()
    }
}

@Composable
fun LoginScreen() {
    val sdk = DynamicSDK.getInstance()

    Button(onClick = { sdk.ui.showAuth() }) {
        Text("Sign In")
    }
}

@Composable
fun HomeScreen() {
    val sdk = DynamicSDK.getInstance()

    Column {
        Text("Welcome!")

        Button(onClick = { sdk.ui.showUserProfile() }) {
            Text("View Profile")
        }

        Button(onClick = {
            try {
                sdk.auth.logout()
            } catch (e: Exception) {
                Log.e("Home", "Logout failed: ${e.message}")
            }
        }) {
            Text("Logout")
        }
    }
}

Session State Management with ViewModel

For production apps, use a ViewModel for better state management:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dynamic.sdk.android.DynamicSDK
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class SessionViewModel : ViewModel() {
    private val sdk = DynamicSDK.getInstance()

    private val _isAuthenticated = MutableStateFlow(
        sdk.auth.authenticatedUser != null
    )
    val isAuthenticated: StateFlow<Boolean> = _isAuthenticated.asStateFlow()

    init {
        // Observe authentication changes
        viewModelScope.launch {
            sdk.auth.authenticatedUserChanges.collect { user ->
                _isAuthenticated.value = user != null
            }
        }
    }

    fun logout() {
        viewModelScope.launch {
            try {
                sdk.auth.logout()
            } catch (e: Exception) {
                Log.e("SessionVM", "Logout failed: ${e.message}")
            }
        }
    }
}

// Use in Compose
@Composable
fun AppContent() {
    val viewModel: SessionViewModel = viewModel()
    val isAuthenticated by viewModel.isAuthenticated.collectAsState()

    if (isAuthenticated) {
        HomeScreen()
    } else {
        LoginScreen()
    }
}
Complete Example App: For a fully functional Android app demonstrating all SDK features, check the Screens directory in the documentation repository for complete implementation examples.