mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Fix account selectors when balances are missing (#20385)
* Fix account selectors when balances are missing Some of the account selectors we use would return an empty set of accounts if the `AccountTracker` state was missing. This resulted in UI crashes when trying to access the current selected account. The selectors have been updated to use the `identities` as the source- of-truth for the full set of accounts. This ensures that even if the balances are missing, each account will at least be represented by an empty object. * Fix unit test * Fix another unit test * Fix another unit test * Fix another unit test * Fix more unit tests --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com>
This commit is contained in:
parent
c3f907fe4f
commit
3044aa0ebe
@ -61,6 +61,9 @@ const render = ({ txProps, contextProps } = {}) => {
|
||||
balance: '0x1F4',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
gasFeeEstimates: MOCK_FEE_ESTIMATE,
|
||||
|
@ -67,6 +67,9 @@ const renderComponent = ({
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
gasEstimateType: 'fee-market',
|
||||
|
@ -41,6 +41,9 @@ const renderComponent = (componentProps) => {
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
},
|
||||
|
@ -28,6 +28,9 @@ const render = () => {
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
},
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ import withModalProps from '../../../helpers/higher-order-components/with-modal-
|
||||
import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils';
|
||||
import { mmiActionsFactory } from '../../../store/institutional/institution-background';
|
||||
import { setSelectedAddress } from '../../../store/actions';
|
||||
import { getMetaMaskAccountsRaw } from '../../../selectors';
|
||||
import { getMetaMaskIdentities } from '../../../selectors';
|
||||
import {
|
||||
getMMIAddressFromModalOrAddress,
|
||||
getCustodyAccountDetails,
|
||||
@ -42,7 +42,7 @@ const CustodyConfirmLink = ({ hideModal }) => {
|
||||
const dispatch = useDispatch();
|
||||
const mmiActions = mmiActionsFactory();
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
const mmiAccounts = useSelector(getMetaMaskAccountsRaw);
|
||||
const mmiAccounts = useSelector(getMetaMaskIdentities);
|
||||
const address = useSelector(getMMIAddressFromModalOrAddress);
|
||||
const custodyAccountDetails = useSelector(getCustodyAccountDetails);
|
||||
const { custodians } = useSelector(getMMIConfiguration);
|
||||
|
@ -1598,6 +1598,9 @@ describe('Send Slice', () => {
|
||||
address: mockAddress1,
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
},
|
||||
send: {
|
||||
...getInitialSendStateWithExistingTxState({
|
||||
@ -2387,7 +2390,9 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
@ -2522,7 +2527,9 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
@ -2705,7 +2712,9 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
|
@ -290,28 +290,38 @@ export function deprecatedGetCurrentNetworkId(state) {
|
||||
return state.metamask.networkId ?? 'loading';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MetaMask accounts, including account name and balance.
|
||||
*/
|
||||
export const getMetaMaskAccounts = createSelector(
|
||||
getMetaMaskAccountsRaw,
|
||||
getMetaMaskIdentities,
|
||||
getMetaMaskAccountBalances,
|
||||
getMetaMaskCachedBalances,
|
||||
(currentAccounts, cachedBalances) =>
|
||||
Object.entries(currentAccounts).reduce(
|
||||
(selectedAccounts, [accountID, account]) => {
|
||||
if (account.balance === null || account.balance === undefined) {
|
||||
return {
|
||||
...selectedAccounts,
|
||||
[accountID]: {
|
||||
(identities, balances, cachedBalances) =>
|
||||
Object.keys(identities).reduce((accounts, address) => {
|
||||
// TODO: mix in the identity state here as well, consolidating this
|
||||
// selector with `accountsWithSendEtherInfoSelector`
|
||||
let account = {};
|
||||
|
||||
if (balances[address]) {
|
||||
account = {
|
||||
...account,
|
||||
balance: cachedBalances && cachedBalances[accountID],
|
||||
},
|
||||
...balances[address],
|
||||
};
|
||||
}
|
||||
return {
|
||||
...selectedAccounts,
|
||||
[accountID]: account,
|
||||
|
||||
if (account.balance === null || account.balance === undefined) {
|
||||
account = {
|
||||
...account,
|
||||
balance: cachedBalances && cachedBalances[address],
|
||||
};
|
||||
},
|
||||
{},
|
||||
),
|
||||
}
|
||||
|
||||
return {
|
||||
...accounts,
|
||||
[address]: account,
|
||||
};
|
||||
}, {}),
|
||||
);
|
||||
|
||||
export function getSelectedAddress(state) {
|
||||
@ -334,11 +344,23 @@ export function getMetaMaskKeyrings(state) {
|
||||
return state.metamask.keyrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get identity state.
|
||||
*
|
||||
* @param {object} state - Redux state
|
||||
* @returns {object} A map of account addresses to identities (which includes the account name)
|
||||
*/
|
||||
export function getMetaMaskIdentities(state) {
|
||||
return state.metamask.identities;
|
||||
}
|
||||
|
||||
export function getMetaMaskAccountsRaw(state) {
|
||||
/**
|
||||
* Get account balances state.
|
||||
*
|
||||
* @param {object} state - Redux state
|
||||
* @returns {object} A map of account addresses to account objects (which includes the account balance)
|
||||
*/
|
||||
export function getMetaMaskAccountBalances(state) {
|
||||
return state.metamask.accounts;
|
||||
}
|
||||
|
||||
@ -376,8 +398,8 @@ export const getMetaMaskAccountsConnected = createSelector(
|
||||
);
|
||||
|
||||
export function isBalanceCached(state) {
|
||||
const selectedAccount = state.metamask.accounts[getSelectedAddress(state)];
|
||||
const selectedAccountBalance = selectedAccount && selectedAccount.balance;
|
||||
const selectedAccountBalance =
|
||||
getMetaMaskAccountBalances(state)[getSelectedAddress(state)]?.balance;
|
||||
const cachedBalance = getSelectedAccountCachedBalance(state);
|
||||
|
||||
return Boolean(!selectedAccountBalance && cachedBalance);
|
||||
|
@ -244,6 +244,9 @@ describe('Actions', () => {
|
||||
'0xAnotherAddress': '0x0',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAnotherAddress': {},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@ -1942,6 +1945,9 @@ describe('Actions', () => {
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xFirstAddress': {},
|
||||
},
|
||||
cachedBalances: {
|
||||
'0x1': {
|
||||
'0xFirstAddress': '0x0',
|
||||
|
Loading…
Reference in New Issue
Block a user