Skip to content

Commit 49a4f07

Browse files
committed
Merge branch 'main'
2 parents c409314 + 18f11a7 commit 49a4f07

File tree

62 files changed

+493
-261
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+493
-261
lines changed

configs/dependencies.gradle

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ ext {
2828
hiltVersion = "2.48"
2929

3030
// Nunchuk dep versions
31-
nativeSdkVersion = '1.1.63'
31+
nativeSdkVersion = '1.1.64'
3232

3333
// Matrix
3434
matrixSdkVersion = '1.5.30'
@@ -38,10 +38,10 @@ ext {
3838

3939
MAJOR_VERSION = 1
4040
MINOR_VERSION = 9
41-
PATCH_VERSION = 36
42-
TASK_LABEL = "BYZANTINE"
41+
PATCH_VERSION = 37
42+
TASK_LABEL = "UAT"
4343

44-
VERSION_CODE = 217
44+
VERSION_CODE = 220
4545

4646
androidConfig = [
4747
applicationId : "com.nunchuk.android",

nunchuk-core/src/main/java/com/nunchuk/android/compose/provider/SignerProvider.kt

+6-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ class SignersModelProvider : CollectionPreviewParameterProvider<List<SignerModel
1111
"Tom’s TAPSIGNER",
1212
fingerPrint = "79EB35F4",
1313
derivationPath = "",
14-
isMasterSigner = false
14+
isMasterSigner = false,
15+
index = 10
1516
),
1617
SignerModel(
1718
"123",
1819
"Tom’s TAPSIGNER 2",
1920
fingerPrint = "79EB35F4",
2021
derivationPath = "",
21-
isMasterSigner = false
22+
isMasterSigner = false,
23+
index = 10
2224
),
2325
)
2426
)
@@ -31,7 +33,8 @@ class SignerModelProvider : CollectionPreviewParameterProvider<SignerModel>(
3133
"Tom’s TAPSIGNER",
3234
fingerPrint = "79EB35F4",
3335
derivationPath = "",
34-
isMasterSigner = false
36+
isMasterSigner = false,
37+
index = 10
3538
),
3639
)
3740
)

nunchuk-core/src/main/java/com/nunchuk/android/core/data/model/membership/TransactionResponse.kt

+14-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package com.nunchuk.android.core.data.model.membership
2121

2222
import com.google.gson.annotations.SerializedName
2323
import com.nunchuk.android.model.transaction.ServerTransaction
24+
import com.nunchuk.android.type.TransactionStatus
2425

2526
data class TransactionResponse(
2627
@SerializedName("transaction") val transaction: TransactionServerDto? = null
@@ -60,4 +61,16 @@ internal fun TransactionServerDto.toServerTransaction() = ServerTransaction(
6061
spendingLimitMessage = spendingLimitReach?.message.orEmpty(),
6162
signedInMilis = signedAtMilis,
6263
isCosigning = isCosigning
63-
)
64+
)
65+
66+
fun String?.toTransactionStatus(): TransactionStatus {
67+
return when (this) {
68+
"PENDING_SIGNATURES" -> TransactionStatus.PENDING_SIGNATURES
69+
"READY_TO_BROADCAST" -> TransactionStatus.READY_TO_BROADCAST
70+
"NETWORK_REJECTED" -> TransactionStatus.NETWORK_REJECTED
71+
"PENDING_CONFIRMATION" -> TransactionStatus.PENDING_CONFIRMATION
72+
"REPLACED" -> TransactionStatus.REPLACED
73+
"CONFIRMED" -> TransactionStatus.CONFIRMED
74+
else -> TransactionStatus.CONFIRMED
75+
}
76+
}

nunchuk-core/src/main/java/com/nunchuk/android/core/domain/membership/InheritanceClaimCreateTransactionUseCase.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import com.nunchuk.android.model.Amount
2424
import com.nunchuk.android.model.Transaction
2525
import com.nunchuk.android.nativelib.NunchukNativeSdk
2626
import com.nunchuk.android.repository.PremiumWalletRepository
27-
import com.nunchuk.android.type.AddressType
28-
import com.nunchuk.android.type.WalletType
2927
import com.nunchuk.android.usecase.UseCase
3028
import kotlinx.coroutines.CoroutineDispatcher
3129
import javax.inject.Inject
@@ -63,11 +61,11 @@ class InheritanceClaimCreateTransactionUseCase @Inject constructor(
6361
isDraft = parameters.isDraft,
6462
)
6563
if (parameters.isDraft) return transaction
66-
userWalletRepository.inheritanceClaimingClaim(
64+
val transactionAdditional = userWalletRepository.inheritanceClaimingClaim(
6765
magic = parameters.magic,
6866
psbt = transaction.psbt
6967
)
70-
return transaction
68+
return transaction.copy(status = transactionAdditional.status)
7169
}
7270

