feat(suite): add Tron basic support

This commit is contained in:
tomasklim
2026-01-24 19:56:35 +01:00
committed by Tomas Klima
parent 8766fce82a
commit 12c4ee25b4
18 changed files with 81 additions and 17 deletions

View File

@@ -164,7 +164,7 @@ export const BasicTxDetails = ({
)}
{/* Ethereum */}
{tx.ethereumSpecific && (
{network.networkType === 'ethereum' && tx.ethereumSpecific && (
<>
<Item label={<Translation id="TR_NONCE" />} iconName="receipt">
{tx.ethereumSpecific?.nonce}

View File

@@ -73,7 +73,7 @@ export const AdvancedTxDetails = ({
<Translation id="TR_CHAINED_TXS" />
</Tabs.Item>
)}
{network.networkType === 'ethereum' && tx.ethereumSpecific && (
{tx.ethereumSpecific?.data && (
<Tabs.Item id="data" onClick={() => setSelectedTab('data')}>
<Translation id="TR_DATA" />
</Tabs.Item>

View File

@@ -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 (
<>
<IOGroup

View File

@@ -41,6 +41,7 @@ const helpLink: Record<
ripple: null,
solana: null,
stellar: null,
tron: null,
};
export const ReplaceByFeeFailedOriginalTxConfirmed = ({

View File

@@ -23,6 +23,7 @@ export const useAccountAddressDictionary = (account: Account | undefined) =>
case 'solana':
case 'ripple':
case 'stellar':
case 'tron':
case 'ethereum': {
return {
[account.descriptor]: {

View File

@@ -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');

View File

@@ -23,6 +23,7 @@ export const coinsColors: CoinsColors = {
pol: '#7b3fe4',
regtest: '#e75f5f',
sol: '#9945ff',
trx: '#ec002a',
test: '#e75f5f',
thod: '#454a75',
tsep: '#454a75',

View File

@@ -47,7 +47,9 @@ export type Protocol =
| 'thod'
| 'txrp'
| 'txlm'
| 'dsol';
| 'dsol'
| 'tron'
| 'trx';
export const NETWORK_TO_PROTOCOLS: Record<NetworkSymbol, Protocol[]> = {
btc: ['bitcoin', 'btc'],
@@ -60,6 +62,7 @@ export const NETWORK_TO_PROTOCOLS: Record<NetworkSymbol, Protocol[]> = {
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'],

View File

@@ -153,6 +153,7 @@ export const getUnusedAddressFromAccount = (account: Account) => {
case 'ripple':
case 'ethereum':
case 'solana':
case 'tron':
case 'stellar': {
return {
address: account.descriptor,

View File

@@ -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/`,

View File

@@ -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',

View File

@@ -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';

View File

@@ -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;

View File

@@ -205,6 +205,8 @@ export const composeSendFormTransactionFeeLevelsThunk = createThunk<
isNetworkReserveEnabled,
}),
);
} else if (networkType === 'tron') {
// TODO: Tron send not yet implemented
} else {
return exhaustive(networkType);
}

View File

@@ -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?: {

View File

@@ -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<AccountInfo>, 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<NetworkFeature>,
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;

View File

@@ -7,6 +7,7 @@ const mapNetworkTypeToFeeUnits: Record<NetworkType, string> = {
ripple: 'Drops',
solana: 'Lamports',
stellar: 'Stroops',
tron: 'Sun',
};
export const getFeeUnits = (networkType: NetworkType) => mapNetworkTypeToFeeUnits[networkType];

View File

@@ -101,6 +101,8 @@ const PRESERVE_TOKEN_SYMBOL_CASE_STANDARDS: ReadonlySet<TokenStandard> = new Set
'BEP20',
'BEP721',
'BEP1155',
'TRC10',
'TRC20',
]);
export const shouldUppercaseTokenSymbol = (token: TokenInfo) =>