From 12c4ee25b4e661bc0274f8ecb29efa1edc2282ab Mon Sep 17 00:00:00 2001 From: tomasklim Date: Sat, 24 Jan 2026 19:56:35 +0100 Subject: [PATCH] feat(suite): add Tron basic support --- .../TxDetailModal/BasicTxDetails.tsx | 2 +- .../AdvancedTxDetails/AdvancedTxDetails.tsx | 2 +- .../AdvancedTxDetails/IODetails/IODetails.tsx | 4 ++-- .../ReplaceByFeeFailedOriginalTxConfirmed.tsx | 1 + .../suite/src/hooks/wallet/useAccounts.ts | 1 + .../src/views/wallet/send/Outputs/Address.tsx | 1 + packages/theme/src/coinsColors.ts | 1 + suite-common/suite-constants/src/protocol.ts | 5 +++- suite-common/trading/src/utils.ts | 1 + .../wallet-config/src/getExplorerUrls.ts | 7 ++++++ .../wallet-config/src/networksConfig.ts | 23 +++++++++++++++++++ suite-common/wallet-config/src/types.ts | 10 +++++++- .../wallet-core/src/device/deviceThunks.ts | 3 +++ .../wallet-core/src/send/sendFormThunks.ts | 2 ++ suite-common/wallet-types/src/account.ts | 9 ++++++++ suite-common/wallet-utils/src/accountUtils.ts | 23 ++++++++++--------- suite-common/wallet-utils/src/feeUnitUtils.ts | 1 + suite-common/wallet-utils/src/tokenUtils.ts | 2 ++ 18 files changed, 81 insertions(+), 17 deletions(-) diff --git a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/BasicTxDetails.tsx b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/BasicTxDetails.tsx index 146610e148..ce3c43754d 100644 --- a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/BasicTxDetails.tsx +++ b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/BasicTxDetails.tsx @@ -164,7 +164,7 @@ export const BasicTxDetails = ({ )} {/* Ethereum */} - {tx.ethereumSpecific && ( + {network.networkType === 'ethereum' && tx.ethereumSpecific && ( <> } iconName="receipt"> {tx.ethereumSpecific?.nonce} diff --git a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/AdvancedTxDetails.tsx b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/AdvancedTxDetails.tsx index 7756991a1a..b9ff521dc0 100644 --- a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/AdvancedTxDetails.tsx +++ b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/AdvancedTxDetails.tsx @@ -73,7 +73,7 @@ export const AdvancedTxDetails = ({ )} - {network.networkType === 'ethereum' && tx.ethereumSpecific && ( + {tx.ethereumSpecific?.data && ( setSelectedTab('data')}> diff --git a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/IODetails/IODetails.tsx b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/IODetails/IODetails.tsx index 819b396f60..c966bcffde 100644 --- a/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/IODetails/IODetails.tsx +++ b/packages/suite/src/components/suite/modals/ReduxModal/UserContextModal/TxDetailModal/Detail/AdvancedTxDetails/IODetails/IODetails.tsx @@ -18,7 +18,7 @@ type IODetailsProps = { tx: WalletAccountTransaction; }; -// Not ready for Cardano tokens, they will not be visible, probably +// Not ready for Cardano tokens because they are utxo based export const IODetails = ({ tx }: IODetailsProps) => { const network = useSelector(state => state.wallet.selectedAccount.network); const accountKey = getAccountKey(tx.descriptor, tx.symbol, tx.deviceState); @@ -27,7 +27,7 @@ export const IODetails = ({ tx }: IODetailsProps) => { ); const getContent = () => { - if (network?.networkType === 'ethereum') { + if (network?.networkType === 'ethereum' || network?.networkType === 'tron') { return ( <> case 'solana': case 'ripple': case 'stellar': + case 'tron': case 'ethereum': { return { [account.descriptor]: { diff --git a/packages/suite/src/views/wallet/send/Outputs/Address.tsx b/packages/suite/src/views/wallet/send/Outputs/Address.tsx index faf9b73dd9..03787029d9 100644 --- a/packages/suite/src/views/wallet/send/Outputs/Address.tsx +++ b/packages/suite/src/views/wallet/send/Outputs/Address.tsx @@ -334,6 +334,7 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => { } }, evmChecks: async (address: string) => { + // TODO: tron? if (networkType === 'ethereum') { if (!isOnline) { return translationString('TR_ADDRESS_CANT_VERIFY_HISTORY'); diff --git a/packages/theme/src/coinsColors.ts b/packages/theme/src/coinsColors.ts index 7352a253ba..803630ecde 100644 --- a/packages/theme/src/coinsColors.ts +++ b/packages/theme/src/coinsColors.ts @@ -23,6 +23,7 @@ export const coinsColors: CoinsColors = { pol: '#7b3fe4', regtest: '#e75f5f', sol: '#9945ff', + trx: '#ec002a', test: '#e75f5f', thod: '#454a75', tsep: '#454a75', diff --git a/suite-common/suite-constants/src/protocol.ts b/suite-common/suite-constants/src/protocol.ts index 004d588983..50060a1c46 100644 --- a/suite-common/suite-constants/src/protocol.ts +++ b/suite-common/suite-constants/src/protocol.ts @@ -47,7 +47,9 @@ export type Protocol = | 'thod' | 'txrp' | 'txlm' - | 'dsol'; + | 'dsol' + | 'tron' + | 'trx'; export const NETWORK_TO_PROTOCOLS: Record = { btc: ['bitcoin', 'btc'], @@ -60,6 +62,7 @@ export const NETWORK_TO_PROTOCOLS: Record = { xrp: ['ripple', 'xrp'], ada: ['cardano', 'ada'], sol: ['solana', 'sol'], + trx: ['tron', 'trx'], pol: ['polygon', 'matic', 'pol'], bsc: ['binance', 'bnb', 'bsc'], arb: ['arbitrum', 'arbitrum-one', 'arb', 'arbitrum-ethereum'], diff --git a/suite-common/trading/src/utils.ts b/suite-common/trading/src/utils.ts index 3e8022b64a..43d7fbb35b 100644 --- a/suite-common/trading/src/utils.ts +++ b/suite-common/trading/src/utils.ts @@ -153,6 +153,7 @@ export const getUnusedAddressFromAccount = (account: Account) => { case 'ripple': case 'ethereum': case 'solana': + case 'tron': case 'stellar': { return { address: account.descriptor, diff --git a/suite-common/wallet-config/src/getExplorerUrls.ts b/suite-common/wallet-config/src/getExplorerUrls.ts index f2a67728c9..23f0059347 100644 --- a/suite-common/wallet-config/src/getExplorerUrls.ts +++ b/suite-common/wallet-config/src/getExplorerUrls.ts @@ -21,6 +21,13 @@ export const getExplorerUrls = ( address: `${baseUrl}/address/`, nft: `${baseUrl}/nft/`, }, + tron: { + base: baseUrl, + tx: `${baseUrl}/transaction/`, + address: `${baseUrl}/address/`, + nft: `${baseUrl}/contract/`, // should be trc721, trc1155 instead of contract + token: `${baseUrl}/contract/`, // should be trc10, trc20 instead of contract + }, ripple: { base: baseUrl, tx: `${baseUrl}/tx/`, diff --git a/suite-common/wallet-config/src/networksConfig.ts b/suite-common/wallet-config/src/networksConfig.ts index 0329f53524..496f8b0239 100644 --- a/suite-common/wallet-config/src/networksConfig.ts +++ b/suite-common/wallet-config/src/networksConfig.ts @@ -323,6 +323,29 @@ export const networks = { caipId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', nativeTokenReserve: '0.003', }, + trx: { + symbol: 'trx', + displaySymbol: 'TRX', + name: 'Tron', + networkType: 'tron', + bip43Path: "m/44'/195'/0'/0/i", + decimals: 6, + testnet: false, + features: ['tokens', 'coin-definitions', 'graph'], + explorer: getExplorerUrls('https://tronscan.org/#', 'tron'), + support: { + [DeviceModelInternal.T2T1]: '2.10.1', + [DeviceModelInternal.T2B1]: '2.10.1', + [DeviceModelInternal.T3B1]: '2.10.1', + [DeviceModelInternal.T3T1]: '2.10.1', + [DeviceModelInternal.T3W1]: '2.10.1', + }, + backendTypes: ['blockbook'], + isDebugOnlyNetwork: true, + accountTypes: {}, + coingeckoId: 'tron', + tradeCryptoId: 'tron', + }, ada: { // icarus derivation symbol: 'ada', diff --git a/suite-common/wallet-config/src/types.ts b/suite-common/wallet-config/src/types.ts index 6c468465f6..fd7c3ec512 100644 --- a/suite-common/wallet-config/src/types.ts +++ b/suite-common/wallet-config/src/types.ts @@ -21,6 +21,7 @@ export type NetworkSymbol = | 'xlm' | 'test' | 'regtest' + | 'trx' | 'tsep' | 'thod' | 'txrp' @@ -35,7 +36,14 @@ export const asNetworkSymbol = (value: string) => value as NetworkSymbol; */ export type NetworkSymbolExtended = NetworkSymbol | (string & {}); -export type NetworkType = 'bitcoin' | 'ethereum' | 'ripple' | 'cardano' | 'solana' | 'stellar'; +export type NetworkType = + | 'bitcoin' + | 'ethereum' + | 'ripple' + | 'cardano' + | 'solana' + | 'stellar' + | 'tron'; type UtilityAccountType = 'normal' | 'imported' | 'placeholder'; // reserved accountTypes to stand in for a real accountType type RealAccountType = 'legacy' | 'segwit' | 'coinjoin' | 'taproot' | 'ledger'; diff --git a/suite-common/wallet-core/src/device/deviceThunks.ts b/suite-common/wallet-core/src/device/deviceThunks.ts index 9fad752866..ccac948059 100644 --- a/suite-common/wallet-core/src/device/deviceThunks.ts +++ b/suite-common/wallet-core/src/device/deviceThunks.ts @@ -262,6 +262,9 @@ export const confirmAddressOnDeviceThunk = createThunk( const isCardanoAddressChunked = getEnvironment() === 'mobile'; switch (account.networkType) { + case 'tron': + response = await TrezorConnect.tronGetAddress(params); + break; case 'ethereum': response = await TrezorConnect.ethereumGetAddress(params); break; diff --git a/suite-common/wallet-core/src/send/sendFormThunks.ts b/suite-common/wallet-core/src/send/sendFormThunks.ts index 2995c91a73..33cd04a16f 100644 --- a/suite-common/wallet-core/src/send/sendFormThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormThunks.ts @@ -205,6 +205,8 @@ export const composeSendFormTransactionFeeLevelsThunk = createThunk< isNetworkReserveEnabled, }), ); + } else if (networkType === 'tron') { + // TODO: Tron send not yet implemented } else { return exhaustive(networkType); } diff --git a/suite-common/wallet-types/src/account.ts b/suite-common/wallet-types/src/account.ts index 1217d24622..797c8a6f90 100644 --- a/suite-common/wallet-types/src/account.ts +++ b/suite-common/wallet-types/src/account.ts @@ -72,6 +72,15 @@ type AccountNetworkSpecific = stellarCursor: undefined; page: AccountInfo['page']; } + | { + networkType: 'tron'; + misc: { + contractInfo?: ContractInfo; + }; + marker: undefined; + stellarCursor: undefined; + page: AccountInfo['page']; + } | { networkType: 'solana'; misc?: { diff --git a/suite-common/wallet-utils/src/accountUtils.ts b/suite-common/wallet-utils/src/accountUtils.ts index eeb93f789b..e481690e01 100644 --- a/suite-common/wallet-utils/src/accountUtils.ts +++ b/suite-common/wallet-utils/src/accountUtils.ts @@ -260,6 +260,7 @@ export const getAccountTypeDesc = ({ path, accountType, networkType }: getAccoun switch (networkType) { case 'ethereum': + case 'tron': return 'TR_ACCOUNT_TYPE_NORMAL_EVM_DESC'; case 'solana': return 'TR_ACCOUNT_TYPE_NORMAL_SOLANA_DESC'; @@ -790,6 +791,16 @@ export const getAccountSpecific = (accountInfo: Partial, networkTyp }; } + if (networkType === 'tron') { + return { + networkType, + misc: { ...misc }, + marker: undefined, + stellarCursor: undefined, + page: accountInfo.page, + }; + } + return { networkType, misc: undefined, @@ -1037,22 +1048,11 @@ export const getNetworkAccountFeatures = ({ export const hasNetworkFeatures = ( account: Account | undefined, features: NetworkFeature | Array, - isDebugMode?: boolean, ) => { if (!account) { return false; } - // For Stellar tokens feature, return false when not in debug mode - // TODO(stellar): remove this when we are ready to release it. - if ( - isDebugMode === false && - account.networkType === 'stellar' && - (features === 'tokens' || (Array.isArray(features) && features.includes('tokens'))) - ) { - return false; - } - const networkFeatures = getNetworkAccountFeatures(account); const areFeaturesPresent = ([] as NetworkFeature[]) @@ -1094,6 +1094,7 @@ export const isAddressBasedNetwork = (networkType: NetworkType) => { if (networkType === 'bitcoin') return false; if (networkType === 'cardano') return false; if (networkType === 'ethereum') return true; + if (networkType === 'tron') return true; if (networkType === 'ripple') return true; if (networkType === 'solana') return true; if (networkType === 'stellar') return true; diff --git a/suite-common/wallet-utils/src/feeUnitUtils.ts b/suite-common/wallet-utils/src/feeUnitUtils.ts index 17639aef6e..5b92926496 100644 --- a/suite-common/wallet-utils/src/feeUnitUtils.ts +++ b/suite-common/wallet-utils/src/feeUnitUtils.ts @@ -7,6 +7,7 @@ const mapNetworkTypeToFeeUnits: Record = { ripple: 'Drops', solana: 'Lamports', stellar: 'Stroops', + tron: 'Sun', }; export const getFeeUnits = (networkType: NetworkType) => mapNetworkTypeToFeeUnits[networkType]; diff --git a/suite-common/wallet-utils/src/tokenUtils.ts b/suite-common/wallet-utils/src/tokenUtils.ts index 7652bc6e40..404ddb454a 100644 --- a/suite-common/wallet-utils/src/tokenUtils.ts +++ b/suite-common/wallet-utils/src/tokenUtils.ts @@ -101,6 +101,8 @@ const PRESERVE_TOKEN_SYMBOL_CASE_STANDARDS: ReadonlySet = new Set 'BEP20', 'BEP721', 'BEP1155', + 'TRC10', + 'TRC20', ]); export const shouldUppercaseTokenSymbol = (token: TokenInfo) =>