Skip to content

Commit b874e4c

Browse files
committed
feat: update transaction controller to selectedAccount
1 parent 00c043e commit b874e4c

File tree

7 files changed

+131
-29
lines changed

7 files changed

+131
-29
lines changed

packages/transaction-controller/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@metamask/controller-utils": "^11.0.0",
5353
"@metamask/eth-query": "^4.0.0",
5454
"@metamask/gas-fee-controller": "^17.0.0",
55+
"@metamask/keyring-api": "6.4.0",
5556
"@metamask/metamask-eth-abis": "^3.1.1",
5657
"@metamask/network-controller": "^19.0.0",
5758
"@metamask/nonce-tracker": "^5.0.0",

packages/transaction-controller/src/TransactionController.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from '@metamask/controller-utils';
1717
import EthQuery from '@metamask/eth-query';
1818
import HttpProvider from '@metamask/ethjs-provider-http';
19+
import { EthAccountType } from '@metamask/keyring-api';
1920
import type {
2021
BlockTracker,
2122
NetworkController,
@@ -434,6 +435,20 @@ const MOCK_CUSTOM_NETWORK: MockNetwork = {
434435
};
435436

436437
const ACCOUNT_MOCK = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207';
438+
const INTERNAL_ACCOUNT_MOCK = {
439+
id: '58def058-d35f-49a1-a7ab-e2580565f6f5',
440+
address: ACCOUNT_MOCK,
441+
type: EthAccountType.Eoa,
442+
options: {},
443+
methods: [],
444+
metadata: {
445+
name: 'Account 1',
446+
keyring: { type: 'HD Key Tree' },
447+
importTime: 1631619180000,
448+
lastSelected: 1631619180000,
449+
},
450+
};
451+
437452
const ACCOUNT_2_MOCK = '0x08f137f335ea1b8f193b8f6ea92561a60d23a211';
438453
const NONCE_MOCK = 12;
439454
const ACTION_ID_MOCK = '123456';
@@ -582,7 +597,7 @@ describe('TransactionController', () => {
582597
// eslint-disable-next-line @typescript-eslint/no-explicit-any
583598
getNetworkClientRegistry: () => ({} as any),
584599
getPermittedAccounts: async () => [ACCOUNT_MOCK],
585-
getSelectedAddress: () => ACCOUNT_MOCK,
600+
getSelectedAccount: () => INTERNAL_ACCOUNT_MOCK,
586601
isMultichainEnabled: false,
587602
hooks: {},
588603
onNetworkStateChange: network.subscribe,

packages/transaction-controller/src/TransactionController.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type {
2525
FetchGasFeeEstimateOptions,
2626
GasFeeState,
2727
} from '@metamask/gas-fee-controller';
28+
import type { InternalAccount } from '@metamask/keyring-api';
2829
import type {
2930
BlockTracker,
3031
NetworkClientId,
@@ -42,7 +43,7 @@ import type {
4243
Transaction as NonceTrackerTransaction,
4344
} from '@metamask/nonce-tracker';
4445
import { errorCodes, rpcErrors, providerErrors } from '@metamask/rpc-errors';
45-
import type { Hex } from '@metamask/utils';
46+
import type { CaipChainId, Hex } from '@metamask/utils';
4647
import { add0x } from '@metamask/utils';
4748
import { Mutex } from 'async-mutex';
4849
import { MethodRegistry } from 'eth-method-registry';
@@ -297,7 +298,7 @@ export type TransactionControllerOptions = {
297298
getNetworkState: () => NetworkState;
298299
getPermittedAccounts: (origin?: string) => Promise<string[]>;
299300
getSavedGasFees?: (chainId: Hex) => SavedGasFees | undefined;
300-
getSelectedAddress: () => string;
301+
getSelectedAccount: () => InternalAccount;
301302
incomingTransactions?: IncomingTransactionOptions;
302303
isMultichainEnabled: boolean;
303304
isSimulationEnabled?: () => boolean;
@@ -614,7 +615,7 @@ export class TransactionController extends BaseController<
614615

615616
private readonly getPermittedAccounts: (origin?: string) => Promise<string[]>;
616617

617-
private readonly getSelectedAddress: () => string;
618+
private readonly getSelectedAccount: () => InternalAccount;
618619

619620
private readonly getExternalPendingTransactions: (
620621
address: string,
@@ -733,7 +734,7 @@ export class TransactionController extends BaseController<
733734
* @param options.getNetworkState - Gets the state of the network controller.
734735
* @param options.getPermittedAccounts - Get accounts that a given origin has permissions for.
735736
* @param options.getSavedGasFees - Gets the saved gas fee config.
736-
* @param options.getSelectedAddress - Gets the address of the currently selected account.
737+
* @param options.getSelectedAccount - Gets the address of the currently selected account.
737738
* @param options.incomingTransactions - Configuration options for incoming transaction support.
738739
* @param options.isMultichainEnabled - Enable multichain support.
739740
* @param options.isSimulationEnabled - Whether new transactions will be automatically simulated.
@@ -761,7 +762,7 @@ export class TransactionController extends BaseController<
761762
getNetworkState,
762763
getPermittedAccounts,
763764
getSavedGasFees,
764-
getSelectedAddress,
765+
getSelectedAccount,
765766
incomingTransactions = {},
766767
isMultichainEnabled = false,
767768
isSimulationEnabled,
@@ -802,7 +803,7 @@ export class TransactionController extends BaseController<
802803
this.getGasFeeEstimates =
803804
getGasFeeEstimates || (() => Promise.resolve({} as GasFeeState));
804805
this.getPermittedAccounts = getPermittedAccounts;
805-
this.getSelectedAddress = getSelectedAddress;
806+
this.getSelectedAccount = getSelectedAccount;
806807
this.getExternalPendingTransactions =
807808
getExternalPendingTransactions ?? (() => []);
808809
this.securityProviderRequest = securityProviderRequest;
@@ -1035,7 +1036,7 @@ export class TransactionController extends BaseController<
10351036
if (origin) {
10361037
await validateTransactionOrigin(
10371038
await this.getPermittedAccounts(origin),
1038-
this.getSelectedAddress(),
1039+
this.getSelectedAccount().address,
10391040
txParams.from,
10401041
origin,
10411042
);
@@ -3430,7 +3431,7 @@ export class TransactionController extends BaseController<
34303431
}): IncomingTransactionHelper {
34313432
const incomingTransactionHelper = new IncomingTransactionHelper({
34323433
blockTracker,
3433-
getCurrentAccount: this.getSelectedAddress,
3434+
getCurrentAccount: this.getSelectedAccount,
34343435
getLastFetchedBlockNumbers: () => this.state.lastFetchedBlockNumbers,
34353436
getChainId: chainId ? () => chainId : this.getChainId.bind(this),
34363437
isEnabled: this.#incomingTransactionOptions.isEnabled,

packages/transaction-controller/src/TransactionControllerIntegration.test.ts

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
InfuraNetworkType,
1212
NetworkType,
1313
} from '@metamask/controller-utils';
14+
import type { InternalAccount } from '@metamask/keyring-api';
15+
import { EthAccountType, EthMethod } from '@metamask/keyring-api';
1416
import {
1517
NetworkController,
1618
NetworkClientType,
@@ -25,6 +27,7 @@ import assert from 'assert';
2527
import nock from 'nock';
2628
import type { SinonFakeTimers } from 'sinon';
2729
import { useFakeTimers } from 'sinon';
30+
import { v4 } from 'uuid';
2831

2932
import { advanceTime } from '../../../tests/helpers';
3033
import { mockNetwork } from '../../../tests/mock-network';
@@ -64,7 +67,46 @@ type UnrestrictedControllerMessenger = ControllerMessenger<
6467
| TransactionControllerEvents
6568
>;
6669

70+
const createMockInternalAccount = ({
71+
id = v4(),
72+
address = '0x2990079bcdee240329a520d2444386fc119da21a',
73+
name = 'Account 1',
74+
importTime = Date.now(),
75+
lastSelected = Date.now(),
76+
}: {
77+
id?: string;
78+
address?: string;
79+
name?: string;
80+
importTime?: number;
81+
lastSelected?: number;
82+
} = {}): InternalAccount => {
83+
return {
84+
id,
85+
address,
86+
options: {},
87+
methods: [
88+
EthMethod.PersonalSign,
89+
EthMethod.Sign,
90+
EthMethod.SignTransaction,
91+
EthMethod.SignTypedDataV1,
92+
EthMethod.SignTypedDataV3,
93+
EthMethod.SignTypedDataV4,
94+
],
95+
type: EthAccountType.Eoa,
96+
metadata: {
97+
name,
98+
keyring: { type: 'HD Key Tree' },
99+
importTime,
100+
lastSelected,
101+
},
102+
} as InternalAccount;
103+
};
104+
67105
const ACCOUNT_MOCK = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207';
106+
const INTERNAL_ACCOUNT_MOCK = createMockInternalAccount({
107+
address: ACCOUNT_MOCK,
108+
});
109+
68110
const ACCOUNT_2_MOCK = '0x08f137f335ea1b8f193b8f6ea92561a60d23a211';
69111
const ACCOUNT_3_MOCK = '0xe688b84b23f322a994a53dbf8e15fa82cdb71127';
70112
const infuraProjectId = 'fake-infura-project-id';
@@ -167,7 +209,8 @@ const setupController = async (
167209
getNetworkClientRegistry:
168210
networkController.getNetworkClientRegistry.bind(networkController),
169211
getPermittedAccounts: async () => [ACCOUNT_MOCK],
170-
getSelectedAddress: () => '0xdeadbeef',
212+
getSelectedAccount: () =>
213+
createMockInternalAccount({ address: '0xdeadbeef' }),
171214
hooks: {},
172215
isMultichainEnabled: false,
173216
messenger,
@@ -802,7 +845,7 @@ describe('TransactionController Integration', () => {
802845
await setupController({
803846
isMultichainEnabled: true,
804847
getPermittedAccounts: async () => [ACCOUNT_MOCK],
805-
getSelectedAddress: () => ACCOUNT_MOCK,
848+
getSelectedAccount: () => INTERNAL_ACCOUNT_MOCK,
806849
});
807850
const otherNetworkClientIdOnGoerli =
808851
await networkController.upsertNetworkConfiguration(
@@ -883,7 +926,7 @@ describe('TransactionController Integration', () => {
883926
await setupController({
884927
isMultichainEnabled: true,
885928
getPermittedAccounts: async () => [ACCOUNT_MOCK],
886-
getSelectedAddress: () => ACCOUNT_MOCK,
929+
getSelectedAccount: () => INTERNAL_ACCOUNT_MOCK,
887930
});
888931

889932
const addTx1 = await transactionController.addTransaction(
@@ -1140,10 +1183,13 @@ describe('TransactionController Integration', () => {
11401183
});
11411184

11421185
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1186+
const selectedAccountMock = createMockInternalAccount({
1187+
address: selectedAddress,
1188+
});
11431189

11441190
const { networkController, transactionController } =
11451191
await setupController({
1146-
getSelectedAddress: () => selectedAddress,
1192+
getSelectedAccount: () => selectedAccountMock,
11471193
isMultichainEnabled: true,
11481194
});
11491195

@@ -1209,6 +1255,9 @@ describe('TransactionController Integration', () => {
12091255

12101256
it('should start the global incoming transaction helper when no networkClientIds provided', async () => {
12111257
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1258+
const selectedAccountMock = createMockInternalAccount({
1259+
address: selectedAddress,
1260+
});
12121261

12131262
mockNetwork({
12141263
networkClientConfiguration: buildInfuraNetworkClientConfiguration(
@@ -1226,7 +1275,7 @@ describe('TransactionController Integration', () => {
12261275
.reply(200, ETHERSCAN_TRANSACTION_RESPONSE_MOCK);
12271276

12281277
const { transactionController } = await setupController({
1229-
getSelectedAddress: () => selectedAddress,
1278+
getSelectedAccount: () => selectedAccountMock,
12301279
});
12311280

12321281
transactionController.startIncomingTransactionPolling();
@@ -1314,10 +1363,13 @@ describe('TransactionController Integration', () => {
13141363
});
13151364

13161365
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1366+
const selectedAccountMock = createMockInternalAccount({
1367+
address: selectedAddress,
1368+
});
13171369

13181370
const { networkController, transactionController } =
13191371
await setupController({
1320-
getSelectedAddress: () => selectedAddress,
1372+
getSelectedAccount: () => selectedAccountMock,
13211373
isMultichainEnabled: true,
13221374
});
13231375

@@ -1410,10 +1462,13 @@ describe('TransactionController Integration', () => {
14101462
describe('stopIncomingTransactionPolling', () => {
14111463
it('should not poll for new incoming transactions for the given networkClientId', async () => {
14121464
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1465+
const selectedAccountMock = createMockInternalAccount({
1466+
address: selectedAddress,
1467+
});
14131468

14141469
const { networkController, transactionController } =
14151470
await setupController({
1416-
getSelectedAddress: () => selectedAddress,
1471+
getSelectedAccount: () => selectedAccountMock,
14171472
});
14181473

14191474
const networkClients = networkController.getNetworkClientRegistry();
@@ -1454,9 +1509,12 @@ describe('TransactionController Integration', () => {
14541509

14551510
it('should stop the global incoming transaction helper when no networkClientIds provided', async () => {
14561511
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1512+
const selectedAccountMock = createMockInternalAccount({
1513+
address: selectedAddress,
1514+
});
14571515

14581516
const { transactionController } = await setupController({
1459-
getSelectedAddress: () => selectedAddress,
1517+
getSelectedAccount: () => selectedAccountMock,
14601518
});
14611519

14621520
mockNetwork({
@@ -1490,10 +1548,13 @@ describe('TransactionController Integration', () => {
14901548
describe('stopAllIncomingTransactionPolling', () => {
14911549
it('should not poll for incoming transactions on any network client', async () => {
14921550
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1551+
const selectedAccountMock = createMockInternalAccount({
1552+
address: selectedAddress,
1553+
});
14931554

14941555
const { networkController, transactionController } =
14951556
await setupController({
1496-
getSelectedAddress: () => selectedAddress,
1557+
getSelectedAccount: () => selectedAccountMock,
14971558
});
14981559

14991560
const networkClients = networkController.getNetworkClientRegistry();
@@ -1534,10 +1595,13 @@ describe('TransactionController Integration', () => {
15341595
describe('updateIncomingTransactions', () => {
15351596
it('should add incoming transactions to state with the correct chainId for the given networkClientId without waiting for the next block', async () => {
15361597
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1598+
const selectedAccountMock = createMockInternalAccount({
1599+
address: selectedAddress,
1600+
});
15371601

15381602
const { networkController, transactionController } =
15391603
await setupController({
1540-
getSelectedAddress: () => selectedAddress,
1604+
getSelectedAccount: () => selectedAccountMock,
15411605
isMultichainEnabled: true,
15421606
});
15431607

@@ -1600,9 +1664,12 @@ describe('TransactionController Integration', () => {
16001664

16011665
it('should update the incoming transactions for the gloablly selected network when no networkClientIds provided', async () => {
16021666
const selectedAddress = ETHERSCAN_TRANSACTION_BASE_MOCK.to;
1667+
const selectedAccountMock = createMockInternalAccount({
1668+
address: selectedAddress,
1669+
});
16031670

16041671
const { transactionController } = await setupController({
1605-
getSelectedAddress: () => selectedAddress,
1672+
getSelectedAccount: () => selectedAccountMock,
16061673
});
16071674

16081675
mockNetwork({

packages/transaction-controller/src/helpers/IncomingTransactionHelper.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,21 @@ const BLOCK_TRACKER_MOCK = {
3232

3333
const CONTROLLER_ARGS_MOCK = {
3434
blockTracker: BLOCK_TRACKER_MOCK,
35-
getCurrentAccount: () => ADDRESS_MOCK,
35+
getCurrentAccount: () => {
36+
return {
37+
id: '58def058-d35f-49a1-a7ab-e2580565f6f5',
38+
address: ADDRESS_MOCK,
39+
type: 'eip155:eoa' as const,
40+
options: {},
41+
methods: [],
42+
metadata: {
43+
name: 'Account 1',
44+
keyring: { type: 'HD Key Tree' },
45+
importTime: 1631619180000,
46+
lastSelected: 1631619180000,
47+
},
48+
};
49+
},
3650
getLastFetchedBlockNumbers: () => ({}),
3751
getChainId: () => CHAIN_ID_MOCK,
3852
remoteTransactionSource: {} as RemoteTransactionSource,
@@ -546,7 +560,8 @@ describe('IncomingTransactionHelper', () => {
546560
remoteTransactionSource: createRemoteTransactionSourceMock([
547561
TRANSACTION_MOCK_2,
548562
]),
549-
getCurrentAccount: () => undefined as unknown as string,
563+
// @ts-expect-error testing undefined
564+
getCurrentAccount: () => undefined,
550565
});
551566

552567
const { blockNumberListener } = await emitBlockTrackerLatestEvent(

0 commit comments

Comments
 (0)