Skip to content

Commit 6773108

Browse files
authored
Merge pull request #974 from synonymdev/codex/update-bitkit-core-0-1-63
Add legacy RN close recovery flow
2 parents afb165e + ca9ce1d commit 6773108

8 files changed

Lines changed: 583 additions & 1 deletion

File tree

app/src/main/java/to/bitkit/repositories/WalletRepo.kt

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package to.bitkit.repositories
22

33
import androidx.compose.runtime.Immutable
44
import com.synonym.bitkitcore.AddressType
5+
import com.synonym.bitkitcore.LegacyRnCloseRecoveryScanResult
6+
import com.synonym.bitkitcore.LegacyRnCloseRecoverySweepPreview
57
import com.synonym.bitkitcore.PreActivityMetadata
68
import com.synonym.bitkitcore.Scanner
79
import kotlinx.collections.immutable.ImmutableList
@@ -114,6 +116,77 @@ class WalletRepo @Inject constructor(
114116
}
115117
}
116118

119+
suspend fun scanLegacyRnNativeSegwitRecoveryFunds(
120+
indexLimit: UInt,
121+
): Result<LegacyRnCloseRecoveryScanResult> = withContext(bgDispatcher) {
122+
runCatching {
123+
val (mnemonic, passphrase) = recoveryWalletCredentials()
124+
val electrumUrl = settingsStore.data.first().electrumServer
125+
126+
coreService.onchain.scanLegacyRnNativeSegwitRecoveryFunds(
127+
mnemonicPhrase = mnemonic,
128+
network = Env.network,
129+
electrumUrl = electrumUrl,
130+
indexLimit = indexLimit,
131+
bip39Passphrase = passphrase,
132+
)
133+
}.onFailure {
134+
Logger.error("Legacy RN recovery scan failed", it, context = TAG)
135+
}
136+
}
137+
138+
suspend fun prepareLegacyRnNativeSegwitRecoverySweep(
139+
indexLimit: UInt,
140+
feeRateSatsPerVbyte: UInt?,
141+
): Result<LegacyRnCloseRecoverySweepPreview> = withContext(bgDispatcher) {
142+
runCatching {
143+
val (mnemonic, passphrase) = recoveryWalletCredentials()
144+
val electrumUrl = settingsStore.data.first().electrumServer
145+
val destinationAddress = recoverySweepDestinationAddress()
146+
147+
coreService.onchain.prepareLegacyRnNativeSegwitRecoverySweep(
148+
mnemonicPhrase = mnemonic,
149+
network = Env.network,
150+
electrumUrl = electrumUrl,
151+
destinationAddress = destinationAddress,
152+
feeRateSatsPerVbyte = feeRateSatsPerVbyte,
153+
indexLimit = indexLimit,
154+
bip39Passphrase = passphrase,
155+
)
156+
}.onFailure {
157+
Logger.error("Legacy RN recovery sweep prepare failed", it, context = TAG)
158+
}
159+
}
160+
161+
suspend fun broadcastLegacyRnNativeSegwitRecoverySweep(txHex: String): Result<String> = withContext(bgDispatcher) {
162+
runCatching {
163+
val electrumUrl = settingsStore.data.first().electrumServer
164+
val txid = coreService.onchain.broadcastRawTx(serializedTx = txHex, electrumUrl = electrumUrl)
165+
syncNodeAndWallet(SyncSource.MANUAL).onFailure {
166+
Logger.warn("Legacy RN recovery post-broadcast sync failed", it, context = TAG)
167+
}
168+
txid
169+
}.onFailure {
170+
Logger.error("Legacy RN recovery sweep broadcast failed", it, context = TAG)
171+
}
172+
}
173+
174+
private fun recoveryWalletCredentials(): Pair<String, String?> {
175+
val mnemonic = keychain.loadString(Keychain.Key.BIP39_MNEMONIC.name)
176+
?: throw ServiceError.MnemonicNotFound()
177+
val passphrase = keychain.loadString(Keychain.Key.BIP39_PASSPHRASE.name)
178+
return mnemonic to passphrase
179+
}
180+
181+
private suspend fun recoverySweepDestinationAddress(): String {
182+
val currentAddress = getOnchainAddress()
183+
if (currentAddress.isNotBlank()) return currentAddress
184+
185+
return newAddress().getOrThrow().also {
186+
require(it.isNotBlank()) { "Destination address unavailable" }
187+
}
188+
}
189+
117190
suspend fun refreshBip21(): Result<Unit> = withContext(bgDispatcher) {
118191
Logger.debug("Refreshing bip21", context = TAG)
119192

app/src/main/java/to/bitkit/services/CoreService.kt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.synonym.bitkitcore.IBtEstimateFeeResponse2
1616
import com.synonym.bitkitcore.IBtInfo
1717
import com.synonym.bitkitcore.IBtOrder
1818
import com.synonym.bitkitcore.IcJitEntry
19+
import com.synonym.bitkitcore.LegacyRnCloseRecoveryScanResult
20+
import com.synonym.bitkitcore.LegacyRnCloseRecoverySweepPreview
1921
import com.synonym.bitkitcore.LightningActivity
2022
import com.synonym.bitkitcore.OnchainActivity
2123
import com.synonym.bitkitcore.PaymentState
@@ -40,10 +42,13 @@ import com.synonym.bitkitcore.getOrders
4042
import com.synonym.bitkitcore.getTags
4143
import com.synonym.bitkitcore.initDb
4244
import com.synonym.bitkitcore.insertActivity
45+
import com.synonym.bitkitcore.onchainBroadcastRawTx
4346
import com.synonym.bitkitcore.openChannel
47+
import com.synonym.bitkitcore.prepareLegacyRnNativeSegwitRecoverySweep
4448
import com.synonym.bitkitcore.refreshActiveCjitEntries
4549
import com.synonym.bitkitcore.refreshActiveOrders
4650
import com.synonym.bitkitcore.removeTags
51+
import com.synonym.bitkitcore.scanLegacyRnNativeSegwitRecoveryFunds
4752
import com.synonym.bitkitcore.updateActivity
4853
import com.synonym.bitkitcore.updateBlocktankUrl
4954
import com.synonym.bitkitcore.upsertActivities
@@ -1810,6 +1815,56 @@ class OnchainService {
18101815
}
18111816
}
18121817

