diff --git a/packages/transaction-pay-controller/CHANGELOG.md b/packages/transaction-pay-controller/CHANGELOG.md index f7e5ef39508..3c6fc7e0093 100644 --- a/packages/transaction-pay-controller/CHANGELOG.md +++ b/packages/transaction-pay-controller/CHANGELOG.md @@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **BREAKING:** Add `AppMetadataControllerGetStateAction` and `AssetsControllerGetStateForTransactionPayAction` to the `AllowedActions` messenger type ([#8163](https://github.com/MetaMask/core/pull/8163)) - Support gasless Relay deposits via `execute` endpoint ([#8133](https://github.com/MetaMask/core/pull/8133)) - Build Across post-swap transfer actions for `predictDeposit` quotes so Predict deposits can bridge swapped output into the destination proxy wallet ([#8159](https://github.com/MetaMask/core/pull/8159)) ### Changed +- `getTokenBalance`, `getTokenInfo`, and `getTokenFiatRate` now source token metadata, balances, and pricing from `AssetsController:getStateForTransactionPay` when the `assetsUnifyState` remote feature flag is enabled, falling back to individual controller state calls otherwise ([#8163](https://github.com/MetaMask/core/pull/8163)) - Bump `@metamask/assets-controllers` from `^100.2.0` to `^100.2.1` ([#8162](https://github.com/MetaMask/core/pull/8162)) - Bump `@metamask/bridge-controller` from `^69.0.0` to `^69.1.0` ([#8162](https://github.com/MetaMask/core/pull/8162), [#8168](https://github.com/MetaMask/core/pull/8168)) - Bump `@metamask/bridge-status-controller` from `^68.0.1` to `^68.1.0` ([#8162](https://github.com/MetaMask/core/pull/8162), [#8168](https://github.com/MetaMask/core/pull/8168)) diff --git a/packages/transaction-pay-controller/package.json b/packages/transaction-pay-controller/package.json index c4345e7d81d..20db5ff8e64 100644 --- a/packages/transaction-pay-controller/package.json +++ b/packages/transaction-pay-controller/package.json @@ -51,6 +51,8 @@ "@ethersproject/abi": "^5.7.0", "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.0", + "@metamask/app-metadata-controller": "^2.0.0", + "@metamask/assets-controller": "^2.3.0", "@metamask/assets-controllers": "^100.2.1", "@metamask/base-controller": "^9.0.0", "@metamask/bridge-controller": "^69.1.0", diff --git a/packages/transaction-pay-controller/src/tests/messenger-mock.ts b/packages/transaction-pay-controller/src/tests/messenger-mock.ts index b6d69d4f22d..c161a324884 100644 --- a/packages/transaction-pay-controller/src/tests/messenger-mock.ts +++ b/packages/transaction-pay-controller/src/tests/messenger-mock.ts @@ -1,3 +1,4 @@ +import type { AppMetadataControllerGetStateAction } from '@metamask/app-metadata-controller'; import type { TokensControllerGetStateAction } from '@metamask/assets-controllers'; import type { TokenBalancesControllerGetStateAction } from '@metamask/assets-controllers'; import type { TokenRatesControllerGetStateAction } from '@metamask/assets-controllers'; @@ -45,6 +46,10 @@ type RootMessenger = Messenger; export function getMessengerMock({ skipRegister, }: { skipRegister?: boolean } = {}) { + const getAppMetadataControllerStateMock: jest.MockedFn< + AppMetadataControllerGetStateAction['handler'] + > = jest.fn(); + const getControllerStateMock: jest.MockedFn< TransactionPayControllerGetStateAction['handler'] > = jest.fn(); @@ -127,6 +132,8 @@ export function getMessengerMock({ TransactionControllerEstimateGasBatchAction['handler'] > = jest.fn(); + const getAssetsControllerStateMock = jest.fn(); + const messenger: RootMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE, }); @@ -241,12 +248,24 @@ export function getMessengerMock({ 'TransactionController:estimateGasBatch', estimateGasBatchMock, ); + + messenger.registerActionHandler( + 'AppMetadataController:getState', + getAppMetadataControllerStateMock, + ); + + messenger.registerActionHandler( + 'AssetsController:getStateForTransactionPay', + getAssetsControllerStateMock, + ); } const publish = messenger.publish.bind(messenger); return { addTransactionMock, + getAppMetadataControllerStateMock, + getAssetsControllerStateMock, addTransactionBatchMock, estimateGasMock, estimateGasBatchMock, diff --git a/packages/transaction-pay-controller/src/types.ts b/packages/transaction-pay-controller/src/types.ts index ff99540dac5..481f7b3271d 100644 --- a/packages/transaction-pay-controller/src/types.ts +++ b/packages/transaction-pay-controller/src/types.ts @@ -1,3 +1,5 @@ +import type { AppMetadataControllerGetStateAction } from '@metamask/app-metadata-controller'; +import type { AssetsControllerGetStateForTransactionPayAction } from '@metamask/assets-controller'; import type { CurrencyRateControllerActions, TokenBalancesControllerGetStateAction, @@ -38,6 +40,8 @@ import type { CONTROLLER_NAME, TransactionPayStrategy } from './constants'; export type AllowedActions = | AccountTrackerControllerGetStateAction + | AppMetadataControllerGetStateAction + | AssetsControllerGetStateForTransactionPayAction | BridgeControllerActions | BridgeStatusControllerActions | CurrencyRateControllerActions diff --git a/packages/transaction-pay-controller/src/utils/feature-flags.test.ts b/packages/transaction-pay-controller/src/utils/feature-flags.test.ts index 8711713267c..d349573aad8 100644 --- a/packages/transaction-pay-controller/src/utils/feature-flags.test.ts +++ b/packages/transaction-pay-controller/src/utils/feature-flags.test.ts @@ -9,6 +9,7 @@ import { DEFAULT_RELAY_QUOTE_URL, DEFAULT_SLIPPAGE, DEFAULT_STRATEGY_ORDER, + getAssetsUnifyStateFeature, getFallbackGas, DEFAULT_RELAY_EXECUTE_URL, getRelayOriginGasOverhead, @@ -38,8 +39,11 @@ const TOKEN_ADDRESS_DIFFERENT_MOCK = '0xdef789abc012' as Hex; const TOKEN_SPECIFIC_SLIPPAGE_MOCK = 0.02; describe('Feature Flags Utils', () => { - const { messenger, getRemoteFeatureFlagControllerStateMock } = - getMessengerMock(); + const { + messenger, + getAppMetadataControllerStateMock, + getRemoteFeatureFlagControllerStateMock, + } = getMessengerMock(); beforeEach(() => { jest.resetAllMocks(); @@ -562,6 +566,111 @@ describe('Feature Flags Utils', () => { }); }); + describe('getAssetsUnifyStateFeature', () => { + it('returns false when assetsUnifyState is not set', () => { + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(false); + }); + + it('returns false when assetsUnifyState.enabled is false', () => { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: false, + featureVersion: '1', + minimumVersion: null, + }, + }, + }); + + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(false); + }); + + it('returns false when featureVersion does not match expected version', () => { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: true, + featureVersion: '2', + minimumVersion: null, + }, + }, + }); + + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(false); + }); + + it('returns true when minimumVersion is null', () => { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: true, + featureVersion: '1', + minimumVersion: null, + }, + }, + }); + + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(true); + }); + + it('returns false when app version does not satisfy minimumVersion', () => { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: true, + featureVersion: '1', + minimumVersion: '2.0.0', + }, + }, + }); + getAppMetadataControllerStateMock.mockReturnValue({ + currentAppVersion: '1.0.0', + previousAppVersion: '', + previousMigrationVersion: 0, + currentMigrationVersion: 0, + }); + + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(false); + }); + + it('returns true when app version satisfies minimumVersion', () => { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: true, + featureVersion: '1', + minimumVersion: '1.0.0', + }, + }, + }); + getAppMetadataControllerStateMock.mockReturnValue({ + currentAppVersion: '2.0.0', + previousAppVersion: '', + previousMigrationVersion: 0, + currentMigrationVersion: 0, + }); + + const result = getAssetsUnifyStateFeature(messenger); + + expect(result).toBe(true); + }); + }); + describe('getStrategyOrder', () => { it('returns default strategy order when none is set', () => { const strategyOrder = getStrategyOrder(messenger); diff --git a/packages/transaction-pay-controller/src/utils/feature-flags.ts b/packages/transaction-pay-controller/src/utils/feature-flags.ts index 1307150cad0..a5d4a90ba4b 100644 --- a/packages/transaction-pay-controller/src/utils/feature-flags.ts +++ b/packages/transaction-pay-controller/src/utils/feature-flags.ts @@ -1,5 +1,10 @@ import type { Hex } from '@metamask/utils'; -import { createModuleLogger } from '@metamask/utils'; +import { + createModuleLogger, + isValidSemVerRange, + isValidSemVerVersion, + satisfiesVersionRange, +} from '@metamask/utils'; import { uniq } from 'lodash'; import type { TransactionPayControllerMessenger } from '..'; @@ -297,6 +302,64 @@ export function getSlippage( return slippage; } +/** + * Get the AssetsUnifyState feature flag state. + * + * @param messenger - Controller messenger. + * @returns True if the assets unify state feature is enabled, false otherwise. + */ +export function getAssetsUnifyStateFeature( + messenger: TransactionPayControllerMessenger, +): boolean { + const state = messenger.call('RemoteFeatureFlagController:getState'); + const assetsUnifyState = state.remoteFeatureFlags.assetsUnifyState as + | { + enabled: boolean; + featureVersion: string | null; + minimumVersion: string | null; + } + | undefined; + + if (!assetsUnifyState?.enabled) { + return false; + } + + const AssetsUnifyStateFeatureVersion = '1'; + + return ( + assetsUnifyState.featureVersion === AssetsUnifyStateFeatureVersion && + hasMinimumRequiredVersion(messenger, assetsUnifyState.minimumVersion) + ); +} + +/** + * Check if the app version satisfies the minimum required version. + * + * @param messenger - Controller messenger. + * @param minRequiredVersion - The minimum required version. + * @returns True if the app version satisfies the minimum required version, false otherwise. + */ +function hasMinimumRequiredVersion( + messenger: TransactionPayControllerMessenger, + minRequiredVersion: string | null, +): boolean { + if (!minRequiredVersion) { + return true; + } + + const appVersion = messenger.call( + 'AppMetadataController:getState', + )?.currentAppVersion; + + const semverRange = `>=${minRequiredVersion}`; + + return ( + isValidSemVerVersion(appVersion) && + isValidSemVerRange(semverRange) && + satisfiesVersionRange(appVersion, semverRange) + ); +} + /** * Get a value from a record using a case-insensitive key lookup. * diff --git a/packages/transaction-pay-controller/src/utils/token.test.ts b/packages/transaction-pay-controller/src/utils/token.test.ts index 46a0a03017b..e24338cca8d 100644 --- a/packages/transaction-pay-controller/src/utils/token.test.ts +++ b/packages/transaction-pay-controller/src/utils/token.test.ts @@ -10,13 +10,13 @@ import { getTokenBalance, getTokenInfo, getTokenFiatRate, - getAllTokenBalances, getNativeToken, isSameToken, getLiveTokenBalance, normalizeTokenAddress, TokenAddressTarget, } from './token'; +import { getDefaultRemoteFeatureFlagControllerState } from '../../../remote-feature-flag-controller/src/remote-feature-flag-controller'; import { CHAIN_ID_POLYGON, NATIVE_TOKEN_ADDRESS, @@ -50,6 +50,8 @@ const PROVIDER_MOCK = { request: jest.fn() }; describe('Token Utils', () => { const { messenger, + getAssetsControllerStateMock, + getRemoteFeatureFlagControllerStateMock, getTokensControllerStateMock, getNetworkClientByIdMock, getTokenBalanceControllerStateMock, @@ -68,6 +70,10 @@ describe('Token Utils', () => { mockBalanceOf = jest.fn(); mockGetBalance = jest.fn(); + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + }); + findNetworkClientIdByChainIdMock.mockReturnValue(NETWORK_CLIENT_ID_MOCK); getNetworkClientByIdMock.mockReturnValue({ @@ -84,7 +90,44 @@ describe('Token Utils', () => { })); }); + function enableAssetsUnifyState(): void { + getRemoteFeatureFlagControllerStateMock.mockReturnValue({ + ...getDefaultRemoteFeatureFlagControllerState(), + remoteFeatureFlags: { + assetsUnifyState: { + enabled: true, + featureVersion: '1', + minimumVersion: null, + }, + }, + }); + } + describe('getTokenInfo', () => { + it('returns decimals and symbol from AssetsController when assets unify state feature is enabled', () => { + enableAssetsUnifyState(); + getAssetsControllerStateMock.mockReturnValue({ + allTokens: { + [CHAIN_ID_MOCK]: { + test123: [ + { + address: TOKEN_ADDRESS_MOCK.toLowerCase() as Hex, + decimals: DECIMALS_MOCK, + symbol: SYMBOL_MOCK, + }, + ], + }, + }, + }); + + const result = getTokenInfo(messenger, TOKEN_ADDRESS_MOCK, CHAIN_ID_MOCK); + + expect(result).toStrictEqual({ + decimals: DECIMALS_MOCK, + symbol: SYMBOL_MOCK, + }); + }); + it('returns decimals and symbol from controller state', () => { getTokensControllerStateMock.mockReturnValue({ allTokens: { @@ -192,6 +235,51 @@ describe('Token Utils', () => { }); describe('getTokenBalance', () => { + it('returns token balance from AssetsController when assets unify state feature is enabled', () => { + enableAssetsUnifyState(); + getAssetsControllerStateMock.mockReturnValue({ + tokenBalances: { + [FROM_MOCK]: { + [CHAIN_ID_MOCK]: { + [TOKEN_ADDRESS_MOCK]: BALANCE_MOCK, + }, + }, + }, + }); + + const result = getTokenBalance( + messenger, + FROM_MOCK, + CHAIN_ID_MOCK, + TOKEN_ADDRESS_MOCK.toLowerCase() as Hex, + ); + + expect(result).toBe('291'); + }); + + it('returns native balance from AssetsController when assets unify state feature is enabled', () => { + enableAssetsUnifyState(); + getAssetsControllerStateMock.mockReturnValue({ + tokenBalances: {}, + accountsByChainId: { + [CHAIN_ID_MOCK]: { + [FROM_MOCK]: { + balance: '0x123', + }, + }, + }, + }); + + const result = getTokenBalance( + messenger, + FROM_MOCK, + CHAIN_ID_MOCK, + NATIVE_TOKEN_ADDRESS, + ); + + expect(result).toBe('291'); + }); + it('returns balance from controller state', () => { getTokenBalanceControllerStateMock.mockReturnValue({ tokenBalances: { @@ -278,6 +366,37 @@ describe('Token Utils', () => { }); describe('getTokenFiatRate', () => { + it('returns fiat rates from AssetsController when assets unify state feature is enabled', () => { + enableAssetsUnifyState(); + + getAssetsControllerStateMock.mockReturnValue({ + marketData: { + [CHAIN_ID_MOCK]: { + [TOKEN_ADDRESS_MOCK]: { + price: 2.0, + }, + }, + }, + currencyRates: { + [TICKER_MOCK]: { + conversionRate: 3.0, + usdConversionRate: 4.0, + }, + }, + }); + + const result = getTokenFiatRate( + messenger, + TOKEN_ADDRESS_MOCK, + CHAIN_ID_MOCK, + ); + + expect(result).toStrictEqual({ + fiatRate: '6', + usdRate: '8', + }); + }); + it('returns fiat rates', () => { findNetworkClientIdByChainIdMock.mockReturnValue(NETWORK_CLIENT_ID_MOCK); @@ -630,55 +749,6 @@ describe('Token Utils', () => { }); }); - describe('getAllTokenBalances', () => { - it('returns all token balances including native token', () => { - getTokenBalanceControllerStateMock.mockReturnValue({ - tokenBalances: { - [FROM_MOCK]: { - '0x1': { - [TOKEN_ADDRESS_MOCK]: '0x10', - [TOKEN_ADDRESS_2_MOCK]: '0x20', - }, - '0x2': { - [TOKEN_ADDRESS_MOCK]: '0x30', - }, - }, - }, - }); - - getAccountTrackerControllerStateMock.mockReturnValue({ - accountsByChainId: { - '0x1': { - [FROM_MOCK]: { - balance: '0x40', - }, - }, - '0x2': { - [FROM_MOCK]: { - balance: '0x50', - }, - }, - '0x3': { - [FROM_MOCK]: { - balance: '0x60', - }, - }, - }, - }); - - const result = getAllTokenBalances(messenger, FROM_MOCK); - - expect(result).toStrictEqual([ - { chainId: '0x1', tokenAddress: TOKEN_ADDRESS_MOCK, balance: '16' }, - { chainId: '0x1', tokenAddress: TOKEN_ADDRESS_2_MOCK, balance: '32' }, - { chainId: '0x1', tokenAddress: NATIVE_TOKEN_ADDRESS, balance: '64' }, - { chainId: '0x2', tokenAddress: TOKEN_ADDRESS_MOCK, balance: '48' }, - { chainId: '0x2', tokenAddress: NATIVE_TOKEN_ADDRESS, balance: '80' }, - { chainId: '0x3', tokenAddress: NATIVE_TOKEN_ADDRESS, balance: '96' }, - ]); - }); - }); - describe('isSameToken', () => { it('returns true for same address and chain', () => { const token1 = { address: TOKEN_ADDRESS_MOCK, chainId: CHAIN_ID_MOCK }; diff --git a/packages/transaction-pay-controller/src/utils/token.ts b/packages/transaction-pay-controller/src/utils/token.ts index cc3d33f448c..2dc9e9acad0 100644 --- a/packages/transaction-pay-controller/src/utils/token.ts +++ b/packages/transaction-pay-controller/src/utils/token.ts @@ -1,11 +1,16 @@ import { Contract } from '@ethersproject/contracts'; import { Web3Provider } from '@ethersproject/providers'; +import { + AccountTrackerControllerState, + TokenBalancesControllerState, + TokensControllerState, +} from '@metamask/assets-controllers'; import { toChecksumHexAddress } from '@metamask/controller-utils'; import { abiERC20 } from '@metamask/metamask-eth-abis'; import type { Hex } from '@metamask/utils'; import { BigNumber } from 'bignumber.js'; -import { uniq } from 'lodash'; +import { getAssetsUnifyStateFeature } from './feature-flags'; import { CHAIN_ID_POLYGON, NATIVE_TOKEN_ADDRESS, @@ -49,16 +54,38 @@ export function getTokenBalance( chainId: Hex, tokenAddress: Hex, ): string { - const tokenBalanceControllerState = messenger.call( - 'TokenBalancesController:getState', - ); + const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger); + + let getTokenBalances; + let getAccountsByChainId; + if (assetsUnifyStateFeatureEnabled) { + const assetsControllerState = messenger.call( + 'AssetsController:getStateForTransactionPay', + ); + + getTokenBalances = (): + | TokenBalancesControllerState['tokenBalances'] + | undefined => assetsControllerState?.tokenBalances; + getAccountsByChainId = (): + | AccountTrackerControllerState['accountsByChainId'] + | undefined => assetsControllerState?.accountsByChainId; + } else { + getTokenBalances = (): + | TokenBalancesControllerState['tokenBalances'] + | undefined => + messenger.call('TokenBalancesController:getState')?.tokenBalances; + getAccountsByChainId = (): + | AccountTrackerControllerState['accountsByChainId'] + | undefined => + messenger.call('AccountTrackerController:getState')?.accountsByChainId; + } const normalizedAccount = account.toLowerCase() as Hex; const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex; const isNative = normalizedTokenAddress === getNativeToken(chainId); const balanceHex = - tokenBalanceControllerState.tokenBalances?.[normalizedAccount]?.[chainId]?.[ + getTokenBalances()?.[normalizedAccount]?.[chainId]?.[ normalizedTokenAddress ]; @@ -70,12 +97,7 @@ export function getTokenBalance( return new BigNumber(balanceHex, 16).toString(10); } - const accountTrackerControllerState = messenger.call( - 'AccountTrackerController:getState', - ); - - const chainAccounts = - accountTrackerControllerState.accountsByChainId?.[chainId]; + const chainAccounts = getAccountsByChainId()?.[chainId]; const checksumAccount = toChecksumHexAddress(normalizedAccount) as Hex; const nativeBalanceHex = chainAccounts?.[checksumAccount]?.balance as Hex; @@ -83,55 +105,6 @@ export function getTokenBalance( return new BigNumber(nativeBalanceHex ?? '0x0', 16).toString(10); } -/** - * Get the token balance for a specific account and token. - * - * @param messenger - Controller messenger. - * @param account - Address of the account. - * @returns The token balance as a BigNumber. - */ -export function getAllTokenBalances( - messenger: TransactionPayControllerMessenger, - account: Hex, -): { - balance: string; - chainId: Hex; - tokenAddress: Hex; -}[] { - const tokenBalanceControllerState = messenger.call( - 'TokenBalancesController:getState', - ); - - const accountTrackerControllerState = messenger.call( - 'AccountTrackerController:getState', - ); - - const nativeChainIds = Object.keys( - accountTrackerControllerState.accountsByChainId, - ) as Hex[]; - - const normalizedAccount = account.toLowerCase() as Hex; - - const balancesByTokenByChain = - tokenBalanceControllerState.tokenBalances?.[normalizedAccount]; - - const tokenChainIds = Object.keys(balancesByTokenByChain) as Hex[]; - const chainIds = uniq([...tokenChainIds, ...nativeChainIds]); - - return chainIds.flatMap((chainId) => { - const tokenAddresses = [ - ...(Object.keys(balancesByTokenByChain[chainId] ?? {}) as Hex[]), - getNativeToken(chainId), - ]; - - return tokenAddresses.map((tokenAddress) => ({ - chainId, - tokenAddress, - balance: getTokenBalance(messenger, account, chainId, tokenAddress), - })); - }); -} - /** * Get the token decimals for a specific token. * @@ -145,13 +118,23 @@ export function getTokenInfo( tokenAddress: Hex, chainId: Hex, ): { decimals: number; symbol: string } | undefined { - const controllerState = messenger.call('TokensController:getState'); + const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger); + + let allTokens: TokensControllerState['allTokens']; + if (assetsUnifyStateFeatureEnabled) { + allTokens = messenger.call( + 'AssetsController:getStateForTransactionPay', + )?.allTokens; + } else { + allTokens = messenger.call('TokensController:getState')?.allTokens; + } + const normalizedTokenAddress = tokenAddress.toLowerCase() as Hex; const isNative = normalizedTokenAddress === getNativeToken(chainId).toLowerCase(); - const token = Object.values(controllerState.allTokens?.[chainId] ?? {}) + const token = Object.values(allTokens?.[chainId] ?? {}) .flat() .find( (singleToken) => @@ -188,23 +171,35 @@ export function getTokenFiatRate( tokenAddress: Hex, chainId: Hex, ): FiatRates | undefined { + const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger); + + let marketData; + let currencyRates; + if (assetsUnifyStateFeatureEnabled) { + const assetsControllerState = messenger.call( + 'AssetsController:getStateForTransactionPay', + ); + + marketData = assetsControllerState?.marketData; + currencyRates = assetsControllerState?.currencyRates; + } else { + marketData = messenger.call('TokenRatesController:getState')?.marketData; + currencyRates = messenger.call( + 'CurrencyRateController:getState', + )?.currencyRates; + } + const ticker = getTicker(chainId, messenger); if (!ticker) { return undefined; } - const rateControllerState = messenger.call('TokenRatesController:getState'); - - const currencyRateControllerState = messenger.call( - 'CurrencyRateController:getState', - ); - const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex; const isNative = normalizedTokenAddress === getNativeToken(chainId); const tokenToNativeRate = - rateControllerState.marketData?.[chainId]?.[normalizedTokenAddress]?.price; + marketData?.[chainId]?.[normalizedTokenAddress]?.price; if (tokenToNativeRate === undefined && !isNative) { return undefined; @@ -213,7 +208,7 @@ export function getTokenFiatRate( const { conversionRate: nativeToFiatRate, usdConversionRate: nativeToUsdRate, - } = currencyRateControllerState.currencyRates?.[ticker] ?? { + } = currencyRates?.[ticker] ?? { conversionRate: null, usdConversionRate: null, }; diff --git a/packages/transaction-pay-controller/tsconfig.build.json b/packages/transaction-pay-controller/tsconfig.build.json index aa8dd9cb92e..8d530779845 100644 --- a/packages/transaction-pay-controller/tsconfig.build.json +++ b/packages/transaction-pay-controller/tsconfig.build.json @@ -6,6 +6,12 @@ "rootDir": "./src" }, "references": [ + { + "path": "../app-metadata-controller/tsconfig.build.json" + }, + { + "path": "../assets-controller/tsconfig.build.json" + }, { "path": "../assets-controllers/tsconfig.build.json" }, diff --git a/packages/transaction-pay-controller/tsconfig.json b/packages/transaction-pay-controller/tsconfig.json index 0452cae3d20..e9e8544595e 100644 --- a/packages/transaction-pay-controller/tsconfig.json +++ b/packages/transaction-pay-controller/tsconfig.json @@ -4,6 +4,12 @@ "baseUrl": "./" }, "references": [ + { + "path": "../app-metadata-controller" + }, + { + "path": "../assets-controller" + }, { "path": "../assets-controllers" }, diff --git a/yarn.lock b/yarn.lock index 5a654440c02..654c86f60cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2720,7 +2720,7 @@ __metadata: languageName: node linkType: hard -"@metamask/app-metadata-controller@workspace:packages/app-metadata-controller": +"@metamask/app-metadata-controller@npm:^2.0.0, @metamask/app-metadata-controller@workspace:packages/app-metadata-controller": version: 0.0.0-use.local resolution: "@metamask/app-metadata-controller@workspace:packages/app-metadata-controller" dependencies: @@ -5417,6 +5417,8 @@ __metadata: "@ethersproject/abi": "npm:^5.7.0" "@ethersproject/contracts": "npm:^5.7.0" "@ethersproject/providers": "npm:^5.7.0" + "@metamask/app-metadata-controller": "npm:^2.0.0" + "@metamask/assets-controller": "npm:^2.3.0" "@metamask/assets-controllers": "npm:^100.2.1" "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^9.0.0"