---
# System prepended metadata

title: BitChat + Solana Android MVP Implementation Plan

---

# BitChat + Solana Android MVP Implementation Plan

**Version**: 1.0
**Date**: February 2026
**Platform**: Android (Kotlin + Jetpack Compose)
**Approach**: Offline Transaction Creation + Delayed Broadcasting (Approach 1)
**Base Repository**: https://github.com/permissionlesstech/bitchat-android

---

## Executive Summary

This document outlines a detailed implementation plan for integrating Solana blockchain transfers into the BitChat Android application. The MVP will enable users to:

1. Create and sign Solana transactions offline
2. Transfer signed transactions via Bluetooth mesh
3. Queue transactions for broadcasting when internet is available
4. Confirm on-chain settlement and notify users

**Core Value Proposition**: The only Android solution enabling offline Solana transaction creation with secure peer-to-peer transfer via Bluetooth mesh networking.

---

## Table of Contents

1. [Architecture Overview](#architecture-overview)
2. [Technology Stack](#technology-stack)
3. [Core Components](#core-components)
4. [Implementation Phases](#implementation-phases)
5. [File Structure](#file-structure)
6. [Detailed Component Specifications](#detailed-component-specifications)
7. [Data Flow & Protocols](#data-flow--protocols)
8. [Security Implementation](#security-implementation)
9. [Testing Strategy](#testing-strategy)
10. [Deployment Plan](#deployment-plan)
11. [Success Metrics](#success-metrics)
12. [Risk Mitigation](#risk-mitigation)

---

## Architecture Overview

### System Architecture Diagram

```
┌─────────────────────────────────────────────────────────────┐
│                    UI Layer (Jetpack Compose)                │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Wallet     │  │ Transaction  │  │   Message    │      │
│  │   Screen     │  │    Screen    │  │    Screen    │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
                            │
┌─────────────────────────────────────────────────────────────┐
│                  ViewModel Layer (MVVM Pattern)              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              ChatViewModel (Extended)                 │   │
│  │  - StateFlow for reactive UI updates                 │   │
│  │  - Wallet state management                            │   │
│  │  - Transaction lifecycle coordination                 │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                            │
┌─────────────────────────────────────────────────────────────┐
│                      Service Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Solana     │  │ Transaction  │  │  Broadcast   │      │
│  │   Wallet     │  │   Protocol   │  │   Service    │      │
│  │   Service    │  │   Service    │  │              │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
                            │
┌─────────────────────────────────────────────────────────────┐
│              Existing BitChat Infrastructure                 │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │  Bluetooth   │  │  Encryption  │  │    Binary    │      │
│  │    Mesh      │  │   Service    │  │   Protocol   │      │
│  │   Service    │  │ (BouncyCastle)│  │              │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
                            │
┌─────────────────────────────────────────────────────────────┐
│                    External Systems                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Solana     │  │  Encrypted   │  │  Bluetooth   │      │
│  │     RPC      │  │   Shared     │  │     LE       │      │
│  │              │  │ Preferences  │  │              │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘
```

### Key Architectural Principles

1. **MVVM Pattern**: Clear separation between UI (Compose), ViewModel (state), and Services (business logic)
2. **Kotlin Coroutines**: Async operations using coroutines and Flow
3. **Dependency Injection**: Hilt for service management
4. **Protocol Extension**: Extend BitChat's binary protocol without breaking existing functionality
5. **Security First**: EncryptedSharedPreferences + Android Keystore for secure key storage
6. **Modern Solana Patterns**: Use Solana Kotlin SDK with modern patterns

---

## Technology Stack

### Android Requirements

- **Minimum SDK**: API 26 (Android 8.0 Oreo) - Same as BitChat
- **Target SDK**: API 34 (Android 14)
- **Compile SDK**: API 34
- **Kotlin**: 1.9.0+
- **Gradle**: 8.0+
- **Java Version**: 17

---

### Core Dependencies

```kotlin
// app/build.gradle.kts

dependencies {
    // ===== EXISTING BITCHAT DEPENDENCIES =====

    // Jetpack Compose
    implementation("androidx.compose.ui:ui:1.6.0")
    implementation("androidx.compose.material3:material3:1.2.0")
    implementation("androidx.compose.ui:ui-tooling-preview:1.6.0")
    implementation("androidx.activity:activity-compose:1.8.2")

    // Lifecycle & ViewModel
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")

    // Bluetooth
    implementation("no.nordicsemi.android:ble:2.7.0")
    implementation("no.nordicsemi.android:ble-ktx:2.7.0")

    // Cryptography
    implementation("org.bouncycastle:bcprov-jdk15on:1.70")

    // Encrypted Storage
    implementation("androidx.security:security-crypto:1.1.0-alpha06")

    // Coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")

    // DataStore
    implementation("androidx.datastore:datastore-preferences:1.0.0")

    // ===== NEW SOLANA DEPENDENCIES =====

    // Solana Kotlin SDK (choose one based on availability)

    // Option 1: Solana Mobile Kotlin (if available)
    implementation("com.solanamobile:solana-kotlin:0.2.5")

    // Option 2: Solana4k (community library)
    implementation("com.github.metaplex-foundation:solana4k:1.0.0")

    // Option 3: Web3j for Solana (if needed)
    implementation("org.web3j:core:5.0.0")

    // For this plan, we'll use Solana Mobile's Kotlin SDK

    // Base58 encoding
    implementation("com.github.komputing:kbase58:0.1")

    // Ed25519 signing (if not in Solana SDK)
    implementation("net.i2p.crypto:eddsa:0.3.0")

    // BIP39 Mnemonic
    implementation("cash.z.ecc.android:kotlin-bip39:1.0.7")

    // QR Code generation
    implementation("com.google.zxing:core:3.5.2")
    implementation("com.journeyapps:zxing-android-embedded:4.3.0")

    // JSON serialization
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")

    // Network monitoring
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")

    // Hilt for Dependency Injection
    implementation("com.google.dagger:hilt-android:2.50")
    kapt("com.google.dagger:hilt-compiler:2.50")
    implementation("androidx.hilt:hilt-navigation-compose:1.1.0")

    // Testing
    testImplementation("junit:junit:4.13.2")
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
    androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0")
}

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.plugin.serialization")
    id("com.google.dagger.hilt.android")
    kotlin("kapt")
}
```

---

## Core Components

### 1. SolanaWalletService

**Responsibility**: Manage Solana keypairs, balance tracking, and wallet state

**Key Functions:**
- Generate new Solana keypair
- Import/export seed phrase (BIP39)
- Securely store private key in Android Keystore
- Fetch SOL balance from RPC
- Derive wallet address (base58 encoded public key)

---

### 2. TransactionProtocolService

**Responsibility**: Extend BitChat's binary protocol for Solana transactions

**New Message Types:**
- `0x30`: Solana Transaction Packet
- `0x31`: Transaction Delivery Acknowledgment
- `0x32`: Transaction Broadcast Confirmation
- `0x33`: Transaction Status Update

**Packet Structure:**
```kotlin
data class SolanaTransactionPacket(
    val version: Byte = 0x01,
    val transactionType: TransactionType,
    val serializedTransaction: ByteArray,
    val senderAddress: String,
    val recipientAddress: String,
    val amount: Long, // lamports
    val timestamp: Int,
    val flags: TransactionFlags,
    val signature: ByteArray // Ed25519 64 bytes
)

enum class TransactionType(val value: Byte) {
    SOL_TRANSFER(0x00),
    TOKEN_TRANSFER(0x01),
    NFT_TRANSFER(0x02)
}

@JvmInline
value class TransactionFlags(val value: Byte) {
    companion object {
        const val REQUIRES_BLOCKHASH_UPDATE: Byte = 0b00000001
        const val PRIORITY_FEE_ENABLED: Byte = 0b00000010
    }
}
```

---

### 3. BroadcastService

**Responsibility**: Queue and broadcast transactions to Solana network

**Key Functions:**
- Queue transactions for broadcasting
- Monitor internet connectivity
- Fetch recent blockhash when broadcasting
- Submit transaction to RPC endpoint
- Poll for confirmation
- Retry failed transactions with exponential backoff
- Emit status updates via Bluetooth

**Queue Persistence:**
- Store queued transactions in Room database
- Survive app restarts
- TTL: 24 hours default

---

### 4. Transaction UI Components (Jetpack Compose)

**Screens:**
- `WalletScreen` - Balance, address, transaction history
- `SendTransactionScreen` - Amount input, recipient selection
- `ReceiveScreen` - QR code, address display
- `TransactionHistoryScreen` - List of transactions with status

---

## Implementation Phases

### Phase 0: Setup & Foundation (Week 1)

**Goals:**
- Set up development environment
- Install Solana dependencies
- Create feature branch
- Design database schema extensions

**Deliverables:**
1. Feature branch: `feature/solana-integration`
2. Updated `build.gradle.kts` with Solana dependencies
3. Room database entities for wallet and transactions
4. Development RPC endpoint configuration (Devnet)

**Tasks:**

#### Task 0.1: Update Dependencies

```kotlin
// app/build.gradle.kts
android {
    namespace = "com.bitchat.android"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.bitchat.android"
        minSdk = 26
        targetSdk = 34
        versionCode = 1
        versionName = "1.0.0-solana-beta"
    }

    buildFeatures {
        compose = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.8"
    }
}
```

#### Task 0.2: Create Database Schema

```kotlin
// data/local/SolanaDatabase.kt
package com.bitchat.android.data.local

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters

@Database(
    entities = [
        WalletEntity::class,
        QueuedTransactionEntity::class
    ],
    version = 1,
    exportSchema = false
)
@TypeConverters(Converters::class)
abstract class SolanaDatabase : RoomDatabase() {
    abstract fun walletDao(): WalletDao
    abstract fun transactionDao(): TransactionDao
}

// data/local/entities/WalletEntity.kt
@Entity(tableName = "wallets")
data class WalletEntity(
    @PrimaryKey val publicKey: String,
    val createdAt: Long,
    val lastBalanceUpdate: Long,
    val balanceLamports: Long
)

// data/local/entities/QueuedTransactionEntity.kt
@Entity(tableName = "queued_transactions")
data class QueuedTransactionEntity(
    @PrimaryKey val id: String,
    val serializedTransaction: ByteArray,
    val senderAddress: String,
    val recipientAddress: String,
    val amount: Long,
    val timestamp: Long,
    val status: String,
    val requiresBlockhashUpdate: Boolean,
    val retryCount: Int = 0,
    val signature: String? = null
)
```

#### Task 0.3: Set Up Hilt Dependency Injection

```kotlin
// BitchatApplication.kt
package com.bitchat.android

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class BitchatApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // Existing initialization
    }
}

// di/SolanaModule.kt
package com.bitchat.android.di

import android.content.Context
import androidx.room.Room
import com.bitchat.android.data.local.SolanaDatabase
import com.bitchat.android.solana.SolanaWalletService
import com.bitchat.android.solana.SolanaRpcService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object SolanaModule {

    @Provides
    @Singleton
    fun provideSolanaDatabase(@ApplicationContext context: Context): SolanaDatabase {
        return Room.databaseBuilder(
            context,
            SolanaDatabase::class.java,
            "solana_database"
        ).build()
    }

    @Provides
    @Singleton
    fun provideSolanaRpcService(): SolanaRpcService {
        return SolanaRpcService(cluster = Cluster.DEVNET)
    }

    @Provides
    @Singleton
    fun provideSolanaWalletService(
        @ApplicationContext context: Context,
        rpcService: SolanaRpcService
    ): SolanaWalletService {
        return SolanaWalletService(context, rpcService)
    }
}
```

**Phase 0 Deliverables:**
- [ ] Updated `build.gradle.kts` with dependencies
- [ ] Room database schema created
- [ ] Hilt modules configured
- [ ] Development environment verified
- [ ] Devnet RPC endpoint tested

---

### Phase 1: Wallet Foundation (Week 2)

**Goals:**
- Implement basic wallet generation and storage
- Display wallet address and balance
- Test secure key storage

**Components to Build:**

#### 1.1 SolanaWalletService.kt

```kotlin
// solana/SolanaWalletService.kt
package com.bitchat.android.solana

import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.solanamobile.seedvault.WalletContractV1
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import org.bitcoinj.crypto.MnemonicCode
import org.bitcoinj.crypto.HDKeyDerivation
import java.security.Security
import org.bouncycastle.jce.provider.BouncyCastleProvider

class SolanaWalletService(
    private val context: Context,
    private val rpcService: SolanaRpcService
) {
    companion object {
        private const val KEYSTORE_ALIAS = "bitchat_solana_wallet"
        private const val PREFS_NAME = "bitchat_solana_prefs"
        private const val KEY_PUBLIC_ADDRESS = "public_address"
        private const val KEY_ENCRYPTED_SEED = "encrypted_seed"
        private const val KEY_MNEMONIC = "mnemonic"
    }

    init {
        // Add BouncyCastle provider if not already added
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(BouncyCastleProvider())
        }
    }

    private val _walletState = MutableStateFlow<WalletState>(WalletState.Uninitialized)
    val walletState: StateFlow<WalletState> = _walletState.asStateFlow()

    private val _balance = MutableStateFlow(0L)
    val balance: StateFlow<Long> = _balance.asStateFlow()

    private val encryptedPrefs by lazy {
        val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        EncryptedSharedPreferences.create(
            context,
            PREFS_NAME,
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }

    private val keyStore: KeyStore by lazy {
        KeyStore.getInstance("AndroidKeyStore").apply {
            load(null)
        }
    }

    /**
     * Generate a new Solana wallet
     */
    suspend fun generateWallet(): Result<WalletInfo> {
        return try {
            // 1. Generate BIP39 mnemonic (24 words)
            val entropy = ByteArray(32).apply {
                java.security.SecureRandom().nextBytes(this)
            }
            val mnemonic = MnemonicCode.INSTANCE.toMnemonic(entropy)
            val mnemonicPhrase = mnemonic.joinToString(" ")

            // 2. Derive seed from mnemonic
            val seed = MnemonicCode.toSeed(mnemonic, "")

            // 3. Derive Solana keypair (BIP44: m/44'/501'/0'/0')
            val masterKey = HDKeyDerivation.createMasterPrivateKey(seed)
            val purposeKey = HDKeyDerivation.deriveChildKey(masterKey, 44 or HDKeyDerivation.HARDENED_BIT)
            val coinTypeKey = HDKeyDerivation.deriveChildKey(purposeKey, 501 or HDKeyDerivation.HARDENED_BIT)
            val accountKey = HDKeyDerivation.deriveChildKey(coinTypeKey, 0 or HDKeyDerivation.HARDENED_BIT)
            val changeKey = HDKeyDerivation.deriveChildKey(accountKey, 0)
            val addressKey = HDKeyDerivation.deriveChildKey(changeKey, 0)

            // 4. Extract private key (32 bytes for Ed25519)
            val privateKeyBytes = addressKey.privKeyBytes

            // 5. Derive public key using Ed25519
            val publicKeyBytes = derivePublicKey(privateKeyBytes)

            // 6. Convert to base58 address
            val publicAddress = Base58.encode(publicKeyBytes)

            // 7. Encrypt and store private key
            val encryptedSeed = encryptSeed(privateKeyBytes)

            encryptedPrefs.edit().apply {
                putString(KEY_PUBLIC_ADDRESS, publicAddress)
                putString(KEY_ENCRYPTED_SEED, encryptedSeed)
                putString(KEY_MNEMONIC, mnemonicPhrase)
            }.apply()

            // 8. Update state
            val walletInfo = WalletInfo(
                publicKey = publicAddress,
                mnemonic = mnemonicPhrase
            )

            _walletState.value = WalletState.Initialized(walletInfo)

            // 9. Start balance monitoring
            startBalanceMonitoring()

            Result.success(walletInfo)

        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    /**
     * Load existing wallet from storage
     */
    suspend fun loadWallet(): Result<WalletInfo> {
        return try {
            val publicAddress = encryptedPrefs.getString(KEY_PUBLIC_ADDRESS, null)
                ?: return Result.failure(WalletException.NoWalletFound)

            val mnemonic = encryptedPrefs.getString(KEY_MNEMONIC, null)
                ?: return Result.failure(WalletException.NoMnemonicFound)

            val walletInfo = WalletInfo(
                publicKey = publicAddress,
                mnemonic = mnemonic
            )

            _walletState.value = WalletState.Initialized(walletInfo)

            startBalanceMonitoring()

            Result.success(walletInfo)

        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    /**
     * Get current SOL balance
     */
    suspend fun refreshBalance() {
        val currentState = _walletState.value
        if (currentState !is WalletState.Initialized) return

        try {
            val balanceLamports = rpcService.getBalance(currentState.walletInfo.publicKey)
            _balance.value = balanceLamports
        } catch (e: Exception) {
            // Log error but don't crash
            e.printStackTrace()
        }
    }

    /**
     * Sign a Solana transaction
     */
    suspend fun signTransaction(transaction: ByteArray): Result<ByteArray> {
        return try {
            val encryptedSeed = encryptedPrefs.getString(KEY_ENCRYPTED_SEED, null)
                ?: return Result.failure(WalletException.NoKeypairFound)

            val privateKeyBytes = decryptSeed(encryptedSeed)

            // Sign with Ed25519
            val signature = signWithEd25519(transaction, privateKeyBytes)

            Result.success(signature)

        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    /**
     * Export seed phrase (requires user authentication)
     */
    fun exportSeedPhrase(): Result<String> {
        return try {
            val mnemonic = encryptedPrefs.getString(KEY_MNEMONIC, null)
                ?: return Result.failure(WalletException.NoMnemonicFound)

            Result.success(mnemonic)

        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    // MARK: - Private Methods

    private fun derivePublicKey(privateKey: ByteArray): ByteArray {
        // Use BouncyCastle for Ed25519 key derivation
        val keyFactory = java.security.KeyFactory.getInstance("Ed25519", "BC")
        val privateKeySpec = org.bouncycastle.jce.spec.ECPrivateKeySpec(
            java.math.BigInteger(1, privateKey),
            org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec("Ed25519")
        )
        // ... implementation details for Ed25519 public key derivation
        // For production, use a library like TweetNaCl or Solana SDK's key derivation
        return ByteArray(32) // Placeholder
    }

    private fun encryptSeed(seed: ByteArray): String {
        // Get or create encryption key in Android Keystore
        val secretKey = getOrCreateSecretKey()

        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        cipher.init(Cipher.ENCRYPT_MODE, secretKey)

        val iv = cipher.iv
        val encryptedBytes = cipher.doFinal(seed)

        // Combine IV + encrypted data
        val combined = iv + encryptedBytes
        return android.util.Base64.encodeToString(combined, android.util.Base64.DEFAULT)
    }

    private fun decryptSeed(encryptedData: String): ByteArray {
        val secretKey = getOrCreateSecretKey()

        val combined = android.util.Base64.decode(encryptedData, android.util.Base64.DEFAULT)

        // Extract IV (first 12 bytes for GCM)
        val iv = combined.sliceArray(0 until 12)
        val encryptedBytes = combined.sliceArray(12 until combined.size)

        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, iv))

        return cipher.doFinal(encryptedBytes)
    }

    private fun getOrCreateSecretKey(): SecretKey {
        return if (keyStore.containsAlias(KEYSTORE_ALIAS)) {
            keyStore.getKey(KEYSTORE_ALIAS, null) as SecretKey
        } else {
            val keyGenerator = KeyGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_AES,
                "AndroidKeyStore"
            )

            val spec = KeyGenParameterSpec.Builder(
                KEYSTORE_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
            )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .setUserAuthenticationRequired(false) // Change to true for biometric
                .build()

            keyGenerator.init(spec)
            keyGenerator.generateKey()
        }
    }

    private fun signWithEd25519(message: ByteArray, privateKey: ByteArray): ByteArray {
        // Use BouncyCastle or TweetNaCl for Ed25519 signing
        // Placeholder implementation
        return ByteArray(64) // Ed25519 signatures are 64 bytes
    }

    private suspend fun startBalanceMonitoring() {
        // Poll balance every 10 seconds
        kotlinx.coroutines.GlobalScope.launch {
            while (true) {
                refreshBalance()
                kotlinx.coroutines.delay(10_000)
            }
        }
    }
}

// MARK: - Data Classes

data class WalletInfo(
    val publicKey: String,
    val mnemonic: String
)

sealed class WalletState {
    object Uninitialized : WalletState()
    data class Initialized(val walletInfo: WalletInfo) : WalletState()
    data class Error(val exception: Exception) : WalletState()
}

sealed class WalletException : Exception() {
    object NoWalletFound : WalletException()
    object NoMnemonicFound : WalletException()
    object NoKeypairFound : WalletException()
}
```

#### 1.2 SolanaRpcService.kt

```kotlin
// solana/SolanaRpcService.kt
package com.bitchat.android.solana

import com.google.gson.Gson
import com.google.gson.JsonObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.util.concurrent.TimeUnit

enum class Cluster(val url: String, val wsUrl: String) {
    MAINNET(
        "https://api.mainnet-beta.solana.com",
        "wss://api.mainnet-beta.solana.com"
    ),
    DEVNET(
        "https://api.devnet.solana.com",
        "wss://api.devnet.solana.com"
    ),
    TESTNET(
        "https://api.testnet.solana.com",
        "wss://api.testnet.solana.com"
    )
}

class SolanaRpcService(
    private val cluster: Cluster = Cluster.DEVNET
) {
    private val client = OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()

    private val gson = Gson()
    private val mediaType = "application/json".toMediaType()

    /**
     * Get SOL balance for a public key
     */
    suspend fun getBalance(publicKey: String): Long = withContext(Dispatchers.IO) {
        val requestBody = buildJsonRpcRequest(
            method = "getBalance",
            params = listOf(publicKey)
        )

        val response = executeRequest(requestBody)
        val result = response.getAsJsonObject("result")
        result.get("value").asLong
    }

    /**
     * Get recent blockhash
     */
    suspend fun getRecentBlockhash(): String = withContext(Dispatchers.IO) {
        val requestBody = buildJsonRpcRequest(
            method = "getLatestBlockhash",
            params = listOf(
                mapOf("commitment" to "confirmed")
            )
        )

        val response = executeRequest(requestBody)
        val value = response.getAsJsonObject("result").getAsJsonObject("value")
        value.get("blockhash").asString
    }

    /**
     * Send a signed transaction
     */
    suspend fun sendTransaction(
        signedTransaction: String,
        encoding: String = "base64"
    ): String = withContext(Dispatchers.IO) {
        val requestBody = buildJsonRpcRequest(
            method = "sendTransaction",
            params = listOf(
                signedTransaction,
                mapOf(
                    "encoding" to encoding,
                    "preflightCommitment" to "confirmed"
                )
            )
        )

        val response = executeRequest(requestBody)
        response.get("result").asString
    }

    /**
     * Confirm transaction
     */
    suspend fun confirmTransaction(
        signature: String,
        timeout: Long = 30_000
    ): Boolean = withContext(Dispatchers.IO) {
        val startTime = System.currentTimeMillis()

        while (System.currentTimeMillis() - startTime < timeout) {
            val requestBody = buildJsonRpcRequest(
                method = "getSignatureStatuses",
                params = listOf(listOf(signature))
            )

            val response = executeRequest(requestBody)
            val value = response.getAsJsonObject("result").getAsJsonArray("value")

            if (value.size() > 0 && !value[0].isJsonNull) {
                val status = value[0].asJsonObject
                val confirmationStatus = status.get("confirmationStatus")?.asString

                if (confirmationStatus == "confirmed" || confirmationStatus == "finalized") {
                    return@withContext true
                }
            }

            kotlinx.coroutines.delay(1000) // Poll every 1 second
        }

        false
    }

    // MARK: - Private Methods

    private fun buildJsonRpcRequest(method: String, params: List<Any>): String {
        val request = JsonObject().apply {
            addProperty("jsonrpc", "2.0")
            addProperty("id", 1)
            addProperty("method", method)
            add("params", gson.toJsonTree(params))
        }

        return gson.toJson(request)
    }

    private fun executeRequest(jsonBody: String): JsonObject {
        val requestBody = jsonBody.toRequestBody(mediaType)

        val request = Request.Builder()
            .url(cluster.url)
            .post(requestBody)
            .build()

        client.newCall(request).execute().use { response ->
            if (!response.isSuccessful) {
                throw RpcException("RPC request failed: ${response.code}")
            }

            val responseBody = response.body?.string()
                ?: throw RpcException("Empty response body")

            val jsonResponse = gson.fromJson(responseBody, JsonObject::class.java)

            if (jsonResponse.has("error")) {
                val error = jsonResponse.getAsJsonObject("error")
                throw RpcException("RPC error: ${error.get("message").asString}")
            }

            return jsonResponse
        }
    }
}

class RpcException(message: String) : Exception(message)
```

#### 1.3 WalletScreen.kt (Jetpack Compose UI)

```kotlin
// ui/screens/WalletScreen.kt
package com.bitchat.android.ui.screens

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.bitchat.android.solana.WalletState
import com.bitchat.android.viewmodels.WalletViewModel

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WalletScreen(
    viewModel: WalletViewModel = hiltViewModel()
) {
    val walletState by viewModel.walletState.collectAsState()
    val balance by viewModel.balance.collectAsState()

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Solana Wallet") },
                actions = {
                    IconButton(onClick = { /* Settings */ }) {
                        Icon(Icons.Default.Settings, "Settings")
                    }
                }
            )
        }
    ) { paddingValues ->
        when (val state = walletState) {
            is WalletState.Uninitialized -> {
                WalletOnboarding(
                    onCreateWallet = { viewModel.createWallet() },
                    onImportWallet = { /* TODO */ },
                    modifier = Modifier.padding(paddingValues)
                )
            }

            is WalletState.Initialized -> {
                WalletDashboard(
                    walletInfo = state.walletInfo,
                    balance = balance,
                    onSend = { /* Navigate to send screen */ },
                    onReceive = { /* Navigate to receive screen */ },
                    modifier = Modifier.padding(paddingValues)
                )
            }

            is WalletState.Error -> {
                ErrorScreen(
                    error = state.exception,
                    modifier = Modifier.padding(paddingValues)
                )
            }
        }
    }
}

@Composable
fun WalletOnboarding(
    onCreateWallet: () -> Unit,
    onImportWallet: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .fillMaxSize()
            .padding(24.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Icon(
            imageVector = Icons.Default.AccountBalanceWallet,
            contentDescription = null,
            modifier = Modifier.size(100.dp),
            tint = MaterialTheme.colorScheme.primary
        )

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

        Text(
            text = "Create Your Solana Wallet",
            style = MaterialTheme.typography.headlineMedium
        )

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

        Text(
            text = "Your wallet will be secured with your device's encryption",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )

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

        Button(
            onClick = onCreateWallet,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Create Wallet")
        }

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

        OutlinedButton(
            onClick = onImportWallet,
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Import Existing Wallet")
        }
    }
}

@Composable
fun WalletDashboard(
    walletInfo: com.bitchat.android.solana.WalletInfo,
    balance: Long,
    onSend: () -> Unit,
    onReceive: () -> Unit,
    modifier: Modifier = Modifier
) {
    val clipboardManager = LocalClipboardManager.current

    Column(
        modifier = modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        // Balance Card
        Card(
            modifier = Modifier.fillMaxWidth(),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.primaryContainer
            )
        ) {
            Column(
                modifier = Modifier.padding(24.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = "Balance",
                    style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.onPrimaryContainer
                )

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

                Text(
                    text = formatBalance(balance),
                    style = MaterialTheme.typography.displayMedium,
                    color = MaterialTheme.colorScheme.onPrimaryContainer
                )

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

                Text(
                    text = "SOL",
                    style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.onPrimaryContainer
                )

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

                // Address
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.clickable {
                        clipboardManager.setText(AnnotatedString(walletInfo.publicKey))
                    }
                ) {
                    Text(
                        text = truncateAddress(walletInfo.publicKey),
                        style = MaterialTheme.typography.bodySmall.copy(
                            fontFamily = FontFamily.Monospace
                        ),
                        color = MaterialTheme.colorScheme.onPrimaryContainer
                    )

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

                    Icon(
                        imageVector = Icons.Default.ContentCopy,
                        contentDescription = "Copy",
                        modifier = Modifier.size(16.dp),
                        tint = MaterialTheme.colorScheme.onPrimaryContainer
                    )
                }
            }
        }

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

        // Action Buttons
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            OutlinedButton(
                onClick = onReceive,
                modifier = Modifier.weight(1f)
            ) {
                Icon(Icons.Default.QrCode, contentDescription = null)
                Spacer(modifier = Modifier.width(8.dp))
                Text("Receive")
            }

            Button(
                onClick = onSend,
                modifier = Modifier.weight(1f)
            ) {
                Icon(Icons.Default.Send, contentDescription = null)
                Spacer(modifier = Modifier.width(8.dp))
                Text("Send")
            }
        }

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

        // Transaction History
        Text(
            text = "Recent Transactions",
            style = MaterialTheme.typography.titleMedium
        )

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

        LazyColumn {
            item {
                Card(
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(32.dp),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(
                            text = "No transactions yet",
                            style = MaterialTheme.typography.bodyMedium,
                            color = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                    }
                }
            }
        }
    }
}

private fun formatBalance(lamports: Long): String {
    val sol = lamports / 1_000_000_000.0
    return String.format("%.4f", sol)
}

private fun truncateAddress(address: String): String {
    return if (address.length > 16) {
        "${address.take(8)}...${address.takeLast(8)}"
    } else {
        address
    }
}
```

#### 1.4 WalletViewModel.kt

```kotlin
// viewmodels/WalletViewModel.kt
package com.bitchat.android.viewmodels

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bitchat.android.solana.SolanaWalletService
import com.bitchat.android.solana.WalletState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class WalletViewModel @Inject constructor(
    private val walletService: SolanaWalletService
) : ViewModel() {

    val walletState: StateFlow<WalletState> = walletService.walletState
    val balance: StateFlow<Long> = walletService.balance

    init {
        // Try to load existing wallet on init
        viewModelScope.launch {
            walletService.loadWallet()
        }
    }

    fun createWallet() {
        viewModelScope.launch {
            walletService.generateWallet()
        }
    }

    fun refreshBalance() {
        viewModelScope.launch {
            walletService.refreshBalance()
        }
    }

    fun exportSeedPhrase(): Result<String> {
        return walletService.exportSeedPhrase()
    }
}
```

**Phase 1 Deliverables:**
- [ ] `SolanaWalletService.kt` - Wallet management
- [ ] `SolanaRpcService.kt` - RPC communication
- [ ] `WalletScreen.kt` - Wallet UI (Jetpack Compose)
- [ ] `WalletViewModel.kt` - State management
- [ ] `ReceiveScreen.kt` - QR code for receiving
- [ ] Unit tests for wallet generation and key storage

**Phase 1 Success Criteria:**
- Can generate new wallet and store securely
- Can display wallet address and balance
- Can copy address to clipboard
- Balance refreshes automatically
- Seed phrase can be exported

---

### Phase 2: Transaction Creation (Week 3)

**Goals:**
- Build UI for creating transactions
- Implement transaction signing
- Serialize transactions for Bluetooth transfer

**Components to Build:**

#### 2.1 TransactionBuilder.kt

```kotlin
// solana/TransactionBuilder.kt
package com.bitchat.android.solana

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class TransactionBuilder(
    private val rpcService: SolanaRpcService
) {
    /**
     * Create a SOL transfer transaction
     */
    suspend fun createTransferTransaction(
        from: String,
        to: String,
        amountLamports: Long
    ): ByteArray = withContext(Dispatchers.Default) {
        // Note: This is a simplified version
        // In production, use Solana SDK's transaction builder

        // Get recent blockhash (will be updated before broadcast)
        val blockhash = rpcService.getRecentBlockhash()

        // Build transaction structure
        val transaction = SolanaTransaction(
            recentBlockhash = blockhash,
            feePayer = from,
            instructions = listOf(
                SystemProgramInstruction.transfer(
                    from = from,
                    to = to,
                    lamports = amountLamports
                )
            )
        )

        // Serialize to bytes
        transaction.serialize()
    }

    /**
     * Create transaction with priority fee
     */
    suspend fun createTransferTransactionWithPriorityFee(
        from: String,
        to: String,
        amountLamports: Long,
        priorityFeeMicroLamports: Long = 5000
    ): ByteArray = withContext(Dispatchers.Default) {
        val blockhash = rpcService.getRecentBlockhash()

        val transaction = SolanaTransaction(
            recentBlockhash = blockhash,
            feePayer = from,
            instructions = listOf(
                ComputeBudgetInstruction.setComputeUnitPrice(priorityFeeMicroLamports),
                SystemProgramInstruction.transfer(from, to, amountLamports)
            )
        )

        transaction.serialize()
    }
}

// Simplified transaction structure
data class SolanaTransaction(
    val recentBlockhash: String,
    val feePayer: String,
    val instructions: List<TransactionInstruction>
) {
    fun serialize(): ByteArray {
        // Implement Solana transaction serialization
        // This would use the actual Solana SDK in production
        return ByteArray(0) // Placeholder
    }
}

interface TransactionInstruction

object SystemProgramInstruction {
    fun transfer(from: String, to: String, lamports: Long): TransactionInstruction {
        return object : TransactionInstruction {}
    }
}

object ComputeBudgetInstruction {
    fun setComputeUnitPrice(microLamports: Long): TransactionInstruction {
        return object : TransactionInstruction {}
    }
}
```

#### 2.2 SendTransactionScreen.kt

```kotlin
// ui/screens/SendTransactionScreen.kt
package com.bitchat.android.ui.screens

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.bitchat.android.viewmodels.SendTransactionViewModel

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SendTransactionScreen(
    onNavigateBack: () -> Unit,
    viewModel: SendTransactionViewModel = hiltViewModel()
) {
    var recipientAddress by remember { mutableStateOf("") }
    var amount by remember { mutableStateOf("") }
    var usePriorityFee by remember { mutableStateOf(false) }
    var showConfirmDialog by remember { mutableStateOf(false) }

    val transactionStatus by viewModel.transactionStatus.collectAsState()

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Send SOL") },
                navigationIcon = {
                    IconButton(onClick = onNavigateBack) {
                        Icon(Icons.Default.ArrowBack, "Back")
                    }
                }
            )
        }
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            // Recipient Section
            Text(
                text = "Recipient",
                style = MaterialTheme.typography.titleMedium
            )

            OutlinedButton(
                onClick = { /* Show peer selection */ },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Select BitChat Peer")
            }

            Text(
                text = "Or enter address manually:",
                style = MaterialTheme.typography.bodySmall
            )

            OutlinedTextField(
                value = recipientAddress,
                onValueChange = { recipientAddress = it },
                modifier = Modifier.fillMaxWidth(),
                label = { Text("Solana Address") },
                singleLine = true
            )

            Divider()

            // Amount Section
            Text(
                text = "Amount",
                style = MaterialTheme.typography.titleMedium
            )

            OutlinedTextField(
                value = amount,
                onValueChange = { amount = it },
                modifier = Modifier.fillMaxWidth(),
                label = { Text("SOL") },
                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
                trailingIcon = { Text("SOL") }
            )

            // Quick amount buttons
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                listOf(0.1, 0.5, 1.0).forEach { value ->
                    FilledTonalButton(
                        onClick = { amount = value.toString() },
                        modifier = Modifier.weight(1f)
                    ) {
                        Text("$value SOL")
                    }
                }
            }

            Divider()

            // Fee Section
            Text(
                text = "Network Fee: ~0.000005 SOL",
                style = MaterialTheme.typography.bodyMedium
            )

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                Text("Priority Fee")
                Switch(
                    checked = usePriorityFee,
                    onCheckedChange = { usePriorityFee = it }
                )
            }

            Spacer(modifier = Modifier.weight(1f))

            // Send Button
            Button(
                onClick = { showConfirmDialog = true },
                modifier = Modifier.fillMaxWidth(),
                enabled = recipientAddress.isNotEmpty() && amount.toDoubleOrNull() != null
            ) {
                Text("Review Transaction")
            }
        }

        // Confirmation Dialog
        if (showConfirmDialog) {
            TransactionConfirmationDialog(
                recipient = recipientAddress,
                amount = amount.toDoubleOrNull() ?: 0.0,
                onConfirm = {
                    viewModel.createAndSendTransaction(
                        recipient = recipientAddress,
                        amount = amount.toDoubleOrNull() ?: 0.0,
                        usePriorityFee = usePriorityFee
                    )
                    showConfirmDialog = false
                },
                onDismiss = { showConfirmDialog = false }
            )
        }

        // Status snackbar
        LaunchedEffect(transactionStatus) {
            // Show status updates as snackbars
        }
    }
}

@Composable
fun TransactionConfirmationDialog(
    recipient: String,
    amount: Double,
    onConfirm: () -> Unit,
    onDismiss: () -> Unit
) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Confirm Transaction") },
        text = {
            Column {
                Text("Sending to:")
                Text(recipient, style = MaterialTheme.typography.bodySmall)
                Spacer(modifier = Modifier.height(8.dp))
                Text("Amount: $amount SOL")
                Text("Fee: ~0.000005 SOL")
                Spacer(modifier = Modifier.height(8.dp))
                Text("Total: ${amount + 0.000005} SOL", style = MaterialTheme.typography.titleMedium)
            }
        },
        confirmButton = {
            Button(onClick = onConfirm) {
                Text("Confirm & Send")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    )
}
```

**Phase 2 Deliverables:**
- [ ] `TransactionBuilder.kt` - Transaction creation
- [ ] `SendTransactionScreen.kt` - Send UI
- [ ] `SendTransactionViewModel.kt` - Transaction state management
- [ ] `PeerSelectionScreen.kt` - Select BitChat peer as recipient
- [ ] Unit tests for transaction creation and signing

**Phase 2 Success Criteria:**
- Can create SOL transfer transactions
- Can sign transactions with wallet keypair
- Transaction data is properly serialized
- UI shows clear transaction status
- Can select BitChat peers as recipients

---

### Phase 3: Protocol Extension (Week 4)

Same as iOS plan, but implemented in Kotlin for Android.

**Key Files:**
- Extend `BinaryProtocol.kt`
- `TransactionProtocolService.kt`
- Integration with existing `BluetoothMeshService.kt`

---

### Phase 4: Broadcast Queue (Week 5)

**Components:**
- `BroadcastQueue.kt` using Room database
- `NetworkMonitor.kt` using ConnectivityManager
- Background WorkManager tasks

---

### Phase 5: Testing & Polish (Week 6)

**Testing:**
- Unit tests with JUnit
- UI tests with Compose Testing
- Integration tests
- Manual testing on physical devices

---

## File Structure

```
bitchat-android/
├── app/src/main/
│   ├── kotlin/com/bitchat/android/
│   │   ├── BitchatApplication.kt          # Hilt entry point
│   │   │
│   │   ├── solana/                         # NEW: Solana integration
│   │   │   ├── SolanaWalletService.kt
│   │   │   ├── SolanaRpcService.kt
│   │   │   ├── TransactionBuilder.kt
│   │   │   ├── TransactionProtocolService.kt
│   │   │   ├── BroadcastQueue.kt
│   │   │   └── NetworkMonitor.kt
│   │   │
│   │   ├── data/
│   │   │   ├── local/
│   │   │   │   ├── SolanaDatabase.kt
│   │   │   │   ├── WalletDao.kt
│   │   │   │   ├── TransactionDao.kt
│   │   │   │   └── entities/
│   │   │   │       ├── WalletEntity.kt
│   │   │   │       └── QueuedTransactionEntity.kt
│   │   │   │
│   │   │   └── models/
│   │   │       ├── SolanaTransactionPacket.kt
│   │   │       └── TransactionStatus.kt
│   │   │
│   │   ├── ui/
│   │   │   ├── screens/
│   │   │   │   ├── WalletScreen.kt
│   │   │   │   ├── SendTransactionScreen.kt
│   │   │   │   ├── ReceiveScreen.kt
│   │   │   │   └── TransactionHistoryScreen.kt
│   │   │   │
│   │   │   └── components/
│   │   │       ├── BalanceCard.kt
│   │   │       └── TransactionListItem.kt
│   │   │
│   │   ├── viewmodels/
│   │   │   ├── WalletViewModel.kt
│   │   │   └── SendTransactionViewModel.kt
│   │   │
│   │   ├── di/                             # Hilt modules
│   │   │   ├── SolanaModule.kt
│   │   │   └── DatabaseModule.kt
│   │   │
│   │   ├── BluetoothMeshService.kt         # EXISTING (extend)
│   │   ├── EncryptionService.kt            # EXISTING
│   │   ├── BinaryProtocol.kt               # EXISTING (extend)
│   │   └── ChatViewModel.kt                # EXISTING (integrate)
│   │
│   └── res/
│       ├── values/
│       │   └── strings.xml
│       └── ...
│
└── app/build.gradle.kts                     # Dependencies
```

---

## Security Implementation

### Android Keystore Integration

```kotlin
// Security best practices for Android

class SecureKeyStorage(private val context: Context) {

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

    fun storePrivateKey(alias: String, privateKey: ByteArray) {
        // Use Android Keystore for hardware-backed encryption
        val secretKey = getOrCreateSecretKey(alias)

        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        cipher.init(Cipher.ENCRYPT_MODE, secretKey)

        val iv = cipher.iv
        val encryptedKey = cipher.doFinal(privateKey)

        // Store IV + encrypted key in EncryptedSharedPreferences
        val prefs = getEncryptedPreferences()
        prefs.edit()
            .putString("${alias}_iv", Base64.encodeToString(iv, Base64.DEFAULT))
            .putString("${alias}_key", Base64.encodeToString(encryptedKey, Base64.DEFAULT))
            .apply()
    }

    private fun getOrCreateSecretKey(alias: String): SecretKey {
        if (!keyStore.containsAlias(alias)) {
            val keyGenerator = KeyGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_AES,
                "AndroidKeyStore"
            )

            val spec = KeyGenParameterSpec.Builder(
                alias,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
            )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .setUserAuthenticationRequired(true) // Biometric required
                .setUserAuthenticationValidityDurationSeconds(30)
                .build()

            keyGenerator.init(spec)
            return keyGenerator.generateKey()
        }

        return keyStore.getKey(alias, null) as SecretKey
    }

    private fun getEncryptedPreferences(): SharedPreferences {
        val masterKey = MasterKey.Builder(context)
            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
            .build()

        return EncryptedSharedPreferences.create(
            context,
            "solana_secure_prefs",
            masterKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }
}
```

---

## Testing Strategy

### Unit Tests

```kotlin
// SolanaWalletServiceTest.kt
package com.bitchat.android.solana

import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.Assert.*

class SolanaWalletServiceTest {

    @Test
    fun `generateWallet creates valid keypair`() = runTest {
        val walletService = SolanaWalletService(context, rpcService)

        val result = walletService.generateWallet()

        assertTrue(result.isSuccess)
        val walletInfo = result.getOrNull()!!
        assertTrue(walletInfo.publicKey.length in 32..44)
        assertEquals(24, walletInfo.mnemonic.split(" ").size)
    }

    @Test
    fun `signTransaction produces valid signature`() = runTest {
        // Test transaction signing
    }
}
```

### UI Tests (Compose)

```kotlin
// WalletScreenTest.kt
@RunWith(AndroidJUnit4::class)
class WalletScreenTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun walletScreen_displaysBalance() {
        composeTestRule.setContent {
            WalletScreen()
        }

        composeTestRule.onNodeWithText("Balance").assertIsDisplayed()
    }
}
```

---

## Summary

This Android implementation plan mirrors the iOS plan but uses:
- **Kotlin** instead of Swift
- **Jetpack Compose** instead of SwiftUI
- **Room** instead of CoreData
- **Android Keystore** instead of iOS Keychain
- **Hilt** for dependency injection
- **Coroutines + Flow** for async operations

**Estimated Timeline**: 6-8 weeks for MVP with single Android developer

**Next Steps**: Start with Phase 0 to set up the foundation, then proceed through each phase systematically.

---

Would you like me to expand on any specific component or create additional code examples?