1818+
suspend fun scanLegacyRnNativeSegwitRecoveryFunds(
1819+
mnemonicPhrase: String,
1820+
network: Network?,
1821+
electrumUrl: String,
1822+
indexLimit: UInt,
1823+
bip39Passphrase: String?,
1824+
): LegacyRnCloseRecoveryScanResult {
1825+
return ServiceQueue.CORE.background {
1826+
scanLegacyRnNativeSegwitRecoveryFunds(
1827+
mnemonicPhrase = mnemonicPhrase,
1828+
network = network?.toCoreNetwork(),
1829+
electrumUrl = electrumUrl,
1830+
indexLimit = indexLimit,
1831+
bip39Passphrase = bip39Passphrase,
1832+
)
1833+
}
1834+
}
1835+
1836+
@Suppress("LongParameterList")
1837+
suspend fun prepareLegacyRnNativeSegwitRecoverySweep(
1838+
mnemonicPhrase: String,
1839+
network: Network?,
1840+
electrumUrl: String,
1841+
destinationAddress: String,
1842+
feeRateSatsPerVbyte: UInt?,
1843+
indexLimit: UInt,
1844+
bip39Passphrase: String?,
1845+
): LegacyRnCloseRecoverySweepPreview {
1846+
return ServiceQueue.CORE.background {
1847+
prepareLegacyRnNativeSegwitRecoverySweep(
1848+
mnemonicPhrase = mnemonicPhrase,
1849+
network = network?.toCoreNetwork(),
1850+
electrumUrl = electrumUrl,
1851+
destinationAddress = destinationAddress,
1852+
feeRateSatsPerVbyte = feeRateSatsPerVbyte,
1853+
indexLimit = indexLimit,
1854+
bip39Passphrase = bip39Passphrase,
1855+
)
1856+
}
1857+
}
1858+
1859+
suspend fun broadcastRawTx(
1860+
serializedTx: String,
1861+
electrumUrl: String,
1862+
): String {
1863+
return ServiceQueue.CORE.background {
1864+
onchainBroadcastRawTx(serializedTx = serializedTx, electrumUrl = electrumUrl)
1865+
}
1866+
}
1867+
18131868
suspend fun derivePrivateKey(
18141869
mnemonicPhrase: String,
18151870
derivationPathStr: String?,

app/src/main/java/to/bitkit/ui/ContentView.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import to.bitkit.ui.screens.recovery.RecoveryModeScreen
9494
import to.bitkit.ui.screens.settings.DevSettingsScreen
9595
import to.bitkit.ui.screens.settings.FeeSettingsScreen
9696
import to.bitkit.ui.screens.settings.LdkDebugScreen
97+
import to.bitkit.ui.screens.settings.LegacyRnRecoveryScreen
9798
import to.bitkit.ui.screens.settings.ProbingToolScreen
9899
import to.bitkit.ui.screens.settings.VssDebugScreen
99100
import to.bitkit.ui.screens.shop.ShopIntroScreen
@@ -955,6 +956,9 @@ private fun NavGraphBuilder.settings(
955956
composableWithDefaultTransitions<Routes.DevSettings> {
956957
DevSettingsScreen(navController)
957958
}
959+
composableWithDefaultTransitions<Routes.LegacyRnRecovery> {
960+
LegacyRnRecoveryScreen(navController)
961+
}
958962
composableWithDefaultTransitions<Routes.Trezor> {
959963
TrezorScreen(navController)
960964
}
@@ -1946,6 +1950,9 @@ sealed interface Routes {
19461950
@Serializable
19471951
data object DevSettings : Routes
19481952

1953+
@Serializable
1954+
data object LegacyRnRecovery : Routes
1955+
19491956
@Serializable
19501957
data object LdkDebug : Routes
19511958

app/src/main/java/to/bitkit/ui/screens/settings/DevSettingsScreen.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ fun DevSettingsScreen(
6868
SettingsButtonRow("VSS") { navController.navigateTo(Routes.VssDebug) }
6969
SettingsButtonRow("Probing Tool") { navController.navigateTo(Routes.ProbingTool) }
7070

71+
SectionHeader("RECOVERY")
72+
SettingsButtonRow("Legacy Close Recovery") { navController.navigateTo(Routes.LegacyRnRecovery) }
73+
7174
if (PaykitFeatureFlags.isUiAvailable) {
7275
SectionHeader("PAYKIT")
7376
SettingsSwitchRow(

0 commit comments

Comments
 (0)