Skip to content

Commit ed2a43e

Browse files
committed
[WIP] Add support for hideExternalAccounts
1 parent e9921fb commit ed2a43e

File tree

2 files changed

+83
-37
lines changed

2 files changed

+83
-37
lines changed

packages/snaps-controllers/src/interface/SnapInterfaceController.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ export class SnapInterfaceController extends BaseController<
293293
getSelectedAccount: this.#getSelectedAccount.bind(this),
294294
setSelectedAccount: this.#setSelectedAccount.bind(this),
295295
listAccounts: this.#listAccounts.bind(this),
296+
snapOwnsAccount: this.#snapOwnsAccount.bind(this, snapId),
296297
});
297298

298299
this.update((draftState) => {
@@ -349,6 +350,7 @@ export class SnapInterfaceController extends BaseController<
349350
getSelectedAccount: this.#getSelectedAccount.bind(this),
350351
setSelectedAccount: this.#setSelectedAccount.bind(this),
351352
listAccounts: this.#listAccounts.bind(this),
353+
snapOwnsAccount: this.#snapOwnsAccount.bind(this, snapId),
352354
});
353355

354356
this.update((draftState) => {
@@ -498,7 +500,13 @@ export class SnapInterfaceController extends BaseController<
498500
* @param chainIds - The chain IDs to get the accounts for.
499501
* @returns The list of accounts.
500502
*/
501-
#listAccounts(chainIds: CaipChainId[]) {
503+
#listAccounts(chainIds?: CaipChainId[]) {
504+
if (!chainIds || chainIds.length === 0) {
505+
return this.messagingSystem.call(
506+
'AccountsController:listMultichainAccounts',
507+
);
508+
}
509+
502510
const accounts = chainIds.reduce<InternalAccount[]>((acc, chainId) => {
503511
const result = this.messagingSystem.call(
504512
'AccountsController:listMultichainAccounts',
@@ -546,6 +554,17 @@ export class SnapInterfaceController extends BaseController<
546554
return this.messagingSystem.call('SnapController:get', id);
547555
}
548556

557+
/**
558+
* Whether if the snap owns the account.
559+
*
560+
* @param snapId - The snap id.
561+
* @param account - The account.
562+
* @returns True if the snap owns the account, otherwise false.
563+
*/
564+
#snapOwnsAccount(snapId: SnapId, account: InternalAccount) {
565+
return account.metadata.snap?.id === snapId;
566+
}
567+
549568
/**
550569
* Utility function to validate the components of an interface.
551570
* Throws if something is invalid.

packages/snaps-controllers/src/interface/utils.ts

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,12 @@ type GetSelectedAccount = () => InternalAccount;
119119
/**
120120
* A function to get accounts for the provided chain IDs.
121121
*/
122-
type ListAccounts = (chainIds: CaipChainId[]) => InternalAccount[];
122+
type ListAccounts = (chainIds?: CaipChainId[]) => InternalAccount[];
123+
124+
/**
125+
* A function to check if the snap owns the account.
126+
*/
127+
type SnapOwnsAccount = (account: InternalAccount) => boolean;
123128

124129
/**
125130
* Data getters for elements.
@@ -130,13 +135,15 @@ type ListAccounts = (chainIds: CaipChainId[]) => InternalAccount[];
130135
* @param setSelectedAccount - A function to set the selected account in the client.
131136
* @param getSelectedAccount - A function to get the selected account in the client.
132137
* @param listAccounts - A function to list accounts for the provided chain IDs.
138+
* @param snapOwnsAccount - A function to check if the snap owns the account.
133139
*/
134140
type ElementDataGetters = {
135141
getAssetsState: GetAssetsState;
136142
getAccountByAddress: GetAccountByAddress;
137143
getSelectedAccount: GetSelectedAccount;
138144
setSelectedAccount: SetSelectedAccount;
139145
listAccounts: ListAccounts;
146+
snapOwnsAccount: SnapOwnsAccount;
140147
};
141148

142149
/**
@@ -285,33 +292,50 @@ export function getDefaultAsset(
285292
* @param elementDataGetters.getSelectedAccount - A function to get the selected account in the client.
286293
* @param elementDataGetters.listAccounts - A function to list accounts for the provided chain IDs.
287294
* @param elementDataGetters.setSelectedAccount - A function to set the selected account in the client.
295+
* @param elementDataGetters.snapOwnsAccount - A function to check if the snap owns the account.
288296
* @returns The default state for the account selector.
289297
*/
290298
export function getAccountSelectorDefaultStateValue(
291299
element: AccountSelectorElement,
292-
{ getSelectedAccount, listAccounts, setSelectedAccount }: ElementDataGetters,
300+
{
301+
getSelectedAccount,
302+
listAccounts,
303+
setSelectedAccount,
304+
snapOwnsAccount,
305+
}: ElementDataGetters,
293306
) {
294-
const { chainIds, switchGlobalAccount } = element.props;
295-
296-
const account = getSelectedAccount();
297-
298-
if (!chainIds || chainIds.length === 0) {
299-
return formatAccountSelectorStateValue(account, chainIds);
300-
}
301-
302-
if (account.scopes.some((scope) => matchingChainId(scope, chainIds))) {
303-
return formatAccountSelectorStateValue(account, chainIds);
307+
const { chainIds, switchGlobalAccount, hideExternalAccounts } = element.props;
308+
309+
const selectedAccount = getSelectedAccount();
310+
311+
if (
312+
(!chainIds ||
313+
chainIds.length === 0 ||
314+
selectedAccount.scopes.some((scope) =>
315+
matchingChainId(scope, chainIds),
316+
)) &&
317+
(!hideExternalAccounts ||
318+
(hideExternalAccounts && snapOwnsAccount(selectedAccount)))
319+
) {
320+
return formatAccountSelectorStateValue(selectedAccount, chainIds);
304321
}
305322

306323
const accounts = listAccounts(chainIds);
307324

308-
assert(accounts.length > 0, 'No accounts found for the provided chain IDs.');
325+
const filteredAccounts = hideExternalAccounts
326+
? accounts.filter((account) => snapOwnsAccount(account))
327+
: accounts;
328+
329+
assert(
330+
filteredAccounts.length > 0,
331+
'No accounts found for the provided chain IDs.',
332+
);
309333

310334
if (switchGlobalAccount) {
311-
setSelectedAccount(accounts[0].id);
335+
setSelectedAccount(filteredAccounts[0].id);
312336
}
313337

314-
return formatAccountSelectorStateValue(accounts[0], chainIds);
338+
return formatAccountSelectorStateValue(filteredAccounts[0], chainIds);
315339
}
316340

317341
/**
@@ -404,26 +428,37 @@ export function getAssetSelectorStateValue(
404428
* Get the state value for an account selector.
405429
*
406430
* @param element - The account selector element.
407-
* @param getAccountByAddress - A function to get an account by address.
408-
* @param setSelectedAccount - A function to set the selected account in the client.
431+
* @param elementDataGetters - Data getters for the element.
432+
* @param elementDataGetters.getAccountByAddress - A function to get an account by address.
433+
* @param elementDataGetters.setSelectedAccount - A function to set the selected account in the client.
434+
* @param elementDataGetters.snapOwnsAccount - A function to check if the snap owns the account.
409435
* @returns The state value for the account selector.
410436
*/
411437
export function getAccountSelectorStateValue(
412438
element: AccountSelectorElement,
413-
getAccountByAddress: GetAccountByAddress,
414-
setSelectedAccount: SetSelectedAccount,
439+
{
440+
getAccountByAddress,
441+
setSelectedAccount,
442+
snapOwnsAccount,
443+
}: ElementDataGetters,
415444
) {
416-
if (!element.props.value) {
445+
const { value, switchGlobalAccount, hideExternalAccounts } = element.props;
446+
447+
if (!value) {
417448
return null;
418449
}
419450

420-
const account = getAccountByAddress(element.props.value);
451+
const account = getAccountByAddress(value);
421452

422453
if (!account) {
423454
return null;
424455
}
425456

426-
if (element.props.switchGlobalAccount) {
457+
if (hideExternalAccounts && !snapOwnsAccount(account)) {
458+
return null;
459+
}
460+
461+
if (switchGlobalAccount) {
427462
setSelectedAccount(account.id);
428463
}
429464

@@ -438,9 +473,6 @@ export function getAccountSelectorStateValue(
438473
*
439474
* @param element - The input element.
440475
* @param elementDataGetters - Data getters for the element.
441-
* @param elementDataGetters.getAssetsState - A function to get the MultichainAssetController state.
442-
* @param elementDataGetters.getAccountByAddress - A function to get an account by its address.
443-
* @param elementDataGetters.setSelectedAccount - A function to set the selected account in the client.
444476
* @returns The state value for a given component.
445477
*/
446478
function getComponentStateValue(
@@ -454,18 +486,17 @@ function getComponentStateValue(
454486
| AssetSelectorElement
455487
| AddressInputElement
456488
| AccountSelectorElement,
457-
{
458-
getAssetsState,
459-
getAccountByAddress,
460-
setSelectedAccount,
461-
}: ElementDataGetters,
489+
elementDataGetters: ElementDataGetters,
462490
) {
463491
switch (element.type) {
464492
case 'Checkbox':
465493
return element.props.checked;
466494

467495
case 'AssetSelector':
468-
return getAssetSelectorStateValue(element.props.value, getAssetsState);
496+
return getAssetSelectorStateValue(
497+
element.props.value,
498+
elementDataGetters.getAssetsState,
499+
);
469500

470501
case 'AddressInput': {
471502
if (!element.props.value) {
@@ -478,11 +509,7 @@ function getComponentStateValue(
478509
}
479510

480511
case 'AccountSelector':
481-
return getAccountSelectorStateValue(
482-
element,
483-
getAccountByAddress,
484-
setSelectedAccount,
485-
);
512+
return getAccountSelectorStateValue(element, elementDataGetters);
486513

487514
default:
488515
return element.props.value;

0 commit comments

Comments
 (0)