@@ -131,6 +131,7 @@ import {
131131} from '@metamask/seedless-onboarding-controller' ;
132132import { PRODUCT_TYPES } from '@metamask/subscription-controller' ;
133133import { isSnapId } from '@metamask/snaps-utils' ;
134+ import { address } from '@solana/addresses' ;
134135import {
135136 findAtomicBatchSupportForChain ,
136137 checkEip7702Support ,
@@ -1638,8 +1639,9 @@ export default class MetamaskController extends EventEmitter {
16381639 setupControllerEventSubscriptions ( ) {
16391640 let lastSelectedAddress ;
16401641 let lastSelectedSolanaAccountAddress ;
1642+ let lastSelectedTronAccountAddress ;
16411643
1642- // this throws if there is no solana account... perhaps we should handle this better at the controller level
1644+ // this throws if there is no solana or Tron account... perhaps we should handle this better at the controller level
16431645 try {
16441646 lastSelectedSolanaAccountAddress =
16451647 this . accountsController . getSelectedMultichainAccount (
@@ -1648,6 +1650,14 @@ export default class MetamaskController extends EventEmitter {
16481650 } catch {
16491651 // noop
16501652 }
1653+ try {
1654+ lastSelectedTronAccountAddress =
1655+ this . accountsController . getSelectedMultichainAccount (
1656+ MultichainNetworks . TRON ,
1657+ ) ?. address ;
1658+ } catch {
1659+ // noop
1660+ }
16511661
16521662 this . controllerMessenger . subscribe (
16531663 'PreferencesController:stateChange' ,
@@ -1943,6 +1953,194 @@ export default class MetamaskController extends EventEmitter {
19431953 } ,
19441954 ) ;
19451955
1956+ // wallet_notify for tron accountChanged when permission changes
1957+ this . controllerMessenger . subscribe (
1958+ `${ this . permissionController . name } :stateChange` ,
1959+ async ( currentValue , previousValue ) => {
1960+ const origins = uniq ( [ ...previousValue . keys ( ) , ...currentValue . keys ( ) ] ) ;
1961+ origins . forEach ( ( origin ) => {
1962+ const previousCaveatValue = previousValue . get ( origin ) ;
1963+ const currentCaveatValue = currentValue . get ( origin ) ;
1964+
1965+ const previousTronAccountChangedNotificationsEnabled = Boolean (
1966+ previousCaveatValue ?. sessionProperties ?. [
1967+ KnownSessionProperties . TronAccountChangedNotifications
1968+ ] ,
1969+ ) ;
1970+ const currentTronAccountChangedNotificationsEnabled = Boolean (
1971+ currentCaveatValue ?. sessionProperties ?. [
1972+ KnownSessionProperties . TronAccountChangedNotifications
1973+ ] ,
1974+ ) ;
1975+
1976+ if (
1977+ ! previousTronAccountChangedNotificationsEnabled &&
1978+ ! currentTronAccountChangedNotificationsEnabled
1979+ ) {
1980+ return ;
1981+ }
1982+
1983+ const previousTronCaipAccountIds = previousCaveatValue
1984+ ? getPermittedAccountsForScopes ( previousCaveatValue , [
1985+ MultichainNetworks . TRON ,
1986+ MultichainNetworks . TRON_SHASTA ,
1987+ MultichainNetworks . TRON_NILE ,
1988+ ] )
1989+ : [ ] ;
1990+ const previousNonUniqueTronHexAccountAddresses =
1991+ previousTronCaipAccountIds . map ( ( caipAccountId ) => {
1992+ const { address } = parseCaipAccountId ( caipAccountId ) ;
1993+ return address ;
1994+ } ) ;
1995+ const previousTronHexAccountAddresses = uniq (
1996+ previousNonUniqueTronHexAccountAddresses ,
1997+ ) ;
1998+ const [ previousSelectedTronAccountAddress ] =
1999+ this . sortMultichainAccountsByLastSelected (
2000+ previousTronHexAccountAddresses ,
2001+ ) ;
2002+
2003+ const currentTronCaipAccountIds = currentCaveatValue
2004+ ? getPermittedAccountsForScopes ( currentCaveatValue , [
2005+ MultichainNetworks . TRON ,
2006+ MultichainNetworks . TRON_SHASTA ,
2007+ MultichainNetworks . TRON_NILE ,
2008+ ] )
2009+ : [ ] ;
2010+ const currentNonUniqueTronHexAccountAddresses =
2011+ currentTronCaipAccountIds . map ( ( caipAccountId ) => {
2012+ const { address } = parseCaipAccountId ( caipAccountId ) ;
2013+ return address ;
2014+ } ) ;
2015+ const currentTronHexAccountAddresses = uniq (
2016+ currentNonUniqueTronHexAccountAddresses ,
2017+ ) ;
2018+ const [ currentSelectedTronAccountAddress ] =
2019+ this . sortMultichainAccountsByLastSelected (
2020+ currentTronHexAccountAddresses ,
2021+ ) ;
2022+
2023+ if (
2024+ previousSelectedTronAccountAddress !==
2025+ currentSelectedTronAccountAddress
2026+ ) {
2027+ this . _notifyTronAccountChange (
2028+ origin ,
2029+ currentSelectedTronAccountAddress
2030+ ? [ currentSelectedTronAccountAddress ]
2031+ : [ ] ,
2032+ ) ;
2033+ }
2034+ } ) ;
2035+ } ,
2036+ getAuthorizedScopesByOrigin ,
2037+ ) ;
2038+
2039+ // TODO: To be removed when state 2 is fully transitioned.
2040+ // wallet_notify for tron accountChanged when selected account changes
2041+ this . controllerMessenger . subscribe (
2042+ `${ this . accountsController . name } :selectedAccountChange` ,
2043+ async ( account ) => {
2044+ if (
2045+ account . type === TrxAccountType . Eoa &&
2046+ account . address !== lastSelectedTronAccountAddress
2047+ ) {
2048+ lastSelectedTronAccountAddress = account . address ;
2049+
2050+ const originsWithTronAccountChangedNotifications =
2051+ getOriginsWithSessionProperty (
2052+ this . permissionController . state ,
2053+ KnownSessionProperties . TronAccountChangedNotifications ,
2054+ ) ;
2055+
2056+ // returns a map of origins to permitted tron accounts
2057+ const tronAccounts = getPermittedAccountsForScopesByOrigin (
2058+ this . permissionController . state ,
2059+ [
2060+ MultichainNetworks . TRON ,
2061+ MultichainNetworks . TRON_SHASTA ,
2062+ MultichainNetworks . TRON_NILE ,
2063+ ] ,
2064+ ) ;
2065+
2066+ if ( tronAccounts . size > 0 ) {
2067+ for ( const [ origin , accounts ] of tronAccounts . entries ( ) ) {
2068+ const parsedTronAddresses = accounts . map ( ( caipAccountId ) => {
2069+ const { address } = parseCaipAccountId ( caipAccountId ) ;
2070+ return address ;
2071+ } ) ;
2072+
2073+ if (
2074+ parsedTronAddresses . includes ( account . address ) &&
2075+ originsWithTronAccountChangedNotifications [ origin ]
2076+ ) {
2077+ this . _notifyTronAccountChange ( origin , [ account . address ] ) ;
2078+ }
2079+ }
2080+ }
2081+ }
2082+ } ,
2083+ ) ;
2084+
2085+ // wallet_notify for tron accountChanged when selected account group changes
2086+ this . controllerMessenger . subscribe (
2087+ `${ this . accountTreeController . name } :selectedAccountGroupChange` ,
2088+ ( groupId ) => {
2089+ // TODO: Move this logic to the SnapKeyring directly.
2090+ // Forward selected accounts to the Snap keyring, so each Snaps can fetch those accounts.
2091+ // eslint-disable-next-line no-void
2092+ void this . forwardSelectedAccountGroupToSnapKeyring (
2093+ this . getSnapKeyringIfAvailable ( ) ,
2094+ groupId ,
2095+ ) ;
2096+
2097+ const [ account ] =
2098+ this . accountTreeController . getAccountsFromSelectedAccountGroup ( {
2099+ scopes : [ TrxScope . Mainnet ] ,
2100+ } ) ;
2101+ if (
2102+ account &&
2103+ account . type === TrxAccountType . Eoa &&
2104+ account . address !== lastSelectedTronAccountAddress
2105+ ) {
2106+ lastSelectedTronAccountAddress = account . address ;
2107+
2108+ const originsWithTronAccountChangedNotifications =
2109+ getOriginsWithSessionProperty (
2110+ this . permissionController . state ,
2111+ KnownSessionProperties . TronAccountChangedNotifications ,
2112+ ) ;
2113+
2114+ // returns a map of origins to permitted tron accounts
2115+ const tronAccounts = getPermittedAccountsForScopesByOrigin (
2116+ this . permissionController . state ,
2117+ [
2118+ MultichainNetworks . TRON ,
2119+ MultichainNetworks . TRON_SHASTA ,
2120+ MultichainNetworks . TRON_NILE ,
2121+ ] ,
2122+ ) ;
2123+
2124+ if ( tronAccounts . size > 0 ) {
2125+ for ( const [ origin , accounts ] of tronAccounts . entries ( ) ) {
2126+ const parsedTronAddresses = accounts . map ( ( caipAccountId ) => {
2127+ const { address } = parseCaipAccountId ( caipAccountId ) ;
2128+ return address ;
2129+ } ) ;
2130+
2131+ if (
2132+ parsedTronAddresses . includes ( account . address ) &&
2133+ originsWithTronAccountChangedNotifications [ origin ]
2134+ // originsWithTronAccountChangedNotifications[origin]
2135+ ) {
2136+ this . _notifyTronAccountChange ( origin , [ account . address ] ) ;
2137+ }
2138+ }
2139+ }
2140+ }
2141+ } ,
2142+ ) ;
2143+
19462144 // TODO: Move this logic to the SnapKeyring directly.
19472145 // Forward selected accounts to the Snap keyring, so each Snaps can fetch those accounts.
19482146 this . controllerMessenger . subscribe (
@@ -6259,13 +6457,13 @@ export default class MetamaskController extends EventEmitter {
62596457 }
62606458
62616459 /**
6262- * For origins with a solana scope permitted, sends a wallet_notify -> metamask_accountChanged
6263- * event to fire for the solana scope with the currently selected solana account if any are
6460+ * For origins with a solana or tron scope permitted, sends a wallet_notify -> metamask_accountChanged
6461+ * event to fire for the scope with the currently selected account if any are
62646462 * permitted or empty array otherwise.
62656463 *
6266- * @param {string } origin - The origin to notify with the current solana account
6464+ * @param {string } origin - The origin to notify with the current account
62676465 */
6268- notifySolanaAccountChangedForCurrentAccount ( origin ) {
6466+ notifyNonEVMAccountChangedForCurrentAccount ( origin ) {
62696467 let caip25Caveat ;
62706468 try {
62716469 caip25Caveat = this . permissionController . getCaveat (
@@ -6292,10 +6490,16 @@ export default class MetamaskController extends EventEmitter {
62926490 KnownSessionProperties . SolanaAccountChangedNotifications
62936491 ] ;
62946492
6493+ const tronAccountsChangedNotifications =
6494+ caip25Caveat . value . sessionProperties ?. [
6495+ KnownSessionProperties . TronAccountChangedNotifications
6496+ ] ;
6497+
62956498 const sessionScopes = getSessionScopes ( caip25Caveat . value , {
62966499 getNonEvmSupportedMethods : this . getNonEvmSupportedMethods . bind ( this ) ,
62976500 } ) ;
62986501
6502+ // Handle Solana account notifications
62996503 const solanaScope =
63006504 sessionScopes [ MultichainNetworks . SOLANA ] ||
63016505 sessionScopes [ MultichainNetworks . SOLANA_DEVNET ] ||
@@ -6316,9 +6520,29 @@ export default class MetamaskController extends EventEmitter {
63166520 this . _notifySolanaAccountChange ( origin , [ accountAddressToEmit ] ) ;
63176521 }
63186522 }
6319- }
63206523
6321- // ---------------------------------------------------------------------------
6524+ // Handle Tron account notifications
6525+ const tronScope =
6526+ sessionScopes [ MultichainNetworks . TRON ] ||
6527+ sessionScopes [ MultichainNetworks . TRON_DEVNET ] ||
6528+ sessionScopes [ MultichainNetworks . TRON_TESTNET ] ;
6529+
6530+ if ( tronAccountsChangedNotifications && tronScope ) {
6531+ const { accounts } = tronScope ;
6532+ const parsedPermittedTronAddresses = accounts . map ( ( caipAccountId ) => {
6533+ const { address } = parseCaipAccountId ( caipAccountId ) ;
6534+ return address ;
6535+ } ) ;
6536+
6537+ const [ accountAddressToEmit ] = this . sortMultichainAccountsByLastSelected (
6538+ parsedPermittedTronAddresses ,
6539+ ) ;
6540+
6541+ if ( accountAddressToEmit ) {
6542+ this . _notifyTronAccountChange ( origin , [ accountAddressToEmit ] ) ;
6543+ }
6544+ }
6545+ } // ---------------------------------------------------------------------------
63226546 // Identity Management (signature operations)
63236547
63246548 getAddTransactionRequest ( {
@@ -6932,13 +7156,13 @@ export default class MetamaskController extends EventEmitter {
69327156 engine,
69337157 } ) ;
69347158
6935- // solana account changed notifications
7159+ // solana and Tron account changed notifications
69367160 // This delay is needed because it's possible for a dapp to not have listeners
69377161 // setup in time right after a connection is established.
69387162 // This can be resolved if we amend the caip standards to include a liveliness
69397163 // handshake as part of the initial connection.
69407164 setTimeout (
6941- ( ) => this . notifySolanaAccountChangedForCurrentAccount ( origin ) ,
7165+ ( ) => this . notifyNonEVMAccountChangedForCurrentAccount ( origin ) ,
69427166 500 ,
69437167 ) ;
69447168
@@ -8677,6 +8901,23 @@ export default class MetamaskController extends EventEmitter {
86778901 ) ;
86788902 }
86798903
8904+ async _notifyTronAccountChange ( origin , accountAddressArray ) {
8905+ this . notifyConnections (
8906+ origin ,
8907+ {
8908+ method : MultichainApiNotifications . walletNotify ,
8909+ params : {
8910+ scope : MultichainNetworks . TRON ,
8911+ notification : {
8912+ method : NOTIFICATION_NAMES . accountsChanged ,
8913+ params : accountAddressArray ,
8914+ } ,
8915+ } ,
8916+ } ,
8917+ API_TYPE . CAIP_MULTICHAIN ,
8918+ ) ;
8919+ }
8920+
86808921 async _notifyChainChange ( ) {
86818922 this . notifyAllConnections (
86828923 async ( origin ) => ( {
0 commit comments