mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 20:45:53 +00:00
fix: cloud backup schema dropped Tron address/keypair on every round trip
WalletPublicInfo/WalletPrivateInfo had no tron field at all, so any wallet created via the (default) cloud-backup wallet creation flow, or restored from a cloud backup, silently lost its Tron address and keypair even though AccountSecretsFactory/SecretsMetaAccountLocalFactory derived them correctly moments earlier - this is why TRX/USDT-TRC20 never appeared for any wallet, new or old, confirmed via a device-side diagnostic dump of the actual DB row (tronAddress=NULL) after a fresh wallet creation. Also reserves (but does not wire up) solana/bitcoin fields in the same schema, since native derivation for those doesn't exist yet - adding them now means that work won't need another silent-drop-prone pass through this same schema later. Adds a regression test exercising the exact apply-diff path that lost the data, plus tron support in the shared cloud-backup test builder DSL.
This commit is contained in:
+22
-3
@@ -17,6 +17,8 @@ import io.novafoundation.nova.common.data.secrets.v2.publicKey
|
|||||||
import io.novafoundation.nova.common.data.secrets.v2.seed
|
import io.novafoundation.nova.common.data.secrets.v2.seed
|
||||||
import io.novafoundation.nova.common.data.secrets.v2.substrateDerivationPath
|
import io.novafoundation.nova.common.data.secrets.v2.substrateDerivationPath
|
||||||
import io.novafoundation.nova.common.data.secrets.v2.substrateKeypair
|
import io.novafoundation.nova.common.data.secrets.v2.substrateKeypair
|
||||||
|
import io.novafoundation.nova.common.data.secrets.v2.tronDerivationPath
|
||||||
|
import io.novafoundation.nova.common.data.secrets.v2.tronKeypair
|
||||||
import io.novafoundation.nova.common.utils.filterNotNull
|
import io.novafoundation.nova.common.utils.filterNotNull
|
||||||
import io.novafoundation.nova.common.utils.findById
|
import io.novafoundation.nova.common.utils.findById
|
||||||
import io.novafoundation.nova.common.utils.mapToSet
|
import io.novafoundation.nova.common.utils.mapToSet
|
||||||
@@ -90,6 +92,7 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
substrate = baseSecrets.getSubstrateBackupSecrets(),
|
substrate = baseSecrets.getSubstrateBackupSecrets(),
|
||||||
ethereum = baseSecrets.getEthereumBackupSecrets(),
|
ethereum = baseSecrets.getEthereumBackupSecrets(),
|
||||||
chainAccounts = emptyList(),
|
chainAccounts = emptyList(),
|
||||||
|
tron = baseSecrets.getTronBackupSecrets(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return CloudBackup(
|
return CloudBackup(
|
||||||
@@ -357,6 +360,7 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
substrate = prepareSubstrateBackupSecrets(baseSecrets, joinedMetaAccountInfo),
|
substrate = prepareSubstrateBackupSecrets(baseSecrets, joinedMetaAccountInfo),
|
||||||
ethereum = baseSecrets.getEthereumBackupSecrets(),
|
ethereum = baseSecrets.getEthereumBackupSecrets(),
|
||||||
chainAccounts = chainAccountsFromChainSecrets + chainAccountFromAdditionalSecrets,
|
chainAccounts = chainAccountsFromChainSecrets + chainAccountFromAdditionalSecrets,
|
||||||
|
tron = baseSecrets.getTronBackupSecrets(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +470,9 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
substrateKeyPair = substrate?.keypair?.toLocalKeyPair() ?: return null,
|
substrateKeyPair = substrate?.keypair?.toLocalKeyPair() ?: return null,
|
||||||
substrateDerivationPath = substrate?.derivationPath,
|
substrateDerivationPath = substrate?.derivationPath,
|
||||||
ethereumKeypair = ethereum?.keypair?.toLocalKeyPair(),
|
ethereumKeypair = ethereum?.keypair?.toLocalKeyPair(),
|
||||||
ethereumDerivationPath = ethereum?.derivationPath
|
ethereumDerivationPath = ethereum?.derivationPath,
|
||||||
|
tronKeypair = tron?.keypair?.toLocalKeyPair(),
|
||||||
|
tronDerivationPath = tron?.derivationPath
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +485,15 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun EncodableStruct<MetaAccountSecrets>?.getTronBackupSecrets(): CloudBackup.WalletPrivateInfo.TronSecrets? {
|
||||||
|
if (this == null) return null
|
||||||
|
|
||||||
|
return CloudBackup.WalletPrivateInfo.TronSecrets(
|
||||||
|
keypair = tronKeypair?.toBackupKeypairSecrets() ?: return null,
|
||||||
|
derivationPath = tronDerivationPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun EncodableStruct<MetaAccountSecrets>?.getSubstrateBackupSecrets(): CloudBackup.WalletPrivateInfo.SubstrateSecrets? {
|
private fun EncodableStruct<MetaAccountSecrets>?.getSubstrateBackupSecrets(): CloudBackup.WalletPrivateInfo.SubstrateSecrets? {
|
||||||
if (this == null) return null
|
if (this == null) return null
|
||||||
|
|
||||||
@@ -520,7 +535,9 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
ethereumPublicKey = metaAccount.ethereumPublicKey,
|
ethereumPublicKey = metaAccount.ethereumPublicKey,
|
||||||
name = metaAccount.name,
|
name = metaAccount.name,
|
||||||
type = metaAccount.type.toBackupWalletType() ?: return null,
|
type = metaAccount.type.toBackupWalletType() ?: return null,
|
||||||
chainAccounts = chainAccounts.mapToSet { chainAccount -> chainAccount.toBackupPublicChainAccount(chainsById) }
|
chainAccounts = chainAccounts.mapToSet { chainAccount -> chainAccount.toBackupPublicChainAccount(chainsById) },
|
||||||
|
tronAddress = metaAccount.tronAddress,
|
||||||
|
tronPublicKey = metaAccount.tronPublicKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,7 +559,9 @@ class RealLocalAccountsCloudBackupFacade(
|
|||||||
isSelected = isSelected,
|
isSelected = isSelected,
|
||||||
position = accountPosition,
|
position = accountPosition,
|
||||||
status = MetaAccountLocal.Status.ACTIVE,
|
status = MetaAccountLocal.Status.ACTIVE,
|
||||||
typeExtras = null
|
typeExtras = null,
|
||||||
|
tronAddress = tronAddress,
|
||||||
|
tronPublicKey = tronPublicKey,
|
||||||
).also {
|
).also {
|
||||||
if (localIdOverwrite != null) {
|
if (localIdOverwrite != null) {
|
||||||
it.id = localIdOverwrite
|
it.id = localIdOverwrite
|
||||||
|
|||||||
+68
@@ -7,6 +7,8 @@ import io.novafoundation.nova.common.data.secrets.v2.ChainAccountSecrets
|
|||||||
import io.novafoundation.nova.common.data.secrets.v2.MetaAccountSecrets
|
import io.novafoundation.nova.common.data.secrets.v2.MetaAccountSecrets
|
||||||
import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2
|
import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2
|
||||||
import io.novafoundation.nova.common.data.secrets.v2.entropy
|
import io.novafoundation.nova.common.data.secrets.v2.entropy
|
||||||
|
import io.novafoundation.nova.common.data.secrets.v2.tronDerivationPath
|
||||||
|
import io.novafoundation.nova.common.data.secrets.v2.tronKeypair
|
||||||
import io.novafoundation.nova.core.model.CryptoType
|
import io.novafoundation.nova.core.model.CryptoType
|
||||||
import io.novafoundation.nova.core_db.dao.MetaAccountDao
|
import io.novafoundation.nova.core_db.dao.MetaAccountDao
|
||||||
import io.novafoundation.nova.core_db.model.chain.account.ChainAccountLocal
|
import io.novafoundation.nova.core_db.model.chain.account.ChainAccountLocal
|
||||||
@@ -536,6 +538,64 @@ class RealLocalAccountsCloudBackupFacadeTest {
|
|||||||
verifyEvent(expectedEvent)
|
verifyEvent(expectedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test for a wallet's Tron address/keypair being silently dropped on a cloud backup round trip:
|
||||||
|
// WalletPublicInfo/WalletPrivateInfo had no tron field at all until this fix, so a backup written from a
|
||||||
|
// wallet that genuinely had a Tron address, once applied back to local (e.g. after "clear all data" +
|
||||||
|
// restore, or on a fresh install created via the cloud-backup-first-wallet flow), landed with
|
||||||
|
// tronAddress/tronPublicKey/tronKeypair = null - found via real-device testing, not by this test.
|
||||||
|
@Test
|
||||||
|
fun shouldApplyAddAccountDiffWithTronSecrets() = runBlocking {
|
||||||
|
LocalAccountsMocker.setupMocks(metaAccountDao) {}
|
||||||
|
SecretStoreMocker.setupMocks(secretStore) {}
|
||||||
|
|
||||||
|
allChainsAreEvm(false)
|
||||||
|
|
||||||
|
val localBackup = buildTestCloudBackup {
|
||||||
|
publicData { }
|
||||||
|
privateData { }
|
||||||
|
}
|
||||||
|
|
||||||
|
val bytes32 = bytes32of(0)
|
||||||
|
val tronAddressBytes = bytes20of(1)
|
||||||
|
val tronDerivationPath = "//44//195//0/0/0"
|
||||||
|
|
||||||
|
val cloudBackup = buildTestCloudBackup {
|
||||||
|
publicData {
|
||||||
|
wallet(walletUUid(0)) {
|
||||||
|
substrateAccountId(bytes32)
|
||||||
|
substrateCryptoType(CryptoType.SR25519)
|
||||||
|
substratePublicKey(bytes32)
|
||||||
|
|
||||||
|
tronPublicKey(bytes32)
|
||||||
|
tronAddress(tronAddressBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
privateData {
|
||||||
|
wallet(walletUUid(0)) {
|
||||||
|
entropy(bytes32)
|
||||||
|
|
||||||
|
substrate {
|
||||||
|
seed(bytes32)
|
||||||
|
keypair(KeyPairSecrets(bytes32, bytes32, bytes32))
|
||||||
|
}
|
||||||
|
|
||||||
|
tron {
|
||||||
|
derivationPath(tronDerivationPath)
|
||||||
|
keypair(KeyPairSecrets(bytes32, bytes32, nonce = null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val diff = localBackup.localVsCloudDiff(cloudBackup, BackupDiffStrategy.overwriteLocal())
|
||||||
|
|
||||||
|
facade.applyBackupDiff(diff, cloudBackup)
|
||||||
|
|
||||||
|
verify(metaAccountDao).insertMetaAccount(metaAccountWithTronAddress(tronAddressBytes))
|
||||||
|
verify(secretStore).putMetaAccountSecrets(eq(0), metaAccountSecretsWithTronDerivationPath(tronDerivationPath))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun shouldApplyRemoveAccountDiff(): Unit = runBlocking {
|
fun shouldApplyRemoveAccountDiff(): Unit = runBlocking {
|
||||||
allChainsAreEvm(false)
|
allChainsAreEvm(false)
|
||||||
@@ -1205,6 +1265,14 @@ class RealLocalAccountsCloudBackupFacadeTest {
|
|||||||
return argThat { it.globallyUniqueId == id }
|
return argThat { it.globallyUniqueId == id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun metaAccountWithTronAddress(tronAddress: ByteArray): MetaAccountLocal {
|
||||||
|
return argThat { it.tronAddress.contentEquals(tronAddress) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun metaAccountSecretsWithTronDerivationPath(derivationPath: String): EncodableStruct<MetaAccountSecrets> {
|
||||||
|
return argThat { it.tronDerivationPath == derivationPath && it.tronKeypair != null }
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun verifyNoAdditionalSecretsInserted() {
|
private suspend fun verifyNoAdditionalSecretsInserted() {
|
||||||
verify(secretStore, never()).putAdditionalMetaAccountSecret(anyLong(), any(), any())
|
verify(secretStore, never()).putAdditionalMetaAccountSecret(anyLong(), any(), any())
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-3
@@ -23,7 +23,19 @@ data class CloudBackup(
|
|||||||
val ethereumPublicKey: ByteArray?,
|
val ethereumPublicKey: ByteArray?,
|
||||||
val name: String,
|
val name: String,
|
||||||
val type: Type,
|
val type: Type,
|
||||||
val chainAccounts: Set<ChainAccountInfo>
|
val chainAccounts: Set<ChainAccountInfo>,
|
||||||
|
// All three below are nullable and defaulted so that Gson deserializing a backup written before that
|
||||||
|
// particular chain family existed - which has no such field in its JSON at all - lands on null here
|
||||||
|
// rather than failing. Solana/bitcoin have no derivation anywhere in this codebase yet (no native
|
||||||
|
// support, unlike Tron) - the fields are reserved now purely so that adding that support later never
|
||||||
|
// needs another silent-drop-prone trip through every call site that touches this schema, the way Tron
|
||||||
|
// did when it was bolted onto a schema that only knew about substrate/ethereum.
|
||||||
|
val tronAddress: ByteArray? = null,
|
||||||
|
val tronPublicKey: ByteArray? = null,
|
||||||
|
val solanaAddress: ByteArray? = null,
|
||||||
|
val solanaPublicKey: ByteArray? = null,
|
||||||
|
val bitcoinAddress: ByteArray? = null,
|
||||||
|
val bitcoinPublicKey: ByteArray? = null,
|
||||||
) : Identifiable {
|
) : Identifiable {
|
||||||
|
|
||||||
override val identifier: String = walletId
|
override val identifier: String = walletId
|
||||||
@@ -72,7 +84,13 @@ data class CloudBackup(
|
|||||||
ethereumPublicKey.contentEquals(other.ethereumPublicKey) &&
|
ethereumPublicKey.contentEquals(other.ethereumPublicKey) &&
|
||||||
name == other.name &&
|
name == other.name &&
|
||||||
type == other.type &&
|
type == other.type &&
|
||||||
chainAccounts == other.chainAccounts
|
chainAccounts == other.chainAccounts &&
|
||||||
|
tronAddress.contentEquals(other.tronAddress) &&
|
||||||
|
tronPublicKey.contentEquals(other.tronPublicKey) &&
|
||||||
|
solanaAddress.contentEquals(other.solanaAddress) &&
|
||||||
|
solanaPublicKey.contentEquals(other.solanaPublicKey) &&
|
||||||
|
bitcoinAddress.contentEquals(other.bitcoinAddress) &&
|
||||||
|
bitcoinPublicKey.contentEquals(other.bitcoinPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
@@ -85,6 +103,12 @@ data class CloudBackup(
|
|||||||
result = 31 * result + name.hashCode()
|
result = 31 * result + name.hashCode()
|
||||||
result = 31 * result + type.hashCode()
|
result = 31 * result + type.hashCode()
|
||||||
result = 31 * result + chainAccounts.hashCode()
|
result = 31 * result + chainAccounts.hashCode()
|
||||||
|
result = 31 * result + (tronAddress?.contentHashCode() ?: 0)
|
||||||
|
result = 31 * result + (tronPublicKey?.contentHashCode() ?: 0)
|
||||||
|
result = 31 * result + (solanaAddress?.contentHashCode() ?: 0)
|
||||||
|
result = 31 * result + (solanaPublicKey?.contentHashCode() ?: 0)
|
||||||
|
result = 31 * result + (bitcoinAddress?.contentHashCode() ?: 0)
|
||||||
|
result = 31 * result + (bitcoinPublicKey?.contentHashCode() ?: 0)
|
||||||
result = 31 * result + identifier.hashCode()
|
result = 31 * result + identifier.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -100,6 +124,11 @@ data class CloudBackup(
|
|||||||
val substrate: SubstrateSecrets?,
|
val substrate: SubstrateSecrets?,
|
||||||
val ethereum: EthereumSecrets?,
|
val ethereum: EthereumSecrets?,
|
||||||
val chainAccounts: List<ChainAccountSecrets>,
|
val chainAccounts: List<ChainAccountSecrets>,
|
||||||
|
// See the matching comment on WalletPublicInfo: tron is fully wired end to end, solana/bitcoin are
|
||||||
|
// schema-only reservations until native derivation for them exists.
|
||||||
|
val tron: TronSecrets? = null,
|
||||||
|
val solana: SolanaSecrets? = null,
|
||||||
|
val bitcoin: BitcoinSecrets? = null,
|
||||||
) : Identifiable {
|
) : Identifiable {
|
||||||
|
|
||||||
override val identifier: String = walletId
|
override val identifier: String = walletId
|
||||||
@@ -118,6 +147,9 @@ data class CloudBackup(
|
|||||||
if (substrate != other.substrate) return false
|
if (substrate != other.substrate) return false
|
||||||
if (ethereum != other.ethereum) return false
|
if (ethereum != other.ethereum) return false
|
||||||
if (chainAccounts != other.chainAccounts) return false
|
if (chainAccounts != other.chainAccounts) return false
|
||||||
|
if (tron != other.tron) return false
|
||||||
|
if (solana != other.solana) return false
|
||||||
|
if (bitcoin != other.bitcoin) return false
|
||||||
return identifier == other.identifier
|
return identifier == other.identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +159,9 @@ data class CloudBackup(
|
|||||||
result = 31 * result + (substrate?.hashCode() ?: 0)
|
result = 31 * result + (substrate?.hashCode() ?: 0)
|
||||||
result = 31 * result + (ethereum?.hashCode() ?: 0)
|
result = 31 * result + (ethereum?.hashCode() ?: 0)
|
||||||
result = 31 * result + chainAccounts.hashCode()
|
result = 31 * result + chainAccounts.hashCode()
|
||||||
|
result = 31 * result + (tron?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (solana?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (bitcoin?.hashCode() ?: 0)
|
||||||
result = 31 * result + identifier.hashCode()
|
result = 31 * result + identifier.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -201,6 +236,23 @@ data class CloudBackup(
|
|||||||
val derivationPath: String?,
|
val derivationPath: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class TronSecrets(
|
||||||
|
val keypair: KeyPairSecrets,
|
||||||
|
val derivationPath: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reserved shape for when native Solana derivation is added - unused until then, see the class-level comment.
|
||||||
|
data class SolanaSecrets(
|
||||||
|
val keypair: KeyPairSecrets,
|
||||||
|
val derivationPath: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reserved shape for when native Bitcoin derivation is added - unused until then, see the class-level comment.
|
||||||
|
data class BitcoinSecrets(
|
||||||
|
val keypair: KeyPairSecrets,
|
||||||
|
val derivationPath: String?,
|
||||||
|
)
|
||||||
|
|
||||||
data class KeyPairSecrets(
|
data class KeyPairSecrets(
|
||||||
val publicKey: ByteArray,
|
val publicKey: ByteArray,
|
||||||
val privateKey: ByteArray,
|
val privateKey: ByteArray,
|
||||||
@@ -234,5 +286,5 @@ data class CloudBackup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun CloudBackup.WalletPrivateInfo.isCompletelyEmpty(): Boolean {
|
fun CloudBackup.WalletPrivateInfo.isCompletelyEmpty(): Boolean {
|
||||||
return entropy == null && substrate == null && ethereum == null && chainAccounts.isEmpty()
|
return entropy == null && substrate == null && ethereum == null && tron == null && chainAccounts.isEmpty()
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-1
@@ -7,6 +7,7 @@ import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.
|
|||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.EthereumSecrets
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.EthereumSecrets
|
||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.KeyPairSecrets
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.KeyPairSecrets
|
||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.SubstrateSecrets
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.SubstrateSecrets
|
||||||
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPrivateInfo.TronSecrets
|
||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo
|
||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo.ChainAccountInfo
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo.ChainAccountInfo
|
||||||
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo.ChainAccountInfo.ChainAccountCryptoType
|
import io.novafoundation.nova.feature_cloud_backup_api.domain.model.CloudBackup.WalletPublicInfo.ChainAccountInfo.ChainAccountCryptoType
|
||||||
@@ -99,6 +100,7 @@ class WalletPrivateInfoBuilder(
|
|||||||
|
|
||||||
private var substrate: SubstrateSecrets? = null
|
private var substrate: SubstrateSecrets? = null
|
||||||
private var ethereum: EthereumSecrets? = null
|
private var ethereum: EthereumSecrets? = null
|
||||||
|
private var tron: TronSecrets? = null
|
||||||
|
|
||||||
private val chainAccounts = mutableListOf<ChainAccountSecrets>()
|
private val chainAccounts = mutableListOf<ChainAccountSecrets>()
|
||||||
|
|
||||||
@@ -114,6 +116,10 @@ class WalletPrivateInfoBuilder(
|
|||||||
ethereum = BackupEthereumSecretsBuilder().apply(builder).build()
|
ethereum = BackupEthereumSecretsBuilder().apply(builder).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun tron(builder: BackupTronSecretsBuilder.() -> Unit) {
|
||||||
|
tron = BackupTronSecretsBuilder().apply(builder).build()
|
||||||
|
}
|
||||||
|
|
||||||
fun chainAccount(accountId: AccountId, builder: (BackupChainAccountSecretsBuilder.() -> Unit)? = null) {
|
fun chainAccount(accountId: AccountId, builder: (BackupChainAccountSecretsBuilder.() -> Unit)? = null) {
|
||||||
val element = BackupChainAccountSecretsBuilder(accountId).apply { builder?.invoke(this) }.build()
|
val element = BackupChainAccountSecretsBuilder(accountId).apply { builder?.invoke(this) }.build()
|
||||||
chainAccounts.add(element)
|
chainAccounts.add(element)
|
||||||
@@ -126,6 +132,7 @@ class WalletPrivateInfoBuilder(
|
|||||||
substrate = substrate,
|
substrate = substrate,
|
||||||
ethereum = ethereum,
|
ethereum = ethereum,
|
||||||
chainAccounts = chainAccounts,
|
chainAccounts = chainAccounts,
|
||||||
|
tron = tron,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,6 +180,25 @@ class BackupEthereumSecretsBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CloudBackupBuildDsl
|
||||||
|
class BackupTronSecretsBuilder {
|
||||||
|
|
||||||
|
private var _keypair: KeyPairSecrets? = null
|
||||||
|
private var _derivationPath: String? = null
|
||||||
|
|
||||||
|
fun derivationPath(value: String?) {
|
||||||
|
_derivationPath = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun keypair(keypair: KeyPairSecrets) {
|
||||||
|
_keypair = keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): TronSecrets {
|
||||||
|
return TronSecrets(requireNotNull(_keypair), _derivationPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@CloudBackupBuildDsl
|
@CloudBackupBuildDsl
|
||||||
class BackupChainAccountSecretsBuilder(private val accountId: AccountId) {
|
class BackupChainAccountSecretsBuilder(private val accountId: AccountId) {
|
||||||
|
|
||||||
@@ -223,6 +249,8 @@ class WalletPublicInfoBuilder(
|
|||||||
private var _substrateAccountId: ByteArray? = null
|
private var _substrateAccountId: ByteArray? = null
|
||||||
private var _ethereumPublicKey: ByteArray? = null
|
private var _ethereumPublicKey: ByteArray? = null
|
||||||
private var _ethereumAddress: ByteArray? = null
|
private var _ethereumAddress: ByteArray? = null
|
||||||
|
private var _tronPublicKey: ByteArray? = null
|
||||||
|
private var _tronAddress: ByteArray? = null
|
||||||
private var _name: String = ""
|
private var _name: String = ""
|
||||||
private var _isSelected: Boolean = false
|
private var _isSelected: Boolean = false
|
||||||
private var _type: WalletPublicInfo.Type = WalletPublicInfo.Type.SECRETS
|
private var _type: WalletPublicInfo.Type = WalletPublicInfo.Type.SECRETS
|
||||||
@@ -252,6 +280,14 @@ class WalletPublicInfoBuilder(
|
|||||||
_ethereumAddress = value
|
_ethereumAddress = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun tronPublicKey(value: ByteArray?) {
|
||||||
|
_tronPublicKey = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tronAddress(value: ByteArray?) {
|
||||||
|
_tronAddress = value
|
||||||
|
}
|
||||||
|
|
||||||
fun name(value: String) {
|
fun name(value: String) {
|
||||||
_name = value
|
_name = value
|
||||||
}
|
}
|
||||||
@@ -274,7 +310,9 @@ class WalletPublicInfoBuilder(
|
|||||||
ethereumPublicKey = _ethereumPublicKey,
|
ethereumPublicKey = _ethereumPublicKey,
|
||||||
name = _name,
|
name = _name,
|
||||||
type = _type,
|
type = _type,
|
||||||
chainAccounts = chainAccounts.toSet()
|
chainAccounts = chainAccounts.toSet(),
|
||||||
|
tronAddress = _tronAddress,
|
||||||
|
tronPublicKey = _tronPublicKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user