Skip to content

Commit

Permalink
Merge branch 'main' into fix/transaction-simulation-bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Andepande authored Jan 9, 2025
2 parents 2ffb812 + b1e29d0 commit 7b4102f
Show file tree
Hide file tree
Showing 22 changed files with 1,182 additions and 43 deletions.
36 changes: 23 additions & 13 deletions app/core/Engine/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ import {
getGlobalChainId,
getGlobalNetworkClientId,
} from '../../util/networks/global-network';
import { logEngineCreation } from './utils/logger';

const NON_EMPTY = 'NON_EMPTY';

Expand Down Expand Up @@ -276,6 +277,8 @@ export class Engine {
initialState: Partial<EngineState> = {},
initialKeyringState?: KeyringControllerState | null,
) {
logEngineCreation(initialState, initialKeyringState);

this.controllerMessenger = new ExtendedControllerMessenger();

const isBasicFunctionalityToggleEnabled = () =>
Expand Down Expand Up @@ -971,8 +974,8 @@ export class Engine {
disableSnaps: !isBasicFunctionalityToggleEnabled(),
}),
clientCryptography: {
pbkdf2Sha512: pbkdf2
}
pbkdf2Sha512: pbkdf2,
},
});

const authenticationController = new AuthenticationController.Controller({
Expand Down Expand Up @@ -1173,7 +1176,7 @@ export class Engine {

return Boolean(
hasProperty(showIncomingTransactions, currentChainId) &&
showIncomingTransactions?.[currentHexChainId],
showIncomingTransactions?.[currentHexChainId],
);
},
updateTransactions: true,
Expand Down Expand Up @@ -1305,7 +1308,9 @@ export class Engine {
.addProperties({
token_standard: 'ERC20',
asset_type: 'token',
chain_id: getDecimalChainId(getGlobalChainId(networkController)),
chain_id: getDecimalChainId(
getGlobalChainId(networkController),
),
})
.build(),
),
Expand Down Expand Up @@ -1517,7 +1522,7 @@ export class Engine {
if (
state.networksMetadata[state.selectedNetworkClientId].status ===
NetworkStatus.Available &&
getGlobalChainId(networkController) !== currentChainId
getGlobalChainId(networkController) !== currentChainId
) {
// We should add a state or event emitter saying the provider changed
setTimeout(() => {
Expand All @@ -1537,7 +1542,9 @@ export class Engine {
} catch (error) {
console.error(
error,
`Network ID not changed, current chainId: ${getGlobalChainId(networkController)}`,
`Network ID not changed, current chainId: ${getGlobalChainId(
networkController,
)}`,
);
}
},
Expand Down Expand Up @@ -1775,7 +1782,7 @@ export class Engine {

const tokenBalances =
allTokenBalances?.[selectedInternalAccount.address as Hex]?.[
chainId
chainId
] ?? {};
tokens.forEach(
(item: { address: string; balance?: string; decimals: number }) => {
Expand All @@ -1786,9 +1793,9 @@ export class Engine {
item.balance ||
(item.address in tokenBalances
? renderFromTokenMinimalUnit(
tokenBalances[item.address as Hex],
item.decimals,
)
tokenBalances[item.address as Hex],
item.decimals,
)
: undefined);
const tokenBalanceFiat = balanceToFiatNumber(
// TODO: Fix this by handling or eliminating the undefined case
Expand Down Expand Up @@ -2148,12 +2155,15 @@ export default {
return instance.resetState();
},

destroyEngine() {
instance?.destroyEngineInstance();
destroyEngine: async () => {
await instance?.destroyEngineInstance();
instance = null;
},

init(state: Partial<EngineState> | undefined, keyringState = null) {
init(
state: Partial<EngineState> | undefined,
keyringState: KeyringControllerState | null = null,
) {
instance = Engine.instance || new Engine(state, keyringState);
Object.freeze(instance);
return instance;
Expand Down
54 changes: 54 additions & 0 deletions app/core/Engine/controllers/AccountsController/logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Logger from '../../../../util/Logger';
import { logAccountsControllerCreation } from './logger';
import { defaultAccountsControllerState } from './utils';
import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../../util/test/accountsControllerTestUtils';

jest.mock('../../../../util/Logger');

describe('logAccountsControllerCreation', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('logs creation with default state when no initial state provided', () => {
logAccountsControllerCreation();

expect(Logger.log).toHaveBeenCalledWith(
'Creating AccountsController with default state',
{
defaultState: defaultAccountsControllerState,
},
);
});

it('logs creation with empty initial state', () => {
const initialState = {
internalAccounts: {
accounts: {},
selectedAccount: '',
},
};

logAccountsControllerCreation(initialState);

expect(Logger.log).toHaveBeenCalledWith(
'Creating AccountsController with provided initial state',
{
hasSelectedAccount: false,
accountsCount: 0,
},
);
});

it('logs creation with populated initial state', () => {
logAccountsControllerCreation(MOCK_ACCOUNTS_CONTROLLER_STATE);

expect(Logger.log).toHaveBeenCalledWith(
'Creating AccountsController with provided initial state',
{
hasSelectedAccount: true,
accountsCount: 2,
},
);
});
});
19 changes: 19 additions & 0 deletions app/core/Engine/controllers/AccountsController/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AccountsControllerState } from '@metamask/accounts-controller';
import Logger from '../../../../util/Logger';
import { defaultAccountsControllerState } from './utils';

export function logAccountsControllerCreation(
initialState?: AccountsControllerState,
) {
if (!initialState) {
Logger.log('Creating AccountsController with default state', {
defaultState: defaultAccountsControllerState,
});
} else {
Logger.log('Creating AccountsController with provided initial state', {
hasSelectedAccount: !!initialState.internalAccounts?.selectedAccount,
accountsCount: Object.keys(initialState.internalAccounts?.accounts || {})
.length,
});
}
}
36 changes: 36 additions & 0 deletions app/core/Engine/controllers/AccountsController/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ import {
import { withScope } from '@sentry/react-native';
import { AGREED, METRICS_OPT_IN } from '../../../../constants/storage';
import StorageWrapper from '../../../../store/storage-wrapper';
import { logAccountsControllerCreation } from './logger';

jest.mock('@sentry/react-native', () => ({
withScope: jest.fn(),
}));
jest.mock('./logger', () => ({
logAccountsControllerCreation: jest.fn(),
}));

const mockedWithScope = jest.mocked(withScope);
const mockedLogAccountsControllerCreation = jest.mocked(
logAccountsControllerCreation,
);

describe('accountControllersUtils', () => {
describe('createAccountsController', () => {
Expand Down Expand Up @@ -50,12 +58,38 @@ describe('accountControllersUtils', () => {
jest.resetAllMocks();
});

it('logs creation with default state when no initial state provided', () => {
createAccountsController({
messenger: accountsControllerMessenger,
});
expect(mockedLogAccountsControllerCreation).toHaveBeenCalledWith(
undefined,
);
});

it('logs creation with provided initial state', () => {
const initialState = {
internalAccounts: {
accounts: {},
selectedAccount: '0x1',
},
};
createAccountsController({
messenger: accountsControllerMessenger,
initialState,
});
expect(mockedLogAccountsControllerCreation).toHaveBeenCalledWith(
initialState,
);
});

it('AccountsController state should be default state when no initial state is passed in', () => {
const accountsController = createAccountsController({
messenger: accountsControllerMessenger,
});
expect(accountsController.state).toEqual(defaultAccountsControllerState);
});

it('AccountsController state should be initial state when initial state is passed in', () => {
const initialAccountsControllerState: AccountsControllerState = {
internalAccounts: {
Expand All @@ -69,13 +103,15 @@ describe('accountControllersUtils', () => {
});
expect(accountsController.state).toEqual(initialAccountsControllerState);
});

it('AccountsController name should be AccountsController', () => {
const accountsControllerName = 'AccountsController';
const accountsController = createAccountsController({
messenger: accountsControllerMessenger,
});
expect(accountsController.name).toEqual(accountsControllerName);
});

it('should detect and log an error when controller fails to initialize', async () => {
const brokenAccountsControllerMessenger =
'controllerMessenger' as unknown as AccountsControllerMessenger;
Expand Down
2 changes: 2 additions & 0 deletions app/core/Engine/controllers/AccountsController/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AccountsControllerState,
} from '@metamask/accounts-controller';
import Logger from '../../../../util/Logger';
import { logAccountsControllerCreation } from './logger';

// Default AccountsControllerState
export const defaultAccountsControllerState: AccountsControllerState = {
Expand All @@ -28,6 +29,7 @@ export const createAccountsController = ({
initialState?: AccountsControllerState;
}): AccountsController => {
try {
logAccountsControllerCreation(initialState);
const accountsController = new AccountsController({
messenger,
state: initialState ?? defaultAccountsControllerState,
Expand Down
20 changes: 20 additions & 0 deletions app/core/Engine/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { KeyringControllerState } from '@metamask/keyring-controller';
import { EngineState } from '../types';
import Logger from '../../../util/Logger';

export function logEngineCreation(
initialState: Partial<EngineState> = {},
initialKeyringState?: KeyringControllerState | null,
) {
if (Object.keys(initialState).length === 0) {
Logger.log('Engine initialized with empty state', {
keyringStateFromBackup: !!initialKeyringState,
});
} else {
Logger.log('Engine initialized with non-empty state', {
hasAccountsState: !!initialState.AccountsController,
hasKeyringState: !!initialState.KeyringController,
keyringStateFromBackup: !!initialKeyringState,
});
}
}
Loading

0 comments on commit 7b4102f

Please sign in to comment.