Pull in foundation phoenix seed code.

This commit is contained in:
Kgothatso Ngako
2026-06-16 20:28:05 +03:00
parent 11272f51b5
commit a825038c06
52 changed files with 1422 additions and 703 deletions

View File

@@ -12,6 +12,7 @@ import androidx.activity.enableEdgeToEdge
import androidx.navigation.compose.rememberNavController
import com.machankura.compose.ui.composable.widgets.nfc.NfcState
import com.machankura.compose.ui.composable.widgets.nfc.NfcStateRepository
import fr.acinq.phoenix.PhoenixGlobal
import fr.acinq.phoenix.android.services.HceService
class MainActivity : ComponentActivity() {
@@ -31,7 +32,13 @@ class MainActivity : ComponentActivity() {
platformContext = PlatformContext(
applicationContext = applicationContext
)
),
phoenixGlobal = PhoenixGlobal(
ctx = fr.acinq.phoenix.utils.PlatformContext(
applicationContext = applicationContext
)
)
)
}
}

View File

@@ -0,0 +1,33 @@
package ac.cord.auxiliary.compose.extensions
import ac.cord.auxiliary.android.InomboloApplication
import fr.acinq.phoenix.PhoenixGlobal
import fr.acinq.phoenix.android.BusinessManager
import fr.acinq.phoenix.android.services.ChannelsWatcher
import fr.acinq.phoenix.android.services.ContactsPhotoCleaner
import fr.acinq.phoenix.data.StartBusinessResult
import fr.acinq.phoenix.utils.preferences.GlobalPrefs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
actual suspend fun platformStartupLogic(words: List<String>): StartBusinessResult {
return withContext(Dispatchers.Default) {
BusinessManager.startNewBusiness(words, isHeadless = false)
}
}
actual fun schedulePlatformLogic(phoenixGlobal: PhoenixGlobal) {
ChannelsWatcher.schedule(phoenixGlobal.ctx.applicationContext)
ContactsPhotoCleaner.schedule(phoenixGlobal.ctx.applicationContext)
}
actual fun getShowIntroFlow(phoenixGlobal: PhoenixGlobal): Flow<Boolean> {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as InomboloApplication
return machankuraApplication.globalPrefs.getShowIntro
}
actual fun getGlobalPrefs(phoenixGlobal: PhoenixGlobal): GlobalPrefs {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as InomboloApplication
return machankuraApplication.globalPrefs
}

View File

@@ -0,0 +1,140 @@
package ac.cord.auxiliary.compose.ui.view.model
import ac.cord.auxiliary.android.InomboloApplication
import ac.cord.auxiliary.compose.AppVersion
import co.touchlab.kermit.Logger
import fr.acinq.bitcoin.MnemonicCode
import fr.acinq.lightning.crypto.LocalKeyManager
import fr.acinq.lightning.utils.toByteVector
import fr.acinq.phoenix.PhoenixGlobal
import fr.acinq.phoenix.android.BusinessManager
import fr.acinq.phoenix.data.DecryptSeedResult
import fr.acinq.phoenix.data.ElectrumConfig
import fr.acinq.phoenix.data.WalletId
import fr.acinq.phoenix.managers.DataStoreManager
import fr.acinq.phoenix.managers.NodeParamsManager
import fr.acinq.phoenix.managers.SeedManager
import fr.acinq.phoenix.security.EncryptedSeed
import fr.acinq.phoenix.utils.preferences.GlobalPrefs
import fr.acinq.phoenix.utils.preferences.UserWalletMetadata
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
actual fun updateBusinessActiveInUI(walletId: WalletId) {
BusinessManager.updateBusinessActiveInUI(walletId)
}
actual fun loadAndDecryptSeed(phoenixGlobal: PhoenixGlobal): DecryptSeedResult {
return SeedManager.loadAndDecrypt(
phoenixGlobal
)
}
actual fun getAvailableWalletsMeta(phoenixGlobal: PhoenixGlobal): Flow<Map<WalletId, UserWalletMetadata>> {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as InomboloApplication
return machankuraApplication.globalPrefs.getAvailableWalletsMeta
}
actual suspend fun saveAvailableWalletMeta(phoenixGlobal: PhoenixGlobal, metadata: UserWalletMetadata) {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as InomboloApplication
machankuraApplication.globalPrefs.saveAvailableWalletMeta(metadata)
}
actual suspend fun saveAvailableWalletMeta(
phoenixGlobal: PhoenixGlobal,
walletId: WalletId,
name: String?,
avatar: String,
isHidden: Boolean
) {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as InomboloApplication
machankuraApplication.globalPrefs.saveAvailableWalletMeta(
walletId = walletId,
name = name,
avatar = avatar,
isHidden = isHidden
)
}
actual fun platformWriteSeed(
log: Logger,
phoenixGlobal: PhoenixGlobal,
globalPrefs: GlobalPrefs,
writingState: WritingSeedState,
viewModelScope: CoroutineScope,
mnemonics: List<String>,
onWritingSeedError: (WritingSeedState.Error) -> Unit,
onWritingSeedStateWriting: (WritingSeedState.Writing) -> Unit,
isRestoringWallet: Boolean,
isTorEnabled: Boolean,
customElectrumServer: ElectrumConfig.Custom?,
onSeedWritten: (WalletId) -> Unit
) {
if (writingState !is WritingSeedState.Init) return
viewModelScope.launch(Dispatchers.IO + CoroutineExceptionHandler { _, e ->
log.e("failed to write mnemonics to disk: ${e.message}")
onWritingSeedError.invoke(
WritingSeedState.Error.Generic(e)
)
}) {
log.d("writing mnemonics to disk...")
onWritingSeedStateWriting.invoke(
WritingSeedState.Writing(mnemonics)
)
val existingSeeds = SeedManager.loadAndDecryptOrNull(phoenixGlobal)?.map {
it.key to it.value.words
}?.toMap()
val seed = MnemonicCode.toSeed(mnemonics, "").toByteVector()
val keyManager = LocalKeyManager(seed, NodeParamsManager.chain, NodeParamsManager.remoteSwapInXpub)
val newWalletId = WalletId(keyManager.nodeKeys.nodeKey.publicKey)
when {
existingSeeds == null -> {
log.e("could not load the existing seed map, aborting...")
onWritingSeedError.invoke(
WritingSeedState.Error.CannotLoadSeedMap
)
return@launch
}
existingSeeds.containsKey(newWalletId) -> {
log.i("attempting to import a seed that already exists, aborting...")
onWritingSeedError.invoke(
WritingSeedState.Error.SeedAlreadyExists
)
return@launch
}
else -> {
val newSeedMap = existingSeeds + (newWalletId to mnemonics)
val encrypted = EncryptedSeed.V2.encrypt(newSeedMap)
SeedManager.writeSeedToDisk(phoenixGlobal, encrypted, overwrite = true)
onSeedWritten.invoke(newWalletId)
if (isRestoringWallet) {
log.i("successfully restored wallet=$newWalletId")
} else {
log.i("successfully created wallet=$newWalletId")
}
}
}
globalPrefs.saveLastUsedAppCode(AppVersion.versionCode)
val dataStoreManager = DataStoreManager(
phoenixGlobal.ctx,
chain = NodeParamsManager.chain,
)
val userPrefs = dataStoreManager.loadUserPrefsForWallet(walletId = newWalletId)
userPrefs.saveIsTorEnabled(isTorEnabled)
userPrefs.saveElectrumServer(customElectrumServer)
viewModelScope.launch(Dispatchers.Main) {
delay(1000)
onSeedWritten(newWalletId)
}
}
}