mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 13:45:48 +00:00
fix: Tron transfers signed with the wrong key (or crashed) due to missing multi-chain-encryption case
SecretsSigner.multiChainEncryptionFor() only recognized substrate accounts, standard Ethereum accounts, and explicit per-chain override accounts. A Tron account's accountId matches none of those (same secp256k1 scheme as Ethereum, but a different SLIP-44 derivation path/keypair), so it fell through to null and crashed on the `!!` - found live testing the send flow end-to-end, reproduced on every Confirm tap. Fixing just the null case would have signed Tron transfers with the Ethereum keypair instead of the Tron one (getMetaAccountKeypair only distinguished ethereum/substrate), producing an invalid signature. Threaded a proper isTronBased flag through down to mapMetaAccountSecretsToKeypair so Tron gets its own MetaAccountSecrets.TronKeypair.
This commit is contained in:
+12
-5
@@ -156,20 +156,25 @@ val AccountSecrets.isChainAccountSecrets
|
||||
suspend fun SecretStoreV2.getMetaAccountKeypair(
|
||||
metaId: Long,
|
||||
isEthereum: Boolean,
|
||||
isTron: Boolean = false,
|
||||
): Keypair = withContext(Dispatchers.Default) {
|
||||
val secrets = getMetaAccountSecrets(metaId) ?: noMetaSecrets(metaId)
|
||||
|
||||
mapMetaAccountSecretsToKeypair(secrets, isEthereum)
|
||||
mapMetaAccountSecretsToKeypair(secrets, isEthereum, isTron)
|
||||
}
|
||||
|
||||
fun mapMetaAccountSecretsToKeypair(
|
||||
secrets: EncodableStruct<MetaAccountSecrets>,
|
||||
ethereum: Boolean,
|
||||
tron: Boolean = false,
|
||||
): Keypair {
|
||||
val keypairStruct = if (ethereum) {
|
||||
secrets[MetaAccountSecrets.EthereumKeypair] ?: noEthereumSecret()
|
||||
} else {
|
||||
secrets[MetaAccountSecrets.SubstrateKeypair]
|
||||
// Tron reuses Ethereum's secp256k1 curve but derives its own keypair under a different SLIP-44 path - it
|
||||
// must be checked before `ethereum`, not folded into it, or a Tron account would get signed with the
|
||||
// wrong (Ethereum) private key.
|
||||
val keypairStruct = when {
|
||||
tron -> secrets[MetaAccountSecrets.TronKeypair] ?: noTronSecret()
|
||||
ethereum -> secrets[MetaAccountSecrets.EthereumKeypair] ?: noEthereumSecret()
|
||||
else -> secrets[MetaAccountSecrets.SubstrateKeypair]
|
||||
}
|
||||
|
||||
return mapKeypairStructToKeypair(keypairStruct)
|
||||
@@ -198,6 +203,8 @@ private fun noChainSecrets(metaId: Long, accountId: ByteArray): Nothing {
|
||||
|
||||
private fun noEthereumSecret(): Nothing = error("No ethereum keypair found")
|
||||
|
||||
private fun noTronSecret(): Nothing = error("No tron keypair found")
|
||||
|
||||
fun mapKeypairStructToKeypair(struct: EncodableStruct<KeyPairSchema>): Keypair {
|
||||
return Keypair(
|
||||
publicKey = struct[KeyPairSchema.PublicKey],
|
||||
|
||||
+10
-3
@@ -142,11 +142,13 @@ class SecretsSigner(
|
||||
private suspend fun getKeypair(accountId: AccountId): Keypair {
|
||||
val chainsById = chainRegistry.chainsById()
|
||||
val multiChainEncryption = metaAccount.multiChainEncryptionFor(accountId, chainsById)!!
|
||||
val isTronBased = metaAccount.tronAddress?.contentEquals(accountId) == true
|
||||
|
||||
return secretStoreV2.getKeypair(
|
||||
metaAccount = metaAccount,
|
||||
accountId = accountId,
|
||||
isEthereumBased = multiChainEncryption is MultiChainEncryption.Ethereum
|
||||
isEthereumBased = multiChainEncryption is MultiChainEncryption.Ethereum,
|
||||
isTronBased = isTronBased
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,11 +161,12 @@ class SecretsSigner(
|
||||
private suspend fun SecretStoreV2.getKeypair(
|
||||
metaAccount: MetaAccount,
|
||||
accountId: AccountId,
|
||||
isEthereumBased: Boolean
|
||||
isEthereumBased: Boolean,
|
||||
isTronBased: Boolean = false,
|
||||
) = if (hasChainSecrets(metaAccount.id, accountId)) {
|
||||
getChainAccountKeypair(metaAccount.id, accountId)
|
||||
} else {
|
||||
getMetaAccountKeypair(metaAccount.id, isEthereumBased)
|
||||
getMetaAccountKeypair(metaAccount.id, isEthereumBased, isTronBased)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,6 +176,10 @@ class SecretsSigner(
|
||||
return when {
|
||||
substrateAccountId.contentEquals(accountId) -> substrateCryptoType?.let(MultiChainEncryption.Companion::substrateFrom)
|
||||
ethereumAccountId().contentEquals(accountId) -> MultiChainEncryption.Ethereum
|
||||
// Tron reuses the exact same secp256k1 signing scheme as Ethereum - it just has its own accountId
|
||||
// (different SLIP-44 derivation path), so it doesn't match ethereumAccountId() above and was
|
||||
// falling through to the chainAccounts lookup, which doesn't cover it either -> null -> NPE on `!!`.
|
||||
tronAddress?.contentEquals(accountId) == true -> MultiChainEncryption.Ethereum
|
||||
else -> {
|
||||
val chainAccount = chainAccounts.values.firstOrNull { it.accountId.contentEquals(accountId) } ?: return null
|
||||
val cryptoType = chainAccount.cryptoType ?: return null
|
||||
|
||||
Reference in New Issue
Block a user