WalletPublicInfo/WalletPrivateInfo had no tron field at all, so any wallet
created via the (default) cloud-backup wallet creation flow, or restored
from a cloud backup, silently lost its Tron address and keypair even though
AccountSecretsFactory/SecretsMetaAccountLocalFactory derived them correctly
moments earlier - this is why TRX/USDT-TRC20 never appeared for any wallet,
new or old, confirmed via a device-side diagnostic dump of the actual DB row
(tronAddress=NULL) after a fresh wallet creation.
Also reserves (but does not wire up) solana/bitcoin fields in the same
schema, since native derivation for those doesn't exist yet - adding them
now means that work won't need another silent-drop-prone pass through this
same schema later.
Adds a regression test exercising the exact apply-diff path that lost the
data, plus tron support in the shared cloud-backup test builder DSL.
hasAccountIn=false was observed live for the currently active account despite
every derivation/mapping code path (creation, backfill, DB->domain mapping)
tracing correctly - need to see the actual DB state per account to know
whether this is a write-time or read-time gap.
Log.d/Log.e added to TronAddressBackfillMigration throw 'Method ... not
mocked' in plain JVM unit tests without this - the framework's own stubs
are meant to be configured this way for exactly this case, not worked
around by avoiding Log calls in production code.
TRX still missing on a real device after installing the backfill fix,
with no way to tell whether the migration ran, skipped, or threw for that
specific account - the migration had zero logging. Adds Log.d at every
decision point (per-account skip reason, success) plus a try-catch around
each account so one account's failure can't silently abort the whole
migration or crash app startup for everyone else.
@Before's preferences.getBoolean stub was never invoked by migrate()-only
tests (only migrationNeeded() reads that preference), tripping Mockito's
strict-stubs UnnecessaryStubbingException across the whole class. Moved
it into a dedicated migrationNeeded() test, matched via any() rather than
the production class's private preference-key constant (which isn't
visible here), and added the missing assertTrue import.
Found via manual device testing against a real, pre-Tron production
wallet: TRX/USDT-TRC20 didn't appear anywhere in the Assets list, not
even as a zero balance - unlike every other configured chain (KSM, USDC,
ETH, BNB, AVAX, LINK all show up at 0). Root cause: MetaAccount.hasAccountIn()
gates Tron balance sync on tronAddress != null, but tronAddress is only
ever populated once, at fresh-mnemonic-creation time in
AccountSecretsFactory.metaAccountSecrets(). The migration that added the
tronPublicKey/tronAddress columns (73_74_AddTronSupport) is pure ALTER
TABLE like every other migration in this codebase - it never derived a
value for pre-existing rows. Net effect: BalancesUpdateSystem silently
skips Tron entirely for every wallet that existed before this feature
shipped, with zero error surfaced anywhere. No automated test catches
this because every automated test creates a fresh (post-Tron) account -
this is exactly the class of bug that only manual testing against a real,
aged wallet can find.
Adds TronAddressBackfillMigration: a one-time, flag-gated pass (mirroring
the existing AccountDataMigration idiom) over SECRETS-type accounts that
still hold their mnemonic entropy in SecretStoreV2 but have no TronKeypair
yet. Derives the Tron keypair via AccountSecretsFactory.chainAccountSecrets
(isEthereum=true, same BIP32/secp256k1 path Tron already uses everywhere
else) at TRON_DEFAULT_DERIVATION_PATH - the same call fresh-account
creation already makes - so a backfilled wallet ends up with byte-for-byte
the same Tron address it would have gotten had it been created today, not
a separately-reimplemented derivation. Watch-only/Ledger/Json/multisig/
proxied accounts (never had a Tron-capable mnemonic) and raw-seed imports
(no entropy) are correctly left untouched, same as they already are for
Ethereum.
Includes a dedicated unit test asserting the backfill derives the exact
same reference Tron address (TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH) that
TronDerivationTest already cross-validated against live TronGrid data for
the standard BIP39 test mnemonic - this touches real wallets' key
material, so it's pinned to a known-good vector rather than just asserting
against its own output.
Real user on a fresh install reported TRX and USDT-TRC20 never
appearing anywhere in the Tokens list (not "zero balance", genuinely
absent - including from the multi-chain USDT chain picker). Traced
the full pipeline; every layer up to and including
TypeBasedAssetSourceRegistry, ChainRegistry, address derivation, and
TronGridApi wiring was already correct.
Root cause: pollingBalanceFlow() had no retry around fetch() - any
single transient failure (DNS hiccup, timeout, momentary connectivity
loss during app cold start) threw out of the `while(true)` loop,
killing the flow permanently. The collector
(FullSyncPaymentUpdater.syncAsset()) only logs and gives up on
failure, it doesn't resubscribe. Since the asset's first balance
write never happens, AssetCache never inserts a DB row for it, and
every UI surface (main list, multi-chain picker, search) reads
exclusively via an INNER JOIN that requires that row to exist - so
the asset is invisible everywhere, permanently, with zero
user-visible error.
Swallow fetch() failures and retry on the next interval instead of
letting them escape the loop - one bad poll no longer blackholes the
asset for the rest of the app session.
Also fixes a related but separate gap found while tracing this:
RealSecretsMetaAccount.multiChainEncryptionIn() had no isTronBased
branch (only isEthereumBased), unlike DefaultMetaAccount's
hasAccountIn/accountIdIn which already handle Tron correctly. This
didn't cause the missing-tokens bug, but would have broken "export
account" (JSON key backup) for Tron - fixed by routing Tron through
MultiChainEncryption.Ethereum, matching what
RealTronTransactionService already does for actual transaction
signing (same secp256k1 keypair).
* Add read-only Tron (TRC20) chain family support
Adds Tron as a third chain family alongside Substrate and EVM:
address derivation (BIP44 coin type 195, secp256k1 reused from the
existing Ethereum path, Base58Check encoding), TronGrid-backed TRX
and TRC20 USDT balance display, and a Room migration for the new
per-account Tron key/address columns. Read-only only — no send,
signing, or broadcast support yet.
* fix: exhaustive when branches for Trc20/TronNative asset types
ChainExt.kt's onChainAssetId and Common.kt's existentialDepositError
both switch exhaustively over Chain.Asset.Type and didn't have cases
for the new Trc20/TronNative variants, breaking compilation. Trc20
mirrors EvmErc20 (contract address as the on-chain id, dust burns
rather than transfers on removal); TronNative mirrors EvmNative.
PolkadotExternalSignInteractor and ExtrinsicSplitter were using standard
CheckMortality which fails with pezsp_runtime DictEnum Era type.
Added isPezkuwiChain detection and routing to custom extensions.
ValidatorProvider, DirectStakingProperties, and DirectStakingRecommendation
were querying Asset Hub chainId for staking data (validators, exposures,
minStake, maxNominations) but these live on the relay chain. Added
chain.parentId resolution so parachain staking correctly routes to relay.
Also:
- Add VoterBagsList pallet support (Pezkuwi naming)
- Wrap BagListRepository queries in runCatching for binding compat
- Remove debug logging