Skip to main content

Android Quickstart

Get started with Privacy Boost in Android/Kotlin in 5 minutes.

Installation

Gradle

Add to your build.gradle.kts:
dependencies {
    implementation("io.privacy-boost:privacy-boost-android:1.0.0")
}
Or for Groovy (build.gradle):
dependencies {
    implementation 'io.privacy-boost:privacy-boost-android:1.0.0'
}

Quick Example

1. Create Wallet Delegate

import com.privacyboost.sdk.*

class MyWalletDelegate(private val wallet: YourWalletImplementation) : WalletDelegate {

    override suspend fun getAddress(): String {
        return wallet.address
    }

    override suspend fun getChainId(): ULong {
        return wallet.chainId.toULong()
    }

    override suspend fun signMessage(message: String): String {
        return wallet.sign(message)
    }

    override suspend fun signTypedData(typedData: String): String {
        return wallet.signTypedData(typedData)
    }

    override suspend fun sendTransaction(tx: TransactionRequest): String {
        return wallet.sendTransaction(tx)
    }
}

2. Initialize and Use SDK

import com.privacyboost.sdk.*
import kotlinx.coroutines.launch

// 1. Create configuration
val config = SdkConfig(
    indexerUrl = "https://test-api.privacy-boost.sunnyside.io/indexer",
    proverUrl = "https://test-api.privacy-boost.sunnyside.io/prover",
    chainId = 1UL,
    shieldContract = "0x1234567890123456789012345678901234567890"
)

// 2. Initialize SDK
val sdk = PrivacyBoostSdk(config)

// 3. Connect wallet (in a coroutine)
lifecycleScope.launch {
    val walletDelegate = MyWalletDelegate(wallet)
    val connectResult = sdk.connect(walletDelegate)
    println("Connected: ${connectResult.address}")

    // 4. Login
    val loginResult = sdk.login()
    println("Privacy address: ${loginResult.privacyAddress}")

    // 5. Check balance
    val balance = sdk.getBalance("0x...")
    println("Shielded: ${balance.shielded}")

    // 6. Deposit
    val depositParams = DepositParams(
        tokenAddress = "0x...",
        amount = "1000000000000000000" // 1 token
    )
    val depositResult = sdk.deposit(depositParams)
    println("Deposit tx: ${depositResult.txHash}")

    // 7. Transfer
    val transferParams = TransferParams(
        to = recipientPrivacyAddress,
        tokenAddress = "0x...",
        amount = "500000000000000000"
    )
    val transferResult = sdk.transfer(transferParams)
    println("Transfer tx: ${transferResult.txHash}")

    // 8. Withdraw
    val withdrawParams = WithdrawParams(
        tokenAddress = "0x...",
        amount = "250000000000000000",
        recipientAddress = "0x..."
    )
    val withdrawResult = sdk.withdraw(withdrawParams)
    println("Withdraw tx: ${withdrawResult.txHash}")
}

Jetpack Compose Example

import androidx.compose.runtime.*
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.privacyboost.sdk.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class WalletViewModel : ViewModel() {
    private val _isAuthenticated = MutableStateFlow(false)
    val isAuthenticated: StateFlow<Boolean> = _isAuthenticated

    private val _privacyAddress = MutableStateFlow<String?>(null)
    val privacyAddress: StateFlow<String?> = _privacyAddress

    private var sdk: PrivacyBoostSdk? = null

    fun connect(wallet: WalletDelegate) {
        viewModelScope.launch {
            try {
                val config = SdkConfig(/* ... */)
                sdk = PrivacyBoostSdk(config)

                sdk?.connect(wallet)
                val result = sdk?.login()

                _privacyAddress.value = result?.privacyAddress
                _isAuthenticated.value = true
            } catch (e: Exception) {
                println("Connection failed: ${e.message}")
            }
        }
    }

    fun deposit(tokenAddress: String, amount: String) {
        viewModelScope.launch {
            val params = DepositParams(tokenAddress, amount)
            sdk?.deposit(params)
        }
    }

    fun logout() {
        sdk?.logout()
        _isAuthenticated.value = false
        _privacyAddress.value = null
    }
}

@Composable
fun WalletScreen(viewModel: WalletViewModel = viewModel()) {
    val isAuthenticated by viewModel.isAuthenticated.collectAsState()
    val privacyAddress by viewModel.privacyAddress.collectAsState()

    Column {
        if (isAuthenticated) {
            Text("Privacy Address:")
            Text(privacyAddress ?: "", style = MaterialTheme.typography.caption)

            Button(onClick = {
                viewModel.deposit("0x...", "1000000000000000000")
            }) {
                Text("Deposit 1 Token")
            }

            Button(onClick = { viewModel.logout() }) {
                Text("Logout")
            }
        } else {
            Button(onClick = {
                viewModel.connect(MyWalletDelegate(wallet))
            }) {
                Text("Connect Wallet")
            }
        }
    }
}

Android Keystore

Store sessions securely:
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey

class SessionStorage(private val context: Context) {
    private val keyAlias = "privacy_session_key"

    fun saveSession(session: String) {
        val cipher = getCipher(Cipher.ENCRYPT_MODE)
        val encrypted = cipher.doFinal(session.toByteArray())

        context.getSharedPreferences("privacy_boost", Context.MODE_PRIVATE)
            .edit()
            .putString("session", Base64.encodeToString(encrypted, Base64.DEFAULT))
            .putString("iv", Base64.encodeToString(cipher.iv, Base64.DEFAULT))
            .apply()
    }

    fun loadSession(): String? {
        val prefs = context.getSharedPreferences("privacy_boost", Context.MODE_PRIVATE)
        val encrypted = prefs.getString("session", null) ?: return null
        val iv = prefs.getString("iv", null) ?: return null

        val cipher = getCipher(
            Cipher.DECRYPT_MODE,
            Base64.decode(iv, Base64.DEFAULT)
        )
        val decrypted = cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT))
        return String(decrypted)
    }

    private fun getCipher(mode: Int, iv: ByteArray? = null): Cipher {
        val key = getOrCreateKey()
        return Cipher.getInstance("AES/GCM/NoPadding").apply {
            if (iv != null) {
                init(mode, key, GCMParameterSpec(128, iv))
            } else {
                init(mode, key)
            }
        }
    }

    private fun getOrCreateKey(): SecretKey {
        val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }

        keyStore.getKey(keyAlias, null)?.let { return it as SecretKey }

        val keyGenerator = KeyGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_AES,
            "AndroidKeyStore"
        )
        keyGenerator.init(
            KeyGenParameterSpec.Builder(
                keyAlias,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
            )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build()
        )
        return keyGenerator.generateKey()
    }
}

Next Steps