Add Tron (TRC20/TRX) send/transfer support

Reuses the existing generic fee-sufficiency validation
(sufficientTransferableBalanceToPayOriginFee) and send flow
unchanged. Transaction construction goes through TronGrid's own
createtransaction/triggersmartcontract endpoints (verified live
against Shasta testnet) rather than a hand-rolled protobuf
implementation; signing reuses the existing secp256k1 path
(SignerPayloadRaw.skipMessageHashing) already used for Ethereum,
no new crypto library. Also fixes a Phase 1 gap: Chain.isValidAddress()
had no isTronBased branch, so every Tron send would have failed
address validation.

No Energy staking/delegation/rental UI - only Tron's default
protocol behavior (burn TRX to cover Bandwidth/Energy shortfall).
This commit is contained in:
2026-07-07 07:08:22 -07:00
parent 46d2a91510
commit 3cd07abe55
16 changed files with 1026 additions and 15 deletions
@@ -15,6 +15,7 @@ import io.novafoundation.nova.common.utils.findIsInstanceOrNull
import io.novafoundation.nova.common.utils.formatNamed
import io.novafoundation.nova.common.utils.removeHexPrefix
import io.novafoundation.nova.common.utils.emptyTronAccountId
import io.novafoundation.nova.common.utils.isValidTronAddress
import io.novafoundation.nova.common.utils.substrateAccountId
import io.novafoundation.nova.common.utils.toTronAddress
import io.novafoundation.nova.common.utils.tronAddressToAccountId
@@ -361,13 +362,19 @@ fun Chain.multiAddressOf(accountId: ByteArray): MultiAddress {
fun Chain.isValidAddress(address: String): Boolean {
return runCatching {
if (isEthereumBased) {
address.asEthereumAddress().isValid()
} else {
address.toAccountId() // verify supplied address can be converted to account id
when {
// Tron addresses are Base58Check(0x41 ++ accountId), not SS58 or plain 0x-hex - neither of the two
// branches below would ever accept them, so this needs its own dedicated check.
isTronBased -> address.isValidTronAddress()
addressPrefix.toShort() == address.addressPrefix() ||
legacyAddressPrefix?.toShort() == address.addressPrefix()
isEthereumBased -> address.asEthereumAddress().isValid()
else -> {
address.toAccountId() // verify supplied address can be converted to account id
addressPrefix.toShort() == address.addressPrefix() ||
legacyAddressPrefix?.toShort() == address.addressPrefix()
}
}
}.getOrDefault(false)
}