From 31f3fec80e8c3bf8b7f5a3202547e185a72a2e48 Mon Sep 17 00:00:00 2001 From: Owen Craston Date: Wed, 11 Dec 2024 17:42:55 -0800 Subject: [PATCH] scaffold selectors --- app/reducers/multichain/index.ts | 4 +- app/selectors/multichain.ts | 198 ++++++++++++++++++++++++++++++- 2 files changed, 199 insertions(+), 3 deletions(-) diff --git a/app/reducers/multichain/index.ts b/app/reducers/multichain/index.ts index 667897d90236..4c33bfd09e95 100644 --- a/app/reducers/multichain/index.ts +++ b/app/reducers/multichain/index.ts @@ -1,8 +1,8 @@ import { MultichainSettingsState } from '../../actions/multichain/state'; export const initialState: MultichainSettingsState = { - bitcoinSupportEnabled: false, - bitcoinTestnetSupportEnabled: false, + bitcoinSupportEnabled: true, + bitcoinTestnetSupportEnabled: true, }; const multichainReducer = (state = initialState) => state; diff --git a/app/selectors/multichain.ts b/app/selectors/multichain.ts index 08b6436874f3..6170ee5968d3 100644 --- a/app/selectors/multichain.ts +++ b/app/selectors/multichain.ts @@ -8,15 +8,27 @@ import { } from './accountsController'; import { selectAllTokens } from './tokensController'; import { selectAccountsByChainId } from './accountTrackerController'; -import { selectNetworkConfigurations } from './networkController'; +import { + selectChainId, + selectNetworkConfigurations, + selectProviderConfig, + selectTicker, +} from './networkController'; import { TokenI } from '../components/UI/Tokens/types'; import { renderFromWei } from '../util/number'; import { toHex } from '@metamask/controller-utils'; import { + selectConversionRate, selectCurrencyRates, selectCurrentCurrency, } from './currencyRateController'; +import { + isBtcTestnetAddress, + isBtcMainnetAddress, +} from '../core/Multichain/utils'; import { selectTokenMarketData } from './tokenRatesController'; +import { isMainNet, isTestNet } from '../util/networks'; +import { isEvmAccountType } from '@metamask/keyring-api'; interface NativeTokenBalance { balance: string; @@ -232,3 +244,187 @@ export function selectIsBitcoinSupportEnabled(state: RootState) { export function selectIsBitcoinTestnetSupportEnabled(state: RootState) { return state.multichainSettings.bitcoinTestnetSupportEnabled; } + +export const selectMultichainIsEvm = createSelector( + selectSelectedInternalAccount, + (selectedAccount) => { + // If no account selected, assume EVM for onboarding scenario + if (!selectedAccount) { + return true; + } + return isEvmAccountType(selectedAccount.type); + }, +); + +export const selectMultichainDefaultToken = createSelector( + selectMultichainIsEvm, + selectProviderConfig, + (isEvm, providerConfig) => { + const symbol = isEvm + ? providerConfig?.ticker ?? 'ETH' + : providerConfig?.ticker; + return { symbol }; + }, +); + +export const selectMultichainIsBitcoin = createSelector( + selectMultichainIsEvm, + selectMultichainDefaultToken, + (isEvm, token) => !isEvm && token.symbol === 'BTC', +); + +export const selectMultichainProviderConfig = createSelector( + selectProviderConfig, + (providerConfig) => providerConfig, +); + +export const selectMultichainCurrentNetwork = selectMultichainProviderConfig; + +export const selectMultichainNativeCurrency = createSelector( + selectMultichainIsEvm, + selectTicker, + selectProviderConfig, + (isEvm, ticker, providerConfig) => (isEvm ? ticker : providerConfig?.ticker), +); + +export const selectMultichainCurrentCurrency = createSelector( + selectMultichainIsEvm, + selectCurrentCurrency, + selectProviderConfig, + (isEvm, currentCurrency, providerConfig) => { + if (isEvm) { + return currentCurrency; + } + // For non-EVM: + return currentCurrency?.toLowerCase() === 'usd' + ? 'usd' + : providerConfig.ticker; + }, +); + +export const selectMultichainShouldShowFiat = createSelector( + selectMultichainIsEvm, + selectChainId, + (state: RootState) => state.settings.showFiatOnTestnets, + selectSelectedInternalAccount, + selectMultichainIsBitcoin, + (isEvm, chainId, showFiatOnTestnets, selectedAccount, isBitcoin) => { + if (isEvm) { + // EVM logic: show fiat on mainnet or showFiatOnTestnets if testnet + if (!isTestNet(chainId)) { + return true; // mainnet + } + return showFiatOnTestnets; + } + + // Non-EVM logic: currently we only have Bitcoin as example + // Show fiat if mainnet or if testnet + showFiatOnTestnets is true + if (isBitcoin && selectedAccount) { + const isMainnet = isBtcMainnetAddress(selectedAccount.address); + const isTestnet = isBtcTestnetAddress(selectedAccount.address); + + if (isMainnet) return true; + if (isTestnet) return showFiatOnTestnets; + } + + // If other non-EVM networks are supported, adjust logic as needed. + return true; + }, +); + +export const selectMultichainCurrentChainId = selectChainId; + +export const selectMultichainIsMainnet = createSelector( + selectMultichainIsEvm, + selectSelectedInternalAccount, + selectChainId, + selectMultichainIsBitcoin, + (isEvm, selectedAccount, chainId, isBitcoin) => { + if (isEvm) { + return isMainNet(chainId); + } + + // Non-EVM: Currently only Bitcoin + if (isBitcoin && selectedAccount) { + return isBtcMainnetAddress(selectedAccount.address); + } + + // If other non-EVM networks: adjust accordingly + return false; + }, +); + +export const selectMultichainIsTestnet = createSelector( + selectMultichainIsEvm, + selectSelectedInternalAccount, + selectChainId, + selectMultichainIsBitcoin, + (isEvm, selectedAccount, chainId, isBitcoin) => { + if (isEvm) { + return isTestNet(chainId); + } + + if (isBitcoin && selectedAccount) { + return isBtcTestnetAddress(selectedAccount.address); + } + + // For other non-EVM networks, implement similar logic + return false; + }, +); + +/** + * If MultichainBalancesController state is integrated into the engine background state, + * adapt the following selector. If not, please provide that part of the state so we can adjust. + */ +export const selectMultichainBalances = createSelector( + // Placeholder: adapt to where balances from MultichainBalancesController are stored. + (state: RootState) => + state.engine.backgroundState.MultichainBalancesController?.balances ?? {}, + (balances) => balances, +); + +export const selectMultichainCoinRates = selectCurrencyRates; + +export const selectMultichainSelectedAccountCachedBalance = createSelector( + selectSelectedInternalAccountFormattedAddress, + selectAccountsByChainId, + selectMultichainIsEvm, + selectChainId, + selectSelectedInternalAccount, + (selectedAddress, accountsByChainId, isEvm, chainId, selectedAccount) => { + if (!selectedAddress || !chainId) return '0x0'; + const account = accountsByChainId[chainId]?.[selectedAddress]; + if (!account) return '0x0'; + + // For EVM: `account.balance` should be a hex string (e.g. '0x1234...') + // For Bitcoin: If the MultichainBalancesController stores balance as a decimal or something else, + // convert or adapt accordingly. If it stores amounts in sats, for example, convert if needed. + return account.balance || '0x0'; + }, +); + +export const selectMultichainSelectedAccountCachedBalanceIsZero = + createSelector( + selectMultichainSelectedAccountCachedBalance, + selectMultichainIsEvm, + (balance, isEvm) => { + const base = isEvm ? 16 : 10; + const numericValue = parseInt(balance, base); + return numericValue === 0; + }, + ); + +export const selectMultichainConversionRate = createSelector( + selectMultichainIsEvm, + selectConversionRate, + selectCurrencyRates, + selectProviderConfig, + (isEvm, evmConversionRate, currencyRates, providerConfig) => { + if (isEvm) { + return evmConversionRate; + } + const ticker = providerConfig?.ticker?.toLowerCase(); + return ticker ? currencyRates?.[ticker]?.conversionRate : undefined; + }, +);