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:
2026-07-11 19:20:02 -07:00
parent e1d199931c
commit bc9087136c
2 changed files with 22 additions and 8 deletions
@@ -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],