7371
data class Param(

nunchuk-core/src/main/java/com/nunchuk/android/core/mapper/MasterSignerMapper.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ import com.nunchuk.android.core.guestmode.SignInMode
2424
import com.nunchuk.android.core.signer.SignerModel
2525
import com.nunchuk.android.core.util.CardIdManager
2626
import com.nunchuk.android.model.MasterSigner
27+
import com.nunchuk.android.nativelib.NunchukNativeSdk
2728
import com.nunchuk.android.type.SignerType
2829
import javax.inject.Inject
2930
import javax.inject.Singleton
3031

3132
@Singleton
3233
class MasterSignerMapper @Inject constructor(
3334
private val accountManager: AccountManager,
34-
private val cardIdManager: CardIdManager
35+
private val cardIdManager: CardIdManager,
36+
private val nunchukNativeSdk: NunchukNativeSdk
3537
) {
3638
suspend operator fun invoke(from: MasterSigner, derivationPath: String = ""): SignerModel {
3739
val accountInfo = accountManager.getAccount()
@@ -49,7 +51,8 @@ class MasterSignerMapper @Inject constructor(
4951
cardId = cardId,
5052
tags = from.tags,
5153
isVisible = from.isVisible,
52-
isMasterSigner = true
54+
isMasterSigner = true,
55+
index = nunchukNativeSdk.getIndexFromPath(derivationPath.ifEmpty { from.device.path })
5356
)
5457
}
5558
}

nunchuk-core/src/main/java/com/nunchuk/android/core/repository/ByzantineSyncer.kt

+3-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import com.nunchuk.android.persistence.entity.KeyHealthStatusEntity
2323
import com.nunchuk.android.type.Chain
2424
import kotlinx.coroutines.CoroutineScope
2525
import kotlinx.coroutines.flow.SharingStarted
26-
import kotlinx.coroutines.flow.firstOrNull
2726
import kotlinx.coroutines.flow.stateIn
2827
import javax.inject.Inject
2928

@@ -62,8 +61,7 @@ internal class ByzantineSyncer @Inject constructor(
6261

6362
val updateOrInsertList = mutableListOf<AlertEntity>()
6463

65-
val localMap = alertDao.getAlerts(groupId, getChatId(), chain.value).firstOrNull().orEmpty()
66-
.associateByTo(mutableMapOf()) { it.id }
64+
val localMap = alertDao.getAlerts(groupId, getChatId(), chain.value).associateByTo(mutableMapOf()) { it.id }
6765

6866
remoteList.forEach { remote ->
6967
val local = localMap[remote.id]
@@ -96,8 +94,7 @@ internal class ByzantineSyncer @Inject constructor(
9694
val finalGroups =
9795
groups.ifEmpty { userWalletApiManager.groupWalletApi.getGroups().data.groups.orEmpty() }
9896
val groupLocals =
99-
groupDao.getGroups(accountManager.getAccount().chatId, chain.value).firstOrNull()
100-
?: emptyList()
97+
groupDao.getGroups(accountManager.getAccount().chatId, chain.value)
10198
val allGroupIds = groupLocals.map { it.groupId }.toHashSet()
10299
val addGroupIds = HashSet<String>()
103100
val chatId = accountManager.getAccount().chatId
@@ -133,8 +130,7 @@ internal class ByzantineSyncer @Inject constructor(
133130

134131
suspend fun syncKeyHealthStatus(groupId: String, walletId: String): List<KeyHealthStatus>? {
135132
runCatching {
136-
val localMap = keyHealthStatusDao.getKeys(groupId, walletId, getChatId(), chain.value)
137-
.firstOrNull().orEmpty().associateByTo(mutableMapOf()) { it.xfp }
133+
val localMap = keyHealthStatusDao.getKeys(groupId, walletId, getChatId(), chain.value).associateByTo(mutableMapOf()) { it.xfp }
138134
val response =
139135
userWalletApiManager.groupWalletApi.getWalletHealthStatus(groupId, walletId)
140136
val remoteList = arrayListOf<KeyHealthStatusDto>()

nunchuk-core/src/main/java/com/nunchuk/android/core/repository/GroupWalletRepositoryImpl.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ internal class GroupWalletRepositoryImpl @Inject constructor(
114114
}
115115
} else {
116116
val step = when (key.index) {
117-
0 -> if (draftWallet.walletConfig?.n == 4) MembershipStep.BYZANTINE_ADD_TAP_SIGNER else MembershipStep.BYZANTINE_ADD_HARDWARE_KEY_0
117+
0 -> if (draftWallet.walletConfig?.n == 4 && draftWallet.walletConfig.allowInheritance) MembershipStep.BYZANTINE_ADD_TAP_SIGNER else MembershipStep.BYZANTINE_ADD_HARDWARE_KEY_0
118118
1 -> MembershipStep.BYZANTINE_ADD_HARDWARE_KEY_1
119119
2 -> MembershipStep.BYZANTINE_ADD_HARDWARE_KEY_2
120120
3 -> MembershipStep.BYZANTINE_ADD_HARDWARE_KEY_3
@@ -241,7 +241,7 @@ internal class GroupWalletRepositoryImpl @Inject constructor(
241241
groupId: String,
242242
walletId: String,
243243
): Flow<List<KeyHealthStatus>> {
244-
return keyHealthStatusDao.getKeys(groupId, walletId, accountManager.getAccount().chatId, chain.value).map {
244+
return keyHealthStatusDao.getKeysFlow(groupId, walletId, accountManager.getAccount().chatId, chain.value).map {
245245
it.map { entity -> entity.toKeyHealthStatus() }
246246
}
247247
}

nunchuk-core/src/main/java/com/nunchuk/android/core/repository/UserWalletsRepository.kt

+41-13
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import com.nunchuk.android.core.data.model.membership.WalletDto
6868
import com.nunchuk.android.core.data.model.membership.toDto
6969
import com.nunchuk.android.core.data.model.membership.toExternalModel
7070
import com.nunchuk.android.core.data.model.membership.toServerTransaction
71+
import com.nunchuk.android.core.data.model.membership.toTransactionStatus
7172
import com.nunchuk.android.core.domain.membership.TargetAction
7273
import com.nunchuk.android.core.exception.RequestAddKeyCancelException
7374
import com.nunchuk.android.core.manager.UserWalletApiManager
@@ -843,7 +844,8 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
843844
psbt = transaction.psbt.orEmpty(),
844845
subAmount = response.data.subAmount ?: 0.0,
845846
fee = response.data.txFee ?: 0.0,
846-
feeRate = response.data.txFeeRate ?: 0.0
847+
feeRate = response.data.txFeeRate ?: 0.0,
848+
status = transaction.status.toTransactionStatus()
847849
)
848850
}
849851

@@ -994,7 +996,7 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
994996
)
995997
val transaction =
996998
response.data.transaction ?: throw NullPointerException("transaction from server null")
997-
return TransactionAdditional(psbt = transaction.psbt.orEmpty())
999+
return TransactionAdditional(psbt = transaction.psbt.orEmpty(), status = transaction.status.toTransactionStatus())
9981000
}
9991001

10001002
override suspend fun inheritanceCheck(): InheritanceCheck {
@@ -1467,7 +1469,7 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
14671469
}
14681470

14691471
override fun getAssistedWalletsLocal(): Flow<List<AssistedWalletBrief>> {
1470-
return assistedWalletDao.getAssistedWallets().map { list ->
1472+
return assistedWalletDao.getAssistedWalletsFlow().map { list ->
14711473
list.map { wallet ->
14721474
AssistedWalletBrief(
14731475
localId = wallet.localId,
@@ -1747,13 +1749,25 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
17471749
val key = request?.key
17481750
if (request?.status == "COMPLETED" && key != null) {
17491751
val type = nunchukNativeSdk.signerTypeFromStr(key.type.orEmpty())
1750-
nunchukNativeSdk.createSigner(name = key.name.orEmpty(),
1751-
xpub = key.xpub.orEmpty(),
1752-
publicKey = key.pubkey.orEmpty(),
1753-
derivationPath = key.derivationPath.orEmpty(),
1754-
masterFingerprint = key.xfp.orEmpty(),
1755-
type = type,
1756-
tags = key.tags.orEmpty().mapNotNull { tag -> tag.toSignerTag() })
1752+
1753+
val hasSigner = nunchukNativeSdk.hasSigner(
1754+
SingleSigner(
1755+
name = key.name.orEmpty(),
1756+
xpub = key.xpub.orEmpty(),
1757+
publicKey = key.pubkey.orEmpty(),
1758+
derivationPath = key.derivationPath.orEmpty(),
1759+
masterFingerprint = key.xfp.orEmpty(),
1760+
)
1761+
)
1762+
if (!hasSigner) {
1763+
nunchukNativeSdk.createSigner(name = key.name.orEmpty(),
1764+
xpub = key.xpub.orEmpty(),
1765+
publicKey = key.pubkey.orEmpty(),
1766+
derivationPath = key.derivationPath.orEmpty(),
1767+
masterFingerprint = key.xfp.orEmpty(),
1768+
type = type,
1769+
tags = key.tags.orEmpty().mapNotNull { tag -> tag.toSignerTag() })
1770+
}
17571771
membershipRepository.saveStepInfo(
17581772
MembershipStepInfo(
17591773
step = localRequest.step,
@@ -1842,7 +1856,7 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
18421856
}
18431857

18441858
override fun getGroups(): Flow<List<ByzantineGroup>> =
1845-
groupDao.getGroups(chatId = accountManager.getAccount().chatId, chain = chain.value)
1859+
groupDao.getGroupsFlow(chatId = accountManager.getAccount().chatId, chain = chain.value)
18461860
.map { group ->
18471861
val groups = group.map { group ->
18481862
group.toByzantineGroup()
@@ -1858,6 +1872,7 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
18581872
val response = userWalletApiManager.groupWalletApi.getGroups()
18591873
val groupAssistedKeys = mutableSetOf<String>()
18601874
val groups = response.data.groups.orEmpty()
1875+
val groupIds = groups.asSequence().map { it.id.orEmpty() }.toSet()
18611876
if (groups.isNotEmpty()) {
18621877
groups.forEach {
18631878
when (it.status) {
@@ -1871,10 +1886,23 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
18711886
}
18721887
}
18731888
}
1889+
val isDeletedWallet = deleteAssistedWallets(groupIds)
18741890
ncDataStore.setGroupAssistedKey(groupAssistedKeys)
18751891
syncer.syncGroups(groups)
18761892

1877-
return groups.isNotEmpty()
1893+
return groups.isNotEmpty() || isDeletedWallet
1894+
}
1895+
1896+
private suspend fun deleteAssistedWallets(groupIds: Set<String>): Boolean {
1897+
val localGroupWallets = assistedWalletDao.getAssistedWallets().filter { it.groupId.isNotEmpty() }
1898+
val deleteGroupIds = localGroupWallets.map { it.groupId }.filter { groupId -> groupIds.isEmpty() || groupIds.contains(groupId).not() }
1899+
assistedWalletDao.deletes(localGroupWallets.filter { deleteGroupIds.contains(it.groupId) })
1900+
1901+
localGroupWallets.filter { deleteGroupIds.contains(it.groupId) }
1902+
.map { it.localId }.forEach { localId ->
1903+
nunchukNativeSdk.deleteWallet(localId)
1904+
}
1905+
return deleteGroupIds.isNotEmpty()
18781906
}
18791907

18801908
override fun getGroup(groupId: String): Flow<ByzantineGroup> {
@@ -2008,7 +2036,7 @@ internal class PremiumWalletRepositoryImpl @Inject constructor(
20082036
}
20092037

20102038
override fun getAlerts(groupId: String): Flow<List<Alert>> {
2011-
return alertDao.getAlerts(groupId, chatId = accountManager.getAccount().chatId, chain.value)
2039+
return alertDao.getAlertsFlow(groupId, chatId = accountManager.getAccount().chatId, chain.value)
20122040
.map { alerts ->
20132041
alerts.map { alert ->
20142042
alert.toAlert()

nunchuk-core/src/main/java/com/nunchuk/android/core/signer/SignerModel.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ data class SignerModel(
4141
val cardId: String = "",
4242
val tags : List<SignerTag> = emptyList(),
4343
val isVisible: Boolean = true,
44-
val isMasterSigner: Boolean
44+
val isMasterSigner: Boolean,
45+
val index: Int = 0,
4546
) : Parcelable {
4647
val isEditablePath: Boolean
4748
get() = type == SignerType.HARDWARE || type == SignerType.SOFTWARE
@@ -73,6 +74,8 @@ data class SignerModel(
7374
} else ""
7475

7576
private fun cardIdShorten() = cardId.takeLast(5)
77+
78+
fun isShowAcctX() = index > 0 && type != SignerType.SERVER && type != SignerType.UNKNOWN
7679
}
7780

7881
fun SingleSigner.toModel(isPrimaryKey: Boolean = false) = SignerModel(
@@ -86,7 +89,8 @@ fun SingleSigner.toModel(isPrimaryKey: Boolean = false) = SignerModel(
8689
isPrimaryKey = isPrimaryKey,
8790
tags = tags,
8891
isVisible = isVisible,
89-
isMasterSigner = hasMasterSigner
92+
isMasterSigner = hasMasterSigner,
93+
index = index
9094
)
9195

9296
fun JoinKey.toSignerModel() = SignerModel(

nunchuk-core/src/main/java/com/nunchuk/android/core/util/InheritancePlanFlow.kt

+2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ object InheritanceSourceFlow {
4545
const val NONE = 0
4646
const val WIZARD = 1
4747
const val GROUP_DASHBOARD = 2
48+
const val SERVICE_TAB = 3
4849

4950
@IntDef(
5051
NONE,
5152
WIZARD,
5253
GROUP_DASHBOARD,
54+
SERVICE_TAB
5355
)
5456
@Retention(AnnotationRetention.SOURCE)
5557
annotation class InheritanceSourceFlowInfo

nunchuk-core/src/main/java/com/nunchuk/android/core/util/SignerUtil.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ val SingleSigner.isColdCard: Boolean
4545
fun SignerType.toReadableString(context: Context, isPrimaryKey: Boolean): String {
4646
if (isPrimaryKey) return context.getString(R.string.nc_signer_type_primary_key)
4747
return when (this) {
48-
AIRGAP -> context.getString(R.string.nc_signer_type_air_gapped)
48+
AIRGAP -> context.getString(R.string.nc_signer_type_airgapped)
4949
SOFTWARE -> context.getString(R.string.nc_signer_type_software)
5050
HARDWARE -> context.getString(R.string.nc_signer_type_hardware)
5151
FOREIGN_SOFTWARE -> context.getString(R.string.nc_signer_type_foreign_software)

nunchuk-core/src/main/res/values/strings.xml

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<string name="nc_text_do_this_later">I’ll do this later</string>
1010
<string name="nc_wallet_export_coldcard">Export wallet to COLDCARD</string>
1111

12-
<string name="nc_signer_type_air_gapped">Air-gapped</string>
12+
<string name="nc_signer_type_airgapped">Airgapped</string>
1313
<string name="nc_signer_type_software">Software</string>
1414
<string name="nc_signer_type_hardware">Wired</string>
1515
<string name="nc_signer_type_foreign_software">Foreign software</string>
@@ -121,7 +121,7 @@
121121
<string name="nc_signed_transaction">You’ve signed this transaction</string>
122122
<string name="nc_my_coldcard">My COLDCARD</string>
123123
<string name="nc_hold_device_near_the_coldcard">Hold your device near the COLDCARD.</string>
124-
<string name="nc_hint_add_mk4">On COLDCARD, go to Advanced/Tools → Export Wallet → Generic JSON → OK → Enter 0 for Account → Press 3.</string>
124+
<string name="nc_hint_add_mk4">On COLDCARD, go to Advanced/Tools → Export Wallet → Generic JSON → OK → Enter Account # (0 if first time) → Press 3.</string>
125125
<string name="nc_hint_export_wallet_mk4">On COLDCARD, go to Settings → Multisig Wallets → Import via NFC</string>
126126
<string name="nc_hint_export_trans_to_mk4">On COLDCARD, go to Ready To Sign → Press 3</string>
127127
<string name="nc_hint_import_signature_from_mk4">Ready to import signature.</string>
@@ -673,4 +673,6 @@
673673
<string name="nc_update_inheritance_plan_group_change_by">%1$s is requesting to make the following changes to the inheritance plan for %1$s:</string>
674674
<string name="nc_cancel_inheritance_plan_group_change_by">%1$s is requesting to cancel the inheritance plan for %1$s.</string>
675675
<string name="nc_no_internet_connection_try_again_later">No Internet connection. Please try again later.</string>
676+
<string name="nc_acct_x">Acct %1$s</string>
677+
<string name="nc_withdrawal_in_progress">Withdrawal in progress...</string>
676678
</resources>

0 commit comments

Comments
 (0)