Skip to content

Commit

Permalink
Merge branch 'main' into caip-multichain-api
Browse files Browse the repository at this point in the history
  • Loading branch information
jiexi authored Dec 17, 2024
2 parents 2a983d2 + 2094380 commit 4542942
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 58 deletions.
2 changes: 1 addition & 1 deletion packages/approval-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@metamask/base-controller": "^7.0.2",
"@metamask/rpc-errors": "^7.0.1",
"@metamask/utils": "^10.0.0",
"nanoid": "^3.1.31"
"nanoid": "^3.3.8"
},
"devDependencies": {
"@metamask/auto-changelog": "^3.4.4",
Expand Down
104 changes: 102 additions & 2 deletions packages/assets-controllers/src/TokensController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ describe('TokensController', () => {
decimals: 6,
});
controller.ignoreTokens(['0x03'], InfuraNetworkType.goerli);
expect(controller.state.ignoredTokens).toStrictEqual(['0x03']);
expect(controller.state.ignoredTokens).toStrictEqual([]);

// Validate the overall ignored tokens state
expect(controller.state.allIgnoredTokens).toStrictEqual({
Expand All @@ -845,6 +845,106 @@ describe('TokensController', () => {
);
});

it('should not update detectedTokens, tokens, and ignoredTokens state given a network that is different from the globally selected network', async () => {
const selectedAddress = '0x0001';
const selectedAccount = createMockInternalAccount({
address: selectedAddress,
});

await withController(
{
mocks: {
getSelectedAccount: selectedAccount,
getAccount: selectedAccount,
},
},
async ({ controller, triggerSelectedAccountChange, changeNetwork }) => {
// Select the first account
triggerSelectedAccountChange(selectedAccount);

// Add tokens to sepolia
changeNetwork({ selectedNetworkClientId: InfuraNetworkType.sepolia });
await controller.addToken({
address: '0x01',
symbol: 'Token1',
decimals: 18,
});
expect(controller.state.tokens).toHaveLength(1);
expect(controller.state.ignoredTokens).toHaveLength(0);

// switch to goerli
changeNetwork({ selectedNetworkClientId: InfuraNetworkType.goerli });

// Add tokens to goerli
await controller.addToken({
address: '0x02',
symbol: 'Token2',
decimals: 8,
});

expect(controller.state.tokens).toHaveLength(1);
expect(controller.state.ignoredTokens).toHaveLength(0);

// ignore token on sepolia
controller.ignoreTokens(['0x01'], InfuraNetworkType.sepolia);

// as we are not on sepolia, tokens, ignoredTokens, and detectedTokens should not be affected
expect(controller.state.tokens).toHaveLength(1);
expect(controller.state.ignoredTokens).toHaveLength(0);
expect(controller.state.detectedTokens).toHaveLength(0);
},
);
});

it('should update tokens, and ignoredTokens and detectedTokens state for the globally selected network', async () => {
const selectedAddress = '0x0001';
const selectedAccount = createMockInternalAccount({
address: selectedAddress,
});

await withController(
{
mocks: {
getSelectedAccount: selectedAccount,
getAccount: selectedAccount,
},
},
async ({ controller, triggerSelectedAccountChange, changeNetwork }) => {
// Select the first account
triggerSelectedAccountChange(selectedAccount);

// Set globally selected network to sepolia
changeNetwork({ selectedNetworkClientId: InfuraNetworkType.sepolia });

// Add a token to sepolia
await controller.addToken({
address: '0x01',
symbol: 'Token1',
decimals: 18,
});
// Add a detected token to sepolia
await controller.addDetectedTokens([
{
address: '0x03',
symbol: 'Token3',
decimals: 18,
},
]);

expect(controller.state.tokens).toHaveLength(1);
expect(controller.state.ignoredTokens).toHaveLength(0);

// Ignore the token on sepolia
controller.ignoreTokens(['0x01'], InfuraNetworkType.sepolia);

// Ensure the tokens and ignoredTokens are updated for sepolia (globally selected network)
expect(controller.state.tokens).toHaveLength(0);
expect(controller.state.ignoredTokens).toHaveLength(1);
expect(controller.state.detectedTokens).toHaveLength(1);
},
);
});

it('should not retain ignored tokens from a different network', async () => {
const selectedAddress = '0x0001';
const selectedAccount = createMockInternalAccount({
Expand Down Expand Up @@ -879,7 +979,7 @@ describe('TokensController', () => {
// Ignore the token on Sepolia
controller.ignoreTokens(['0x01'], InfuraNetworkType.sepolia);
expect(controller.state.tokens).toHaveLength(0);
expect(controller.state.ignoredTokens).toStrictEqual(['0x01']);
expect(controller.state.ignoredTokens).toStrictEqual([]);

// Attempt to ignore a token that was added on Goerli
await controller.addToken({
Expand Down
10 changes: 6 additions & 4 deletions packages/assets-controllers/src/TokensController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ export class TokensController extends BaseController<
tokenAddressesToIgnore: string[],
networkClientId?: NetworkClientId,
) {
let interactingChainId;
let interactingChainId = this.#chainId;
if (networkClientId) {
interactingChainId = this.messagingSystem.call(
'NetworkController:getNetworkClientById',
Expand Down Expand Up @@ -624,12 +624,14 @@ export class TokensController extends BaseController<
});

this.update((state) => {
state.ignoredTokens = newIgnoredTokens;
state.tokens = newTokens;
state.detectedTokens = newDetectedTokens;
state.allIgnoredTokens = newAllIgnoredTokens;
state.allDetectedTokens = newAllDetectedTokens;
state.allTokens = newAllTokens;
if (interactingChainId === this.#chainId) {
state.detectedTokens = newDetectedTokens;
state.tokens = newTokens;
state.ignoredTokens = newIgnoredTokens;
}
});
}

Expand Down
95 changes: 53 additions & 42 deletions packages/keyring-controller/src/KeyringController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ export class KeyringController extends BaseController<
}

const [addedAccountAddress] = await primaryKeyring.addAccounts(1);
await this.verifySeedPhrase();
await this.#verifySeedPhrase();

return addedAccountAddress;
});
Expand Down Expand Up @@ -1356,47 +1356,7 @@ export class KeyringController extends BaseController<
* @returns Promise resolving to the seed phrase as Uint8Array.
*/
async verifySeedPhrase(): Promise<Uint8Array> {
const primaryKeyring = this.getKeyringsByType(KeyringTypes.hd)[0] as
| EthKeyring<Json>
| undefined;
if (!primaryKeyring) {
throw new Error('No HD keyring found.');
}

assertHasUint8ArrayMnemonic(primaryKeyring);

const seedWords = primaryKeyring.mnemonic;
const accounts = await primaryKeyring.getAccounts();
/* istanbul ignore if */
if (accounts.length === 0) {
throw new Error('Cannot verify an empty keyring.');
}

// The HD Keyring Builder is a default keyring builder
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const hdKeyringBuilder = this.#getKeyringBuilderForType(KeyringTypes.hd)!;

const hdKeyring = hdKeyringBuilder();
// @ts-expect-error @metamask/eth-hd-keyring correctly handles
// Uint8Array seed phrases in the `deserialize` method.
await hdKeyring.deserialize({
mnemonic: seedWords,
numberOfAccounts: accounts.length,
});
const testAccounts = await hdKeyring.getAccounts();
/* istanbul ignore if */
if (testAccounts.length !== accounts.length) {
throw new Error('Seed phrase imported incorrect number of accounts.');
}

testAccounts.forEach((account: string, i: number) => {
/* istanbul ignore if */
if (account.toLowerCase() !== accounts[i].toLowerCase()) {
throw new Error('Seed phrase imported different accounts.');
}
});

return seedWords;
return this.#withControllerLock(async () => this.#verifySeedPhrase());
}

/**
Expand Down Expand Up @@ -1883,6 +1843,57 @@ export class KeyringController extends BaseController<
this.#setUnlocked();
}

/**
* Internal non-exclusive method to verify the seed phrase.
*
* @returns A promise resolving to the seed phrase as Uint8Array.
*/
async #verifySeedPhrase(): Promise<Uint8Array> {
this.#assertControllerMutexIsLocked();

const primaryKeyring = this.getKeyringsByType(KeyringTypes.hd)[0] as
| EthKeyring<Json>
| undefined;
if (!primaryKeyring) {
throw new Error('No HD keyring found.');
}

assertHasUint8ArrayMnemonic(primaryKeyring);

const seedWords = primaryKeyring.mnemonic;
const accounts = await primaryKeyring.getAccounts();
/* istanbul ignore if */
if (accounts.length === 0) {
throw new Error('Cannot verify an empty keyring.');
}

// The HD Keyring Builder is a default keyring builder
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const hdKeyringBuilder = this.#getKeyringBuilderForType(KeyringTypes.hd)!;

const hdKeyring = hdKeyringBuilder();
// @ts-expect-error @metamask/eth-hd-keyring correctly handles
// Uint8Array seed phrases in the `deserialize` method.
await hdKeyring.deserialize({
mnemonic: seedWords,
numberOfAccounts: accounts.length,
});
const testAccounts = await hdKeyring.getAccounts();
/* istanbul ignore if */
if (testAccounts.length !== accounts.length) {
throw new Error('Seed phrase imported incorrect number of accounts.');
}

testAccounts.forEach((account: string, i: number) => {
/* istanbul ignore if */
if (account.toLowerCase() !== accounts[i].toLowerCase()) {
throw new Error('Seed phrase imported different accounts.');
}
});

return seedWords;
}

/**
* Get the updated array of each keyring's type and
* accounts list.
Expand Down
2 changes: 1 addition & 1 deletion packages/permission-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@types/deep-freeze-strict": "^1.1.0",
"deep-freeze-strict": "^1.1.1",
"immer": "^9.0.6",
"nanoid": "^3.1.31"
"nanoid": "^3.3.8"
},
"devDependencies": {
"@metamask/approval-controller": "^7.1.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/permission-log-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"deep-freeze-strict": "^1.1.1",
"deepmerge": "^4.2.2",
"jest": "^27.5.1",
"nanoid": "^3.1.31",
"nanoid": "^3.3.8",
"ts-jest": "^27.1.4",
"typedoc": "^0.24.8",
"typedoc-plugin-missing-exports": "^2.0.0",
Expand Down
14 changes: 7 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2175,7 +2175,7 @@ __metadata:
"@types/jest": "npm:^27.4.1"
deepmerge: "npm:^4.2.2"
jest: "npm:^27.5.1"
nanoid: "npm:^3.1.31"
nanoid: "npm:^3.3.8"
sinon: "npm:^9.2.4"
ts-jest: "npm:^27.1.4"
typedoc: "npm:^0.24.8"
Expand Down Expand Up @@ -3327,7 +3327,7 @@ __metadata:
deepmerge: "npm:^4.2.2"
immer: "npm:^9.0.6"
jest: "npm:^27.5.1"
nanoid: "npm:^3.1.31"
nanoid: "npm:^3.3.8"
ts-jest: "npm:^27.1.4"
typedoc: "npm:^0.24.8"
typedoc-plugin-missing-exports: "npm:^2.0.0"
Expand All @@ -3350,7 +3350,7 @@ __metadata:
deep-freeze-strict: "npm:^1.1.1"
deepmerge: "npm:^4.2.2"
jest: "npm:^27.5.1"
nanoid: "npm:^3.1.31"
nanoid: "npm:^3.3.8"
ts-jest: "npm:^27.1.4"
typedoc: "npm:^0.24.8"
typedoc-plugin-missing-exports: "npm:^2.0.0"
Expand Down Expand Up @@ -10202,12 +10202,12 @@ __metadata:
languageName: node
linkType: hard

"nanoid@npm:^3.1.31, nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
"nanoid@npm:^3.1.31, nanoid@npm:^3.3.7, nanoid@npm:^3.3.8":
version: 3.3.8
resolution: "nanoid@npm:3.3.8"
bin:
nanoid: bin/nanoid.cjs
checksum: 10/ac1eb60f615b272bccb0e2b9cd933720dad30bf9708424f691b8113826bb91aca7e9d14ef5d9415a6ba15c266b37817256f58d8ce980c82b0ba3185352565679
checksum: 10/2d1766606cf0d6f47b6f0fdab91761bb81609b2e3d367027aff45e6ee7006f660fb7e7781f4a34799fe6734f1268eeed2e37a5fdee809ade0c2d4eb11b0f9c40
languageName: node
linkType: hard

Expand Down

0 comments on commit 4542942

Please sign in to comment.