@metamask-previews/assets-controllers 106.0.0-preview-55fbbe681 → 106.0.0-preview-498809ee9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MultichainAssetsController/MultichainAssetsController.cjs +14 -28
- package/dist/MultichainAssetsController/MultichainAssetsController.cjs.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.d.cts.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.d.mts.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.mjs +15 -29
- package/dist/MultichainAssetsController/MultichainAssetsController.mjs.map +1 -1
- package/dist/multichain/stellarAccountAssetInfo.cjs +3 -3
- package/dist/multichain/stellarAccountAssetInfo.cjs.map +1 -1
- package/dist/multichain/stellarAccountAssetInfo.d.cts +3 -8
- package/dist/multichain/stellarAccountAssetInfo.d.cts.map +1 -1
- package/dist/multichain/stellarAccountAssetInfo.d.mts +3 -8
- package/dist/multichain/stellarAccountAssetInfo.d.mts.map +1 -1
- package/dist/multichain/stellarAccountAssetInfo.mjs +2 -2
- package/dist/multichain/stellarAccountAssetInfo.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -382,7 +382,7 @@ async function _MultichainAssetsController_bootstrapStellarTrustlineExtras() {
|
|
|
382
382
|
}
|
|
383
383
|
}, _MultichainAssetsController_handleAccountBalancesUpdatedForEnrichment =
|
|
384
384
|
/**
|
|
385
|
-
* After snap balance events, fetch Stellar
|
|
385
|
+
* After snap balance events, fetch Stellar trust-line `extra` via `getAccountAssetInfo`.
|
|
386
386
|
*
|
|
387
387
|
* @param payload - Keyring balance update payload.
|
|
388
388
|
*/
|
|
@@ -398,7 +398,7 @@ async function _MultichainAssetsController_handleAccountBalancesUpdatedForEnrich
|
|
|
398
398
|
}
|
|
399
399
|
}, _MultichainAssetsController_enrichStellarAccountAssetInfo =
|
|
400
400
|
/**
|
|
401
|
-
* Fetches Stellar-only `
|
|
401
|
+
* Fetches Stellar-only `getAccountAssetInfo` client request and merges trust-line `extra` into balances.
|
|
402
402
|
*
|
|
403
403
|
* @param accountId - Account id.
|
|
404
404
|
* @param assetIds - Assets to enrich.
|
|
@@ -417,60 +417,46 @@ async function _MultichainAssetsController_enrichStellarAccountAssetInfo(account
|
|
|
417
417
|
if (!snapId) {
|
|
418
418
|
return;
|
|
419
419
|
}
|
|
420
|
-
const info = await __classPrivateFieldGet(this, _MultichainAssetsController_instances, "m", _MultichainAssetsController_getAccountAssetInfoFromSnap).call(this, accountId, snapId, stellarClassicIds);
|
|
420
|
+
const info = await __classPrivateFieldGet(this, _MultichainAssetsController_instances, "m", _MultichainAssetsController_getAccountAssetInfoFromSnap).call(this, accountId, snapId, account.scopes[0], stellarClassicIds);
|
|
421
421
|
if (!info) {
|
|
422
422
|
return;
|
|
423
423
|
}
|
|
424
|
-
const metadataUpdates = {};
|
|
425
424
|
const extrasByAsset = {};
|
|
426
425
|
for (const assetId of stellarClassicIds) {
|
|
427
|
-
const
|
|
428
|
-
if (
|
|
426
|
+
const snapExtra = info[assetId];
|
|
427
|
+
if (snapExtra === undefined) {
|
|
429
428
|
// Snap omits assets with no on-chain row (portfolio import without trust line).
|
|
430
429
|
extrasByAsset[assetId] = { limit: '0' };
|
|
431
430
|
continue;
|
|
432
431
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (balanceExtra === undefined) {
|
|
436
|
-
// Snap omits extra when there is no on-chain trust line (portfolio import).
|
|
437
|
-
extrasByAsset[assetId] = { limit: '0' };
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
extrasByAsset[assetId] = balanceExtra;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
if (Object.keys(metadataUpdates).length > 0) {
|
|
444
|
-
this.update((state) => {
|
|
445
|
-
state.assetsMetadata = {
|
|
446
|
-
...state.assetsMetadata,
|
|
447
|
-
...metadataUpdates,
|
|
448
|
-
};
|
|
449
|
-
});
|
|
432
|
+
const balanceExtra = (0, stellarAccountAssetInfo_1.stellarAssetInfoExtraToBalanceExtra)(snapExtra);
|
|
433
|
+
extrasByAsset[assetId] = balanceExtra ?? { limit: '0' };
|
|
450
434
|
}
|
|
451
435
|
if (Object.keys(extrasByAsset).length > 0) {
|
|
452
436
|
this.messenger.call('MultichainBalancesController:mergeAccountBalanceExtras', accountId, extrasByAsset);
|
|
453
437
|
}
|
|
454
438
|
}, _MultichainAssetsController_getAccountAssetInfoFromSnap =
|
|
455
439
|
/**
|
|
456
|
-
* Calls the Stellar snap `
|
|
440
|
+
* Calls the Stellar snap `getAccountAssetInfo` client request handler.
|
|
457
441
|
*
|
|
458
442
|
* @param accountId - Account id.
|
|
459
443
|
* @param snapId - Stellar wallet snap id.
|
|
444
|
+
* @param scope - Stellar CAIP-2 chain id.
|
|
460
445
|
* @param assets - CAIP-19 assets to resolve.
|
|
461
|
-
* @returns Per-asset
|
|
446
|
+
* @returns Per-asset trust-line fields, or undefined on failure.
|
|
462
447
|
*/
|
|
463
|
-
async function _MultichainAssetsController_getAccountAssetInfoFromSnap(accountId, snapId, assets) {
|
|
448
|
+
async function _MultichainAssetsController_getAccountAssetInfoFromSnap(accountId, snapId, scope, assets) {
|
|
464
449
|
try {
|
|
465
450
|
return (await this.messenger.call('SnapController:handleRequest', {
|
|
466
451
|
snapId: snapId,
|
|
467
452
|
origin: 'metamask',
|
|
468
|
-
handler: snaps_utils_1.HandlerType.
|
|
453
|
+
handler: snaps_utils_1.HandlerType.OnClientRequest,
|
|
469
454
|
request: {
|
|
470
455
|
jsonrpc: '2.0',
|
|
471
|
-
method: stellarAccountAssetInfo_1.
|
|
456
|
+
method: stellarAccountAssetInfo_1.STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,
|
|
472
457
|
params: {
|
|
473
458
|
accountId,
|
|
459
|
+
scope,
|
|
474
460
|
assets,
|
|
475
461
|
},
|
|
476
462
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountAssetListUpdatedEvent,\n AccountsControllerAccountBalancesUpdatesEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n CaipAssetType,\n CaipAssetTypeOrId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerState,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n GetPermissions,\n PermissionConstraint,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n} from '@metamask/snaps-controllers';\nimport type { FungibleAssetMetadata, Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { isCaipAssetType, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MutexInterface } from 'async-mutex';\nimport { Mutex } from 'async-mutex';\n\nimport type { MultichainBalancesControllerMergeAccountBalanceExtrasAction } from '../MultichainBalancesController';\nimport type { MultichainAssetsControllerMethodActions } from './MultichainAssetsController-method-action-types';\nimport {\n KEYRING_GET_ACCOUNT_ASSET_INFO_METHOD,\n isStellarMultichainAccount,\n stellarAssetInfoExtraToBalanceExtra,\n} from '../multichain/stellarAccountAssetInfo';\nimport type {\n StellarAccountAssetInfoExtra,\n StellarGetAccountAssetInfoResponse,\n} from '../multichain/stellarAccountAssetInfo';\nimport { isStellarClassicAssetCaip19 } from '../multichain/stellarTrustline';\nimport { getChainIdsCaveat } from './utils';\n\nconst controllerName = 'MultichainAssetsController';\n\nexport type MultichainAssetsControllerState = {\n assetsMetadata: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n accountsAssets: { [account: string]: CaipAssetType[] };\n allIgnoredAssets: { [account: string]: CaipAssetType[] };\n};\n\n// Represents the response of the asset snap's onAssetLookup handler\nexport type AssetMetadataResponse = {\n assets: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n};\n\nexport type MultichainAssetsControllerAccountAssetListUpdatedEvent = {\n type: `${typeof controllerName}:accountAssetListUpdated`;\n payload: AccountsControllerAccountAssetListUpdatedEvent['payload'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsController} state.\n */\nexport function getDefaultMultichainAssetsControllerState(): MultichainAssetsControllerState {\n return {\n accountsAssets: {},\n assetsMetadata: {},\n allIgnoredAssets: {},\n };\n}\n\n/**\n * Returns the state of the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsControllerState\n>;\n\n/**\n * Event emitted when the state of the {@link MultichainAssetsController} changes.\n */\nexport type MultichainAssetsControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerActions =\n | MultichainAssetsControllerGetStateAction\n | MultichainAssetsControllerMethodActions;\n\n/**\n * Events emitted by {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerEvents =\n | MultichainAssetsControllerStateChangeEvent\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n\n/**\n * A function executed within a mutually exclusive lock, with\n * a mutex releaser in its option bag.\n *\n * @param releaseLock - A function to release the lock.\n */\ntype MutuallyExclusiveCallback<Result> = ({\n releaseLock,\n}: {\n releaseLock: MutexInterface.Releaser;\n}) => Promise<Result>;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction\n | PhishingControllerBulkScanTokensAction\n | MultichainBalancesControllerMergeAccountBalanceExtrasAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountAssetListUpdatedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | ControllerStateChangedEvent<'KeyringController', KeyringControllerState>;\n\n/**\n * Messenger type for the MultichainAssetsController.\n */\nexport type MultichainAssetsControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsControllerActions | AllowedActions,\n MultichainAssetsControllerEvents | AllowedEvents\n>;\n\n/**\n * {@link MultichainAssetsController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nconst assetsControllerMetadata: StateMetadata<MultichainAssetsControllerState> =\n {\n assetsMetadata: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n accountsAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n allIgnoredAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n };\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getAssetMetadata',\n 'ignoreAssets',\n 'addAssets',\n] as const;\n\n/** Phishing API allows at most this many token addresses per bulk scan request. */\nconst BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE = 100;\n\n/**\n * Default interval for re-scanning stored SPL (`token:`) assets with Blockaid.\n * Once per day limits API load while still catching tokens reclassified after add.\n */\nconst DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ntype ChainTokenEntry = { asset: CaipAssetType; address: string };\n\ntype BulkTokenScanBatchOutcome =\n | {\n status: 'fulfilled';\n response: BulkTokenScanResponse;\n entries: ChainTokenEntry[];\n }\n | { status: 'rejected'; entries: ChainTokenEntry[] };\n\nexport class MultichainAssetsController extends StaticIntervalPollingController<null>()<\n typeof controllerName,\n MultichainAssetsControllerState,\n MultichainAssetsControllerMessenger\n> {\n // Mapping of CAIP-2 Chain ID to Asset Snaps.\n #snaps: Record<CaipChainId, Snap[]>;\n\n readonly #controllerOperationMutex = new Mutex();\n\n constructor({\n messenger,\n state = {},\n blockaidTokenRescanInterval = DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS,\n }: {\n messenger: MultichainAssetsControllerMessenger;\n state?: Partial<MultichainAssetsControllerState>;\n /** Blockaid re-scan interval (ms); default daily. `0` disables. */\n blockaidTokenRescanInterval?: number;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: assetsControllerMetadata,\n state: {\n ...getDefaultMultichainAssetsControllerState(),\n ...state,\n },\n });\n\n this.#snaps = {};\n\n if (blockaidTokenRescanInterval > 0) {\n this.setIntervalLength(blockaidTokenRescanInterval);\n this.startPolling(null);\n }\n\n this.messenger.subscribe(\n 'AccountsController:accountAdded',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountAddedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountRemoved',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountRemovedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (event) => await this.#handleAccountAssetListUpdatedEvent(event),\n );\n this.messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (event) => {\n // eslint-disable-next-line no-void\n void this.#handleAccountBalancesUpdatedForEnrichment(event);\n },\n );\n\n // Bootstrap trust-line `extra` after unlock (and when already unlocked on first state event).\n let previousKeyringIsUnlocked: boolean | undefined;\n this.messenger.subscribe(\n 'KeyringController:stateChanged',\n (keyringState: KeyringControllerState) => {\n const { isUnlocked } = keyringState;\n if (previousKeyringIsUnlocked === undefined) {\n previousKeyringIsUnlocked = isUnlocked;\n if (isUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n return;\n }\n const justUnlocked = isUnlocked && !previousKeyringIsUnlocked;\n previousKeyringIsUnlocked = isUnlocked;\n if (justUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n async _executePoll(_input: null): Promise<void> {\n await this.#withControllerLock(async () => {\n const assetsByAccount: Record<\n string,\n { added: CaipAssetType[]; removed: CaipAssetType[] }\n > = {};\n\n for (const [accountId, assets] of Object.entries(\n this.state.accountsAssets,\n )) {\n const splTokens = assets.filter((asset) => {\n if (!isCaipAssetType(asset)) {\n return false;\n }\n try {\n return parseCaipAssetType(asset).assetNamespace === 'token';\n } catch {\n return false;\n }\n });\n\n if (splTokens.length === 0) {\n continue;\n }\n\n const malicious = await this.#findMaliciousTokensAmong(splTokens);\n if (malicious.length > 0) {\n this.ignoreAssets(malicious, accountId);\n assetsByAccount[accountId] = {\n added: [],\n removed: malicious,\n };\n }\n }\n\n if (Object.keys(assetsByAccount).length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: assetsByAccount,\n });\n }\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdatedEvent(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n return this.#withControllerLock(async () =>\n this.#handleAccountAssetListUpdated(event),\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleOnAccountAddedEvent(account: InternalAccount) {\n return this.#withControllerLock(async () =>\n this.#handleOnAccountAdded(account),\n );\n }\n\n /**\n * Returns the metadata for the given asset\n *\n * @param asset - The asset to get metadata for\n * @returns The metadata for the asset or undefined if not found.\n */\n getAssetMetadata(asset: CaipAssetType): FungibleAssetMetadata | undefined {\n return this.state.assetsMetadata[asset];\n }\n\n /**\n * Ignores a batch of assets for a specific account.\n *\n * @param assetsToIgnore - Array of asset IDs to ignore.\n * @param accountId - The account ID to ignore assets for.\n */\n ignoreAssets(assetsToIgnore: CaipAssetType[], accountId: string): void {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = state.accountsAssets[\n accountId\n ].filter((asset) => !assetsToIgnore.includes(asset));\n }\n\n if (!state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = [];\n }\n\n const newIgnoredAssets = assetsToIgnore.filter(\n (asset) => !state.allIgnoredAssets[accountId].includes(asset),\n );\n state.allIgnoredAssets[accountId].push(...newIgnoredAssets);\n });\n }\n\n /**\n * Adds multiple assets to the stored asset list for a specific account.\n * All assets must belong to the same chain.\n *\n * @param assetIds - Array of CAIP asset IDs to add (must be from same chain).\n * @param accountId - The account ID to add the assets to.\n * @returns The updated asset list for the account.\n * @throws Error if assets are from different chains.\n */\n async addAssets(\n assetIds: CaipAssetType[],\n accountId: string,\n ): Promise<CaipAssetType[]> {\n if (assetIds.length === 0) {\n return this.state.accountsAssets[accountId] || [];\n }\n\n // Validate that all assets are from the same chain\n const chainIds = new Set(\n assetIds.map((assetId) => parseCaipAssetType(assetId).chainId),\n );\n if (chainIds.size > 1) {\n throw new Error(\n `All assets must belong to the same chain. Found assets from chains: ${Array.from(chainIds).join(', ')}`,\n );\n }\n\n return this.#withControllerLock(async () => {\n // Refresh metadata for all assets\n await this.#refreshAssetsMetadata(assetIds);\n\n const addedAssets: CaipAssetType[] = [];\n\n this.update((state) => {\n // Initialize account assets if it doesn't exist\n if (!state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = [];\n }\n\n // Add assets if they don't already exist\n for (const assetId of assetIds) {\n if (!state.accountsAssets[accountId].includes(assetId)) {\n state.accountsAssets[accountId].push(assetId);\n addedAssets.push(assetId);\n }\n }\n\n // Remove from ignored list if they exist there (inline logic like EVM)\n if (state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = state.allIgnoredAssets[\n accountId\n ].filter((asset) => !assetIds.includes(asset));\n\n // Clean up empty arrays\n if (state.allIgnoredAssets[accountId].length === 0) {\n delete state.allIgnoredAssets[accountId];\n }\n }\n\n });\n\n // Publish event to notify other controllers (balances, rates) about the new assets\n if (addedAssets.length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [accountId]: {\n added: addedAssets,\n removed: [],\n },\n },\n });\n // Let MultichainBalancesController create balance rows before merging trust-line `extra`.\n await Promise.resolve();\n await this.#enrichStellarAccountAssetInfo(accountId, addedAssets);\n }\n\n return this.state.accountsAssets[accountId] || [];\n });\n }\n\n /**\n * Checks if an asset is ignored for a specific account.\n *\n * @param asset - The asset ID to check.\n * @param accountId - The account ID to check for.\n * @returns True if the asset is ignored, false otherwise.\n */\n #isAssetIgnored(asset: CaipAssetType, accountId: string): boolean {\n return this.state.allIgnoredAssets[accountId]?.includes(asset) ?? false;\n }\n\n /**\n * Function to update the assets list for an account\n *\n * @param event - The list of assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdated(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n this.#assertControllerMutexIsLocked();\n\n const assetsForMetadataRefresh = new Set<CaipAssetType>([]);\n const accountsAndAssetsToUpdate: AccountAssetListUpdatedEventPayload['assets'] =\n {};\n for (const [accountId, { added, removed }] of Object.entries(\n event.assets,\n )) {\n if (added.length > 0 || removed.length > 0) {\n const existing = this.state.accountsAssets[accountId] || [];\n\n // In case accountsAndAssetsToUpdate event is fired with \"added\" assets that already exist, we don't want to add them again\n // Also filter out ignored assets\n const preFilteredToBeAddedAssets = added.filter(\n (asset) =>\n !existing.includes(asset) &&\n isCaipAssetType(asset) &&\n !this.#isAssetIgnored(asset, accountId),\n );\n\n // Filter out tokens that cannot be verified or are flagged malicious\n const filteredToBeAddedAssets =\n await this.#filterBlockaidSpamTokensOnAdd(preFilteredToBeAddedAssets);\n\n // In case accountsAndAssetsToUpdate event is fired with \"removed\" assets that don't exist, we don't want to remove them\n const filteredToBeRemovedAssets = removed.filter(\n (asset) => existing.includes(asset) && isCaipAssetType(asset),\n );\n\n if (\n filteredToBeAddedAssets.length > 0 ||\n filteredToBeRemovedAssets.length > 0\n ) {\n accountsAndAssetsToUpdate[accountId] = {\n added: filteredToBeAddedAssets,\n removed: filteredToBeRemovedAssets,\n };\n }\n\n for (const asset of existing) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeAddedAssets) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeRemovedAssets) {\n assetsForMetadataRefresh.delete(asset);\n }\n }\n }\n\n this.update((state) => {\n for (const [accountId, { added, removed: removedAssets }] of Object.entries(\n accountsAndAssetsToUpdate,\n )) {\n const assets = new Set([\n ...(state.accountsAssets[accountId] || []),\n ...added,\n ]);\n for (const asset of removedAssets) {\n assets.delete(asset);\n }\n\n state.accountsAssets[accountId] = Array.from(assets);\n }\n });\n\n // Trigger fetching metadata for new assets\n await this.#refreshAssetsMetadata(Array.from(assetsForMetadataRefresh));\n\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: accountsAndAssetsToUpdate,\n });\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles changes when a new account has been added.\n *\n * @param account - The new account being added.\n */\n async #handleOnAccountAdded(account: InternalAccount): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n this.#assertControllerMutexIsLocked();\n\n // Get assets list\n if (account.metadata.snap) {\n const allAssets = await this.#getAssetsList(\n account.id,\n account.metadata.snap.id,\n );\n const caipAssets = allAssets.filter(isCaipAssetType);\n const filteredCaip =\n await this.#filterBlockaidSpamTokensOnAdd(caipAssets);\n const filteredCaipSet = new Set(filteredCaip);\n const assets = allAssets.filter(\n (asset) => !isCaipAssetType(asset) || filteredCaipSet.has(asset),\n );\n await this.#refreshAssetsMetadata(assets);\n this.update((state) => {\n state.accountsAssets[account.id] = assets;\n });\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [account.id]: {\n added: assets,\n removed: [],\n },\n },\n });\n\n await this.#enrichStellarAccountAssetInfo(account.id, filteredCaip);\n }\n }\n\n /**\n * After unlock, enrich trust-line `extra` for all Stellar classics already in the portfolio.\n */\n async #bootstrapStellarTrustlineExtras(): Promise<void> {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n for (const account of accounts) {\n if (!isStellarMultichainAccount(account)) {\n continue;\n }\n const classics = (this.state.accountsAssets[account.id] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length > 0) {\n await this.#enrichStellarAccountAssetInfo(account.id, classics);\n }\n }\n }\n\n /**\n * After snap balance events, fetch Stellar asset info (metadata + trust-line `extra`).\n *\n * @param payload - Keyring balance update payload.\n */\n async #handleAccountBalancesUpdatedForEnrichment(\n payload: AccountBalancesUpdatedEventPayload,\n ): Promise<void> {\n // Yield so MultichainBalancesController applies balance rows first (MAC inits before MBC in extension).\n await Promise.resolve();\n\n for (const accountId of Object.keys(payload.balances)) {\n const classics = (this.state.accountsAssets[accountId] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length === 0) {\n continue;\n }\n await this.#enrichStellarAccountAssetInfo(accountId, classics);\n }\n }\n\n /**\n * Fetches Stellar-only `keyring_getAccountAssetInfo` and merges metadata + balance `extra`.\n *\n * @param accountId - Account id.\n * @param assetIds - Assets to enrich.\n */\n async #enrichStellarAccountAssetInfo(\n accountId: string,\n assetIds: CaipAssetType[],\n ): Promise<void> {\n const stellarClassicIds = assetIds.filter(isStellarClassicAssetCaip19);\n if (stellarClassicIds.length === 0) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n const account = accounts.find((a) => a.id === accountId);\n if (!account || !isStellarMultichainAccount(account)) {\n return;\n }\n\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n return;\n }\n\n const info = await this.#getAccountAssetInfoFromSnap(\n accountId,\n snapId,\n stellarClassicIds,\n );\n if (!info) {\n return;\n }\n\n const metadataUpdates: Record<CaipAssetType, FungibleAssetMetadata> = {};\n const extrasByAsset: Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra | undefined\n > = {};\n\n for (const assetId of stellarClassicIds) {\n const entry = info[assetId];\n if (!entry) {\n // Snap omits assets with no on-chain row (portfolio import without trust line).\n extrasByAsset[assetId] = { limit: '0' };\n continue;\n }\n metadataUpdates[assetId] = entry.metadata;\n const balanceExtra = stellarAssetInfoExtraToBalanceExtra(entry.extra);\n if (balanceExtra === undefined) {\n // Snap omits extra when there is no on-chain trust line (portfolio import).\n extrasByAsset[assetId] = { limit: '0' };\n } else {\n extrasByAsset[assetId] = balanceExtra;\n }\n }\n\n if (Object.keys(metadataUpdates).length > 0) {\n this.update((state) => {\n state.assetsMetadata = {\n ...state.assetsMetadata,\n ...metadataUpdates,\n };\n });\n }\n\n if (Object.keys(extrasByAsset).length > 0) {\n this.messenger.call(\n 'MultichainBalancesController:mergeAccountBalanceExtras',\n accountId,\n extrasByAsset,\n );\n }\n }\n\n /**\n * Calls the Stellar snap `keyring_getAccountAssetInfo` handler.\n *\n * @param accountId - Account id.\n * @param snapId - Stellar wallet snap id.\n * @param assets - CAIP-19 assets to resolve.\n * @returns Per-asset metadata and optional trust-line extra, or undefined on failure.\n */\n async #getAccountAssetInfoFromSnap(\n accountId: string,\n snapId: string,\n assets: CaipAssetType[],\n ): Promise<StellarGetAccountAssetInfoResponse | undefined> {\n try {\n return (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request: {\n jsonrpc: '2.0',\n method: KEYRING_GET_ACCOUNT_ASSET_INFO_METHOD,\n params: {\n accountId,\n assets,\n },\n },\n })) as StellarGetAccountAssetInfoResponse;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The new account id being removed.\n */\n async #handleOnAccountRemovedEvent(accountId: string): Promise<void> {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n delete state.accountsAssets[accountId];\n }\n if (state.allIgnoredAssets[accountId]) {\n delete state.allIgnoredAssets[accountId];\n }\n // TODO: We are not deleting the assetsMetadata because we will soon make this controller extends StaticIntervalPollingController\n // and update all assetsMetadata once a day.\n });\n }\n\n /**\n * Refreshes the assets snaps and metadata for the given list of assets\n *\n * @param assets - The assets to refresh\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #refreshAssetsMetadata(assets: CaipAssetType[]) {\n this.#assertControllerMutexIsLocked();\n\n const assetsWithoutMetadata: CaipAssetType[] = assets.filter(\n (asset) => !this.state.assetsMetadata[asset],\n );\n\n // Call the snap to get the metadata\n if (assetsWithoutMetadata.length > 0) {\n // Check if for every asset in assetsWithoutMetadata there is a snap in snaps by chainId else call getAssetSnaps\n if (\n !assetsWithoutMetadata.every((asset: CaipAssetType) => {\n const { chainId } = parseCaipAssetType(asset);\n return Boolean(this.#getAssetSnapFor(chainId));\n })\n ) {\n this.#snaps = this.#getAssetSnaps();\n }\n await this.#updateAssetsMetadata(assetsWithoutMetadata);\n }\n }\n\n /**\n * Updates the assets metadata for the given list of assets\n *\n * @param assets - The assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #updateAssetsMetadata(assets: CaipAssetType[]) {\n // Creates a mapping of scope to their respective assets list.\n const assetsByScope: Record<CaipChainId, CaipAssetType[]> = {};\n for (const asset of assets) {\n const { chainId } = parseCaipAssetType(asset);\n if (!assetsByScope[chainId]) {\n assetsByScope[chainId] = [];\n }\n assetsByScope[chainId].push(asset);\n }\n\n let newMetadata: Record<CaipAssetType, FungibleAssetMetadata> = {};\n for (const chainId of Object.keys(assetsByScope) as CaipChainId[]) {\n const assetsForChain = assetsByScope[chainId];\n // Now fetch metadata from the associated asset Snaps:\n const snap = this.#getAssetSnapFor(chainId);\n if (snap) {\n const metadata = await this.#getAssetsMetadataFrom(\n assetsForChain,\n snap.id,\n );\n newMetadata = {\n ...newMetadata,\n ...(metadata?.assets ?? {}),\n };\n }\n }\n this.update((state) => {\n state.assetsMetadata = {\n ...this.state.assetsMetadata,\n ...newMetadata,\n };\n });\n }\n\n /**\n * Creates a mapping of CAIP-2 Chain ID to Asset Snaps.\n *\n * @returns A mapping of CAIP-2 Chain ID to Asset Snaps.\n */\n #getAssetSnaps(): Record<CaipChainId, Snap[]> {\n const snaps: Record<CaipChainId, Snap[]> = {};\n const allSnaps = this.#getAllSnaps();\n const allPermissions = allSnaps.map((snap) =>\n this.#getSnapsPermissions(snap.id),\n );\n\n for (const [index, permission] of allPermissions.entries()) {\n let scopes;\n for (const singlePermissionConstraint of Object.values(permission)) {\n scopes = getChainIdsCaveat(singlePermissionConstraint);\n if (!scopes) {\n continue;\n }\n for (const scope of scopes as CaipChainId[]) {\n if (!snaps[scope]) {\n snaps[scope] = [];\n }\n snaps[scope].push(allSnaps[index]);\n }\n }\n }\n return snaps;\n }\n\n /**\n * Returns the first asset snap for the given scope\n *\n * @param scope - The scope to get the asset snap for\n * @returns The asset snap for the given scope\n */\n #getAssetSnapFor(scope: CaipChainId): Snap | undefined {\n const allSnaps = this.#snaps[scope];\n // Pick only the first one, we ignore the other Snaps if there are multiple candidates for now.\n return allSnaps?.[0]; // Will be undefined if there's no Snaps candidate for this scope.\n }\n\n /**\n * Returns all the asset snaps\n *\n * @returns All the asset snaps\n */\n #getAllSnaps(): Snap[] {\n return this.messenger.call('SnapController:getRunnableSnaps');\n }\n\n /**\n * Returns the permissions for the given origin\n *\n * @param origin - The origin to get the permissions for\n * @returns The permissions for the given origin\n */\n #getSnapsPermissions(\n origin: string,\n ): SubjectPermissions<PermissionConstraint> {\n return this.messenger.call(\n 'PermissionController:getPermissions',\n origin,\n ) as SubjectPermissions<PermissionConstraint>;\n }\n\n /**\n * Returns the metadata for the given assets\n *\n * @param assets - The assets to get metadata for\n * @param snapId - The snap ID to get metadata from\n * @returns The metadata for the assets\n */\n async #getAssetsMetadataFrom(\n assets: CaipAssetType[],\n snapId: string,\n ): Promise<AssetMetadataResponse | undefined> {\n try {\n const response = (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetsLookup,\n request: {\n jsonrpc: '2.0',\n method: 'onAssetLookup',\n params: {\n assets,\n },\n },\n })) as AssetMetadataResponse;\n return response;\n } catch (error) {\n // Ignore\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Groups `token:` CAIP assets by chain namespace for bulk scan.\n *\n * @param assets - CAIP assets to inspect.\n * @returns Map of chain namespace to token entries.\n */\n #groupTokenAssetsByChain(\n assets: CaipAssetType[],\n ): Record<string, ChainTokenEntry[]> {\n const tokensByChain: Record<string, ChainTokenEntry[]> = {};\n\n for (const asset of assets) {\n const { assetNamespace, assetReference, chain } =\n parseCaipAssetType(asset);\n\n if (assetNamespace === 'token') {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n }\n\n return tokensByChain;\n }\n\n async #runBatchedBulkTokenScans(\n chainName: string,\n tokenEntries: ChainTokenEntry[],\n ): Promise<BulkTokenScanBatchOutcome[]> {\n const batches: ChainTokenEntry[][] = [];\n for (\n let i = 0;\n i < tokenEntries.length;\n i += BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE\n ) {\n batches.push(\n tokenEntries.slice(i, i + BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE),\n );\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.messenger.call('PhishingController:bulkScanTokens', {\n chainId: chainName,\n tokens: batch.map((entry) => entry.address),\n }),\n ),\n );\n\n return batches.map((entries, index) => {\n const result = batchResults[index];\n if (result.status === 'fulfilled') {\n return {\n status: 'fulfilled' as const,\n response: result.value,\n entries,\n };\n }\n return { status: 'rejected' as const, entries };\n });\n }\n\n /**\n * Fail-open Blockaid filter for newly detected `token:` assets (native/other namespaces unchanged).\n *\n * @param assets - CAIP assets to filter.\n * @returns Filtered list, original order preserved.\n */\n async #filterBlockaidSpamTokensOnAdd(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n if (Object.keys(tokensByChain).length === 0) {\n return [...assets];\n }\n\n const rejectedAssets = new Set<CaipAssetType>();\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n // Fail-open: if API fails, allow all tokens in this batch through\n continue;\n }\n for (const entry of outcome.entries) {\n const scanned = outcome.response[entry.address];\n // Reject only if we have a definitive malicious result\n if (\n scanned?.result_type &&\n scanned.result_type === TokenScanResultType.Malicious\n ) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * SPL `token:` assets in state that Blockaid marks malicious (failed batches skipped).\n *\n * @param assets - CAIP `token:` assets to scan.\n * @returns Subset marked malicious.\n */\n async #findMaliciousTokensAmong(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n const maliciousAssets: CaipAssetType[] = [];\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n continue;\n }\n for (const entry of outcome.entries) {\n if (\n outcome.response[entry.address]?.result_type ===\n TokenScanResultType.Malicious\n ) {\n maliciousAssets.push(entry.asset);\n }\n }\n }\n }\n\n return maliciousAssets;\n }\n\n /**\n * Get assets list for an account\n *\n * @param accountId - AccountId to get assets for\n * @param snapId - Snap ID for the account\n * @returns list of assets\n */\n async #getAssetsList(\n accountId: string,\n snapId: string,\n ): Promise<CaipAssetTypeOrId[]> {\n return await this.#getClient(snapId).listAccountAssets(accountId);\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n\n /**\n * Assert that the controller mutex is locked.\n *\n * @throws If the controller mutex is not locked.\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n #assertControllerMutexIsLocked() {\n if (!this.#controllerOperationMutex.isLocked()) {\n throw new Error(\n 'MultichainAssetsControllerError - Attempt to update state',\n );\n }\n }\n\n /**\n * Lock the controller mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * This wrapper ensures that each mutable operation that interacts with the\n * controller and that changes its state is executed in a mutually exclusive way,\n * preventing unsafe concurrent access that could lead to unpredictable behavior.\n *\n * @param callback - The function to execute while the controller mutex is locked.\n * @returns The result of the function.\n */\n async #withControllerLock<Result>(\n callback: MutuallyExclusiveCallback<Result>,\n ): Promise<Result> {\n return withLock(this.#controllerOperationMutex, callback);\n }\n}\n\n/**\n * Lock the given mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * @param mutex - The mutex to lock.\n * @param callback - The function to execute while the mutex is locked.\n * @returns The result of the function.\n */\nasync function withLock<Result>(\n mutex: Mutex,\n callback: MutuallyExclusiveCallback<Result>,\n): Promise<Result> {\n const releaseLock = await mutex.acquire();\n\n try {\n return await callback({ releaseLock });\n } finally {\n releaseLock();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainAssetsController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountAssetListUpdatedEvent,\n AccountsControllerAccountBalancesUpdatesEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n CaipAssetType,\n CaipAssetTypeOrId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerState,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n GetPermissions,\n PermissionConstraint,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n} from '@metamask/snaps-controllers';\nimport type { FungibleAssetMetadata, Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { isCaipAssetType, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MutexInterface } from 'async-mutex';\nimport { Mutex } from 'async-mutex';\n\nimport type { MultichainBalancesControllerMergeAccountBalanceExtrasAction } from '../MultichainBalancesController';\nimport type { MultichainAssetsControllerMethodActions } from './MultichainAssetsController-method-action-types';\nimport {\n STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,\n isStellarMultichainAccount,\n stellarAssetInfoExtraToBalanceExtra,\n} from '../multichain/stellarAccountAssetInfo';\nimport type {\n StellarAccountAssetInfoExtra,\n StellarGetAccountAssetInfoResponse,\n} from '../multichain/stellarAccountAssetInfo';\nimport { isStellarClassicAssetCaip19 } from '../multichain/stellarTrustline';\nimport { getChainIdsCaveat } from './utils';\n\nconst controllerName = 'MultichainAssetsController';\n\nexport type MultichainAssetsControllerState = {\n assetsMetadata: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n accountsAssets: { [account: string]: CaipAssetType[] };\n allIgnoredAssets: { [account: string]: CaipAssetType[] };\n};\n\n// Represents the response of the asset snap's onAssetLookup handler\nexport type AssetMetadataResponse = {\n assets: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n};\n\nexport type MultichainAssetsControllerAccountAssetListUpdatedEvent = {\n type: `${typeof controllerName}:accountAssetListUpdated`;\n payload: AccountsControllerAccountAssetListUpdatedEvent['payload'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsController} state.\n */\nexport function getDefaultMultichainAssetsControllerState(): MultichainAssetsControllerState {\n return {\n accountsAssets: {},\n assetsMetadata: {},\n allIgnoredAssets: {},\n };\n}\n\n/**\n * Returns the state of the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsControllerState\n>;\n\n/**\n * Event emitted when the state of the {@link MultichainAssetsController} changes.\n */\nexport type MultichainAssetsControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerActions =\n | MultichainAssetsControllerGetStateAction\n | MultichainAssetsControllerMethodActions;\n\n/**\n * Events emitted by {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerEvents =\n | MultichainAssetsControllerStateChangeEvent\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n\n/**\n * A function executed within a mutually exclusive lock, with\n * a mutex releaser in its option bag.\n *\n * @param releaseLock - A function to release the lock.\n */\ntype MutuallyExclusiveCallback<Result> = ({\n releaseLock,\n}: {\n releaseLock: MutexInterface.Releaser;\n}) => Promise<Result>;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction\n | PhishingControllerBulkScanTokensAction\n | MultichainBalancesControllerMergeAccountBalanceExtrasAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountAssetListUpdatedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | ControllerStateChangedEvent<'KeyringController', KeyringControllerState>;\n\n/**\n * Messenger type for the MultichainAssetsController.\n */\nexport type MultichainAssetsControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsControllerActions | AllowedActions,\n MultichainAssetsControllerEvents | AllowedEvents\n>;\n\n/**\n * {@link MultichainAssetsController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nconst assetsControllerMetadata: StateMetadata<MultichainAssetsControllerState> =\n {\n assetsMetadata: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n accountsAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n allIgnoredAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n };\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getAssetMetadata',\n 'ignoreAssets',\n 'addAssets',\n] as const;\n\n/** Phishing API allows at most this many token addresses per bulk scan request. */\nconst BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE = 100;\n\n/**\n * Default interval for re-scanning stored SPL (`token:`) assets with Blockaid.\n * Once per day limits API load while still catching tokens reclassified after add.\n */\nconst DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ntype ChainTokenEntry = { asset: CaipAssetType; address: string };\n\ntype BulkTokenScanBatchOutcome =\n | {\n status: 'fulfilled';\n response: BulkTokenScanResponse;\n entries: ChainTokenEntry[];\n }\n | { status: 'rejected'; entries: ChainTokenEntry[] };\n\nexport class MultichainAssetsController extends StaticIntervalPollingController<null>()<\n typeof controllerName,\n MultichainAssetsControllerState,\n MultichainAssetsControllerMessenger\n> {\n // Mapping of CAIP-2 Chain ID to Asset Snaps.\n #snaps: Record<CaipChainId, Snap[]>;\n\n readonly #controllerOperationMutex = new Mutex();\n\n constructor({\n messenger,\n state = {},\n blockaidTokenRescanInterval = DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS,\n }: {\n messenger: MultichainAssetsControllerMessenger;\n state?: Partial<MultichainAssetsControllerState>;\n /** Blockaid re-scan interval (ms); default daily. `0` disables. */\n blockaidTokenRescanInterval?: number;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: assetsControllerMetadata,\n state: {\n ...getDefaultMultichainAssetsControllerState(),\n ...state,\n },\n });\n\n this.#snaps = {};\n\n if (blockaidTokenRescanInterval > 0) {\n this.setIntervalLength(blockaidTokenRescanInterval);\n this.startPolling(null);\n }\n\n this.messenger.subscribe(\n 'AccountsController:accountAdded',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountAddedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountRemoved',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountRemovedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (event) => await this.#handleAccountAssetListUpdatedEvent(event),\n );\n this.messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (event) => {\n // eslint-disable-next-line no-void\n void this.#handleAccountBalancesUpdatedForEnrichment(event);\n },\n );\n\n // Bootstrap trust-line `extra` after unlock (and when already unlocked on first state event).\n let previousKeyringIsUnlocked: boolean | undefined;\n this.messenger.subscribe(\n 'KeyringController:stateChanged',\n (keyringState: KeyringControllerState) => {\n const { isUnlocked } = keyringState;\n if (previousKeyringIsUnlocked === undefined) {\n previousKeyringIsUnlocked = isUnlocked;\n if (isUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n return;\n }\n const justUnlocked = isUnlocked && !previousKeyringIsUnlocked;\n previousKeyringIsUnlocked = isUnlocked;\n if (justUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n async _executePoll(_input: null): Promise<void> {\n await this.#withControllerLock(async () => {\n const assetsByAccount: Record<\n string,\n { added: CaipAssetType[]; removed: CaipAssetType[] }\n > = {};\n\n for (const [accountId, assets] of Object.entries(\n this.state.accountsAssets,\n )) {\n const splTokens = assets.filter((asset) => {\n if (!isCaipAssetType(asset)) {\n return false;\n }\n try {\n return parseCaipAssetType(asset).assetNamespace === 'token';\n } catch {\n return false;\n }\n });\n\n if (splTokens.length === 0) {\n continue;\n }\n\n const malicious = await this.#findMaliciousTokensAmong(splTokens);\n if (malicious.length > 0) {\n this.ignoreAssets(malicious, accountId);\n assetsByAccount[accountId] = {\n added: [],\n removed: malicious,\n };\n }\n }\n\n if (Object.keys(assetsByAccount).length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: assetsByAccount,\n });\n }\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdatedEvent(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n return this.#withControllerLock(async () =>\n this.#handleAccountAssetListUpdated(event),\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleOnAccountAddedEvent(account: InternalAccount) {\n return this.#withControllerLock(async () =>\n this.#handleOnAccountAdded(account),\n );\n }\n\n /**\n * Returns the metadata for the given asset\n *\n * @param asset - The asset to get metadata for\n * @returns The metadata for the asset or undefined if not found.\n */\n getAssetMetadata(asset: CaipAssetType): FungibleAssetMetadata | undefined {\n return this.state.assetsMetadata[asset];\n }\n\n /**\n * Ignores a batch of assets for a specific account.\n *\n * @param assetsToIgnore - Array of asset IDs to ignore.\n * @param accountId - The account ID to ignore assets for.\n */\n ignoreAssets(assetsToIgnore: CaipAssetType[], accountId: string): void {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = state.accountsAssets[\n accountId\n ].filter((asset) => !assetsToIgnore.includes(asset));\n }\n\n if (!state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = [];\n }\n\n const newIgnoredAssets = assetsToIgnore.filter(\n (asset) => !state.allIgnoredAssets[accountId].includes(asset),\n );\n state.allIgnoredAssets[accountId].push(...newIgnoredAssets);\n });\n }\n\n /**\n * Adds multiple assets to the stored asset list for a specific account.\n * All assets must belong to the same chain.\n *\n * @param assetIds - Array of CAIP asset IDs to add (must be from same chain).\n * @param accountId - The account ID to add the assets to.\n * @returns The updated asset list for the account.\n * @throws Error if assets are from different chains.\n */\n async addAssets(\n assetIds: CaipAssetType[],\n accountId: string,\n ): Promise<CaipAssetType[]> {\n if (assetIds.length === 0) {\n return this.state.accountsAssets[accountId] || [];\n }\n\n // Validate that all assets are from the same chain\n const chainIds = new Set(\n assetIds.map((assetId) => parseCaipAssetType(assetId).chainId),\n );\n if (chainIds.size > 1) {\n throw new Error(\n `All assets must belong to the same chain. Found assets from chains: ${Array.from(chainIds).join(', ')}`,\n );\n }\n\n return this.#withControllerLock(async () => {\n // Refresh metadata for all assets\n await this.#refreshAssetsMetadata(assetIds);\n\n const addedAssets: CaipAssetType[] = [];\n\n this.update((state) => {\n // Initialize account assets if it doesn't exist\n if (!state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = [];\n }\n\n // Add assets if they don't already exist\n for (const assetId of assetIds) {\n if (!state.accountsAssets[accountId].includes(assetId)) {\n state.accountsAssets[accountId].push(assetId);\n addedAssets.push(assetId);\n }\n }\n\n // Remove from ignored list if they exist there (inline logic like EVM)\n if (state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = state.allIgnoredAssets[\n accountId\n ].filter((asset) => !assetIds.includes(asset));\n\n // Clean up empty arrays\n if (state.allIgnoredAssets[accountId].length === 0) {\n delete state.allIgnoredAssets[accountId];\n }\n }\n\n });\n\n // Publish event to notify other controllers (balances, rates) about the new assets\n if (addedAssets.length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [accountId]: {\n added: addedAssets,\n removed: [],\n },\n },\n });\n // Let MultichainBalancesController create balance rows before merging trust-line `extra`.\n await Promise.resolve();\n await this.#enrichStellarAccountAssetInfo(accountId, addedAssets);\n }\n\n return this.state.accountsAssets[accountId] || [];\n });\n }\n\n /**\n * Checks if an asset is ignored for a specific account.\n *\n * @param asset - The asset ID to check.\n * @param accountId - The account ID to check for.\n * @returns True if the asset is ignored, false otherwise.\n */\n #isAssetIgnored(asset: CaipAssetType, accountId: string): boolean {\n return this.state.allIgnoredAssets[accountId]?.includes(asset) ?? false;\n }\n\n /**\n * Function to update the assets list for an account\n *\n * @param event - The list of assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdated(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n this.#assertControllerMutexIsLocked();\n\n const assetsForMetadataRefresh = new Set<CaipAssetType>([]);\n const accountsAndAssetsToUpdate: AccountAssetListUpdatedEventPayload['assets'] =\n {};\n for (const [accountId, { added, removed }] of Object.entries(\n event.assets,\n )) {\n if (added.length > 0 || removed.length > 0) {\n const existing = this.state.accountsAssets[accountId] || [];\n\n // In case accountsAndAssetsToUpdate event is fired with \"added\" assets that already exist, we don't want to add them again\n // Also filter out ignored assets\n const preFilteredToBeAddedAssets = added.filter(\n (asset) =>\n !existing.includes(asset) &&\n isCaipAssetType(asset) &&\n !this.#isAssetIgnored(asset, accountId),\n );\n\n // Filter out tokens that cannot be verified or are flagged malicious\n const filteredToBeAddedAssets =\n await this.#filterBlockaidSpamTokensOnAdd(preFilteredToBeAddedAssets);\n\n // In case accountsAndAssetsToUpdate event is fired with \"removed\" assets that don't exist, we don't want to remove them\n const filteredToBeRemovedAssets = removed.filter(\n (asset) => existing.includes(asset) && isCaipAssetType(asset),\n );\n\n if (\n filteredToBeAddedAssets.length > 0 ||\n filteredToBeRemovedAssets.length > 0\n ) {\n accountsAndAssetsToUpdate[accountId] = {\n added: filteredToBeAddedAssets,\n removed: filteredToBeRemovedAssets,\n };\n }\n\n for (const asset of existing) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeAddedAssets) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeRemovedAssets) {\n assetsForMetadataRefresh.delete(asset);\n }\n }\n }\n\n this.update((state) => {\n for (const [accountId, { added, removed: removedAssets }] of Object.entries(\n accountsAndAssetsToUpdate,\n )) {\n const assets = new Set([\n ...(state.accountsAssets[accountId] || []),\n ...added,\n ]);\n for (const asset of removedAssets) {\n assets.delete(asset);\n }\n\n state.accountsAssets[accountId] = Array.from(assets);\n }\n });\n\n // Trigger fetching metadata for new assets\n await this.#refreshAssetsMetadata(Array.from(assetsForMetadataRefresh));\n\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: accountsAndAssetsToUpdate,\n });\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles changes when a new account has been added.\n *\n * @param account - The new account being added.\n */\n async #handleOnAccountAdded(account: InternalAccount): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n this.#assertControllerMutexIsLocked();\n\n // Get assets list\n if (account.metadata.snap) {\n const allAssets = await this.#getAssetsList(\n account.id,\n account.metadata.snap.id,\n );\n const caipAssets = allAssets.filter(isCaipAssetType);\n const filteredCaip =\n await this.#filterBlockaidSpamTokensOnAdd(caipAssets);\n const filteredCaipSet = new Set(filteredCaip);\n const assets = allAssets.filter(\n (asset) => !isCaipAssetType(asset) || filteredCaipSet.has(asset),\n );\n await this.#refreshAssetsMetadata(assets);\n this.update((state) => {\n state.accountsAssets[account.id] = assets;\n });\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [account.id]: {\n added: assets,\n removed: [],\n },\n },\n });\n\n await this.#enrichStellarAccountAssetInfo(account.id, filteredCaip);\n }\n }\n\n /**\n * After unlock, enrich trust-line `extra` for all Stellar classics already in the portfolio.\n */\n async #bootstrapStellarTrustlineExtras(): Promise<void> {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n for (const account of accounts) {\n if (!isStellarMultichainAccount(account)) {\n continue;\n }\n const classics = (this.state.accountsAssets[account.id] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length > 0) {\n await this.#enrichStellarAccountAssetInfo(account.id, classics);\n }\n }\n }\n\n /**\n * After snap balance events, fetch Stellar trust-line `extra` via `getAccountAssetInfo`.\n *\n * @param payload - Keyring balance update payload.\n */\n async #handleAccountBalancesUpdatedForEnrichment(\n payload: AccountBalancesUpdatedEventPayload,\n ): Promise<void> {\n // Yield so MultichainBalancesController applies balance rows first (MAC inits before MBC in extension).\n await Promise.resolve();\n\n for (const accountId of Object.keys(payload.balances)) {\n const classics = (this.state.accountsAssets[accountId] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length === 0) {\n continue;\n }\n await this.#enrichStellarAccountAssetInfo(accountId, classics);\n }\n }\n\n /**\n * Fetches Stellar-only `getAccountAssetInfo` client request and merges trust-line `extra` into balances.\n *\n * @param accountId - Account id.\n * @param assetIds - Assets to enrich.\n */\n async #enrichStellarAccountAssetInfo(\n accountId: string,\n assetIds: CaipAssetType[],\n ): Promise<void> {\n const stellarClassicIds = assetIds.filter(isStellarClassicAssetCaip19);\n if (stellarClassicIds.length === 0) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n const account = accounts.find((a) => a.id === accountId);\n if (!account || !isStellarMultichainAccount(account)) {\n return;\n }\n\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n return;\n }\n\n const info = await this.#getAccountAssetInfoFromSnap(\n accountId,\n snapId,\n account.scopes[0] as CaipChainId,\n stellarClassicIds,\n );\n if (!info) {\n return;\n }\n\n const extrasByAsset: Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra | undefined\n > = {};\n\n for (const assetId of stellarClassicIds) {\n const snapExtra = info[assetId];\n if (snapExtra === undefined) {\n // Snap omits assets with no on-chain row (portfolio import without trust line).\n extrasByAsset[assetId] = { limit: '0' };\n continue;\n }\n const balanceExtra = stellarAssetInfoExtraToBalanceExtra(snapExtra);\n extrasByAsset[assetId] = balanceExtra ?? { limit: '0' };\n }\n\n if (Object.keys(extrasByAsset).length > 0) {\n this.messenger.call(\n 'MultichainBalancesController:mergeAccountBalanceExtras',\n accountId,\n extrasByAsset,\n );\n }\n }\n\n /**\n * Calls the Stellar snap `getAccountAssetInfo` client request handler.\n *\n * @param accountId - Account id.\n * @param snapId - Stellar wallet snap id.\n * @param scope - Stellar CAIP-2 chain id.\n * @param assets - CAIP-19 assets to resolve.\n * @returns Per-asset trust-line fields, or undefined on failure.\n */\n async #getAccountAssetInfoFromSnap(\n accountId: string,\n snapId: string,\n scope: CaipChainId,\n assets: CaipAssetType[],\n ): Promise<StellarGetAccountAssetInfoResponse | undefined> {\n try {\n return (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnClientRequest,\n request: {\n jsonrpc: '2.0',\n method: STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,\n params: {\n accountId,\n scope,\n assets,\n },\n },\n })) as StellarGetAccountAssetInfoResponse;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The new account id being removed.\n */\n async #handleOnAccountRemovedEvent(accountId: string): Promise<void> {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n delete state.accountsAssets[accountId];\n }\n if (state.allIgnoredAssets[accountId]) {\n delete state.allIgnoredAssets[accountId];\n }\n // TODO: We are not deleting the assetsMetadata because we will soon make this controller extends StaticIntervalPollingController\n // and update all assetsMetadata once a day.\n });\n }\n\n /**\n * Refreshes the assets snaps and metadata for the given list of assets\n *\n * @param assets - The assets to refresh\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #refreshAssetsMetadata(assets: CaipAssetType[]) {\n this.#assertControllerMutexIsLocked();\n\n const assetsWithoutMetadata: CaipAssetType[] = assets.filter(\n (asset) => !this.state.assetsMetadata[asset],\n );\n\n // Call the snap to get the metadata\n if (assetsWithoutMetadata.length > 0) {\n // Check if for every asset in assetsWithoutMetadata there is a snap in snaps by chainId else call getAssetSnaps\n if (\n !assetsWithoutMetadata.every((asset: CaipAssetType) => {\n const { chainId } = parseCaipAssetType(asset);\n return Boolean(this.#getAssetSnapFor(chainId));\n })\n ) {\n this.#snaps = this.#getAssetSnaps();\n }\n await this.#updateAssetsMetadata(assetsWithoutMetadata);\n }\n }\n\n /**\n * Updates the assets metadata for the given list of assets\n *\n * @param assets - The assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #updateAssetsMetadata(assets: CaipAssetType[]) {\n // Creates a mapping of scope to their respective assets list.\n const assetsByScope: Record<CaipChainId, CaipAssetType[]> = {};\n for (const asset of assets) {\n const { chainId } = parseCaipAssetType(asset);\n if (!assetsByScope[chainId]) {\n assetsByScope[chainId] = [];\n }\n assetsByScope[chainId].push(asset);\n }\n\n let newMetadata: Record<CaipAssetType, FungibleAssetMetadata> = {};\n for (const chainId of Object.keys(assetsByScope) as CaipChainId[]) {\n const assetsForChain = assetsByScope[chainId];\n // Now fetch metadata from the associated asset Snaps:\n const snap = this.#getAssetSnapFor(chainId);\n if (snap) {\n const metadata = await this.#getAssetsMetadataFrom(\n assetsForChain,\n snap.id,\n );\n newMetadata = {\n ...newMetadata,\n ...(metadata?.assets ?? {}),\n };\n }\n }\n this.update((state) => {\n state.assetsMetadata = {\n ...this.state.assetsMetadata,\n ...newMetadata,\n };\n });\n }\n\n /**\n * Creates a mapping of CAIP-2 Chain ID to Asset Snaps.\n *\n * @returns A mapping of CAIP-2 Chain ID to Asset Snaps.\n */\n #getAssetSnaps(): Record<CaipChainId, Snap[]> {\n const snaps: Record<CaipChainId, Snap[]> = {};\n const allSnaps = this.#getAllSnaps();\n const allPermissions = allSnaps.map((snap) =>\n this.#getSnapsPermissions(snap.id),\n );\n\n for (const [index, permission] of allPermissions.entries()) {\n let scopes;\n for (const singlePermissionConstraint of Object.values(permission)) {\n scopes = getChainIdsCaveat(singlePermissionConstraint);\n if (!scopes) {\n continue;\n }\n for (const scope of scopes as CaipChainId[]) {\n if (!snaps[scope]) {\n snaps[scope] = [];\n }\n snaps[scope].push(allSnaps[index]);\n }\n }\n }\n return snaps;\n }\n\n /**\n * Returns the first asset snap for the given scope\n *\n * @param scope - The scope to get the asset snap for\n * @returns The asset snap for the given scope\n */\n #getAssetSnapFor(scope: CaipChainId): Snap | undefined {\n const allSnaps = this.#snaps[scope];\n // Pick only the first one, we ignore the other Snaps if there are multiple candidates for now.\n return allSnaps?.[0]; // Will be undefined if there's no Snaps candidate for this scope.\n }\n\n /**\n * Returns all the asset snaps\n *\n * @returns All the asset snaps\n */\n #getAllSnaps(): Snap[] {\n return this.messenger.call('SnapController:getRunnableSnaps');\n }\n\n /**\n * Returns the permissions for the given origin\n *\n * @param origin - The origin to get the permissions for\n * @returns The permissions for the given origin\n */\n #getSnapsPermissions(\n origin: string,\n ): SubjectPermissions<PermissionConstraint> {\n return this.messenger.call(\n 'PermissionController:getPermissions',\n origin,\n ) as SubjectPermissions<PermissionConstraint>;\n }\n\n /**\n * Returns the metadata for the given assets\n *\n * @param assets - The assets to get metadata for\n * @param snapId - The snap ID to get metadata from\n * @returns The metadata for the assets\n */\n async #getAssetsMetadataFrom(\n assets: CaipAssetType[],\n snapId: string,\n ): Promise<AssetMetadataResponse | undefined> {\n try {\n const response = (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetsLookup,\n request: {\n jsonrpc: '2.0',\n method: 'onAssetLookup',\n params: {\n assets,\n },\n },\n })) as AssetMetadataResponse;\n return response;\n } catch (error) {\n // Ignore\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Groups `token:` CAIP assets by chain namespace for bulk scan.\n *\n * @param assets - CAIP assets to inspect.\n * @returns Map of chain namespace to token entries.\n */\n #groupTokenAssetsByChain(\n assets: CaipAssetType[],\n ): Record<string, ChainTokenEntry[]> {\n const tokensByChain: Record<string, ChainTokenEntry[]> = {};\n\n for (const asset of assets) {\n const { assetNamespace, assetReference, chain } =\n parseCaipAssetType(asset);\n\n if (assetNamespace === 'token') {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n }\n\n return tokensByChain;\n }\n\n async #runBatchedBulkTokenScans(\n chainName: string,\n tokenEntries: ChainTokenEntry[],\n ): Promise<BulkTokenScanBatchOutcome[]> {\n const batches: ChainTokenEntry[][] = [];\n for (\n let i = 0;\n i < tokenEntries.length;\n i += BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE\n ) {\n batches.push(\n tokenEntries.slice(i, i + BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE),\n );\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.messenger.call('PhishingController:bulkScanTokens', {\n chainId: chainName,\n tokens: batch.map((entry) => entry.address),\n }),\n ),\n );\n\n return batches.map((entries, index) => {\n const result = batchResults[index];\n if (result.status === 'fulfilled') {\n return {\n status: 'fulfilled' as const,\n response: result.value,\n entries,\n };\n }\n return { status: 'rejected' as const, entries };\n });\n }\n\n /**\n * Fail-open Blockaid filter for newly detected `token:` assets (native/other namespaces unchanged).\n *\n * @param assets - CAIP assets to filter.\n * @returns Filtered list, original order preserved.\n */\n async #filterBlockaidSpamTokensOnAdd(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n if (Object.keys(tokensByChain).length === 0) {\n return [...assets];\n }\n\n const rejectedAssets = new Set<CaipAssetType>();\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n // Fail-open: if API fails, allow all tokens in this batch through\n continue;\n }\n for (const entry of outcome.entries) {\n const scanned = outcome.response[entry.address];\n // Reject only if we have a definitive malicious result\n if (\n scanned?.result_type &&\n scanned.result_type === TokenScanResultType.Malicious\n ) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * SPL `token:` assets in state that Blockaid marks malicious (failed batches skipped).\n *\n * @param assets - CAIP `token:` assets to scan.\n * @returns Subset marked malicious.\n */\n async #findMaliciousTokensAmong(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n const maliciousAssets: CaipAssetType[] = [];\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n continue;\n }\n for (const entry of outcome.entries) {\n if (\n outcome.response[entry.address]?.result_type ===\n TokenScanResultType.Malicious\n ) {\n maliciousAssets.push(entry.asset);\n }\n }\n }\n }\n\n return maliciousAssets;\n }\n\n /**\n * Get assets list for an account\n *\n * @param accountId - AccountId to get assets for\n * @param snapId - Snap ID for the account\n * @returns list of assets\n */\n async #getAssetsList(\n accountId: string,\n snapId: string,\n ): Promise<CaipAssetTypeOrId[]> {\n return await this.#getClient(snapId).listAccountAssets(accountId);\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n\n /**\n * Assert that the controller mutex is locked.\n *\n * @throws If the controller mutex is not locked.\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n #assertControllerMutexIsLocked() {\n if (!this.#controllerOperationMutex.isLocked()) {\n throw new Error(\n 'MultichainAssetsControllerError - Attempt to update state',\n );\n }\n }\n\n /**\n * Lock the controller mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * This wrapper ensures that each mutable operation that interacts with the\n * controller and that changes its state is executed in a mutually exclusive way,\n * preventing unsafe concurrent access that could lead to unpredictable behavior.\n *\n * @param callback - The function to execute while the controller mutex is locked.\n * @returns The result of the function.\n */\n async #withControllerLock<Result>(\n callback: MutuallyExclusiveCallback<Result>,\n ): Promise<Result> {\n return withLock(this.#controllerOperationMutex, callback);\n }\n}\n\n/**\n * Lock the given mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * @param mutex - The mutex to lock.\n * @param callback - The function to execute while the mutex is locked.\n * @returns The result of the function.\n */\nasync function withLock<Result>(\n mutex: Mutex,\n callback: MutuallyExclusiveCallback<Result>,\n): Promise<Result> {\n const releaseLock = await mutex.acquire();\n\n try {\n return await callback({ releaseLock });\n } finally {\n releaseLock();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"MultichainAssetsController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsController.d.mts","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"MultichainAssetsController.d.mts","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import { StaticIntervalPollingController } from "@metamask/polling-controller";
|
|
|
17
17
|
import { HandlerType } from "@metamask/snaps-utils";
|
|
18
18
|
import { isCaipAssetType, parseCaipAssetType } from "@metamask/utils";
|
|
19
19
|
import { Mutex } from "async-mutex";
|
|
20
|
-
import {
|
|
20
|
+
import { STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD, isStellarMultichainAccount, stellarAssetInfoExtraToBalanceExtra } from "../multichain/stellarAccountAssetInfo.mjs";
|
|
21
21
|
import { isStellarClassicAssetCaip19 } from "../multichain/stellarTrustline.mjs";
|
|
22
22
|
import { getChainIdsCaveat } from "./utils.mjs";
|
|
23
23
|
const controllerName = 'MultichainAssetsController';
|
|
@@ -377,7 +377,7 @@ async function _MultichainAssetsController_bootstrapStellarTrustlineExtras() {
|
|
|
377
377
|
}
|
|
378
378
|
}, _MultichainAssetsController_handleAccountBalancesUpdatedForEnrichment =
|
|
379
379
|
/**
|
|
380
|
-
* After snap balance events, fetch Stellar
|
|
380
|
+
* After snap balance events, fetch Stellar trust-line `extra` via `getAccountAssetInfo`.
|
|
381
381
|
*
|
|
382
382
|
* @param payload - Keyring balance update payload.
|
|
383
383
|
*/
|
|
@@ -393,7 +393,7 @@ async function _MultichainAssetsController_handleAccountBalancesUpdatedForEnrich
|
|
|
393
393
|
}
|
|
394
394
|
}, _MultichainAssetsController_enrichStellarAccountAssetInfo =
|
|
395
395
|
/**
|
|
396
|
-
* Fetches Stellar-only `
|
|
396
|
+
* Fetches Stellar-only `getAccountAssetInfo` client request and merges trust-line `extra` into balances.
|
|
397
397
|
*
|
|
398
398
|
* @param accountId - Account id.
|
|
399
399
|
* @param assetIds - Assets to enrich.
|
|
@@ -412,60 +412,46 @@ async function _MultichainAssetsController_enrichStellarAccountAssetInfo(account
|
|
|
412
412
|
if (!snapId) {
|
|
413
413
|
return;
|
|
414
414
|
}
|
|
415
|
-
const info = await __classPrivateFieldGet(this, _MultichainAssetsController_instances, "m", _MultichainAssetsController_getAccountAssetInfoFromSnap).call(this, accountId, snapId, stellarClassicIds);
|
|
415
|
+
const info = await __classPrivateFieldGet(this, _MultichainAssetsController_instances, "m", _MultichainAssetsController_getAccountAssetInfoFromSnap).call(this, accountId, snapId, account.scopes[0], stellarClassicIds);
|
|
416
416
|
if (!info) {
|
|
417
417
|
return;
|
|
418
418
|
}
|
|
419
|
-
const metadataUpdates = {};
|
|
420
419
|
const extrasByAsset = {};
|
|
421
420
|
for (const assetId of stellarClassicIds) {
|
|
422
|
-
const
|
|
423
|
-
if (
|
|
421
|
+
const snapExtra = info[assetId];
|
|
422
|
+
if (snapExtra === undefined) {
|
|
424
423
|
// Snap omits assets with no on-chain row (portfolio import without trust line).
|
|
425
424
|
extrasByAsset[assetId] = { limit: '0' };
|
|
426
425
|
continue;
|
|
427
426
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (balanceExtra === undefined) {
|
|
431
|
-
// Snap omits extra when there is no on-chain trust line (portfolio import).
|
|
432
|
-
extrasByAsset[assetId] = { limit: '0' };
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
extrasByAsset[assetId] = balanceExtra;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (Object.keys(metadataUpdates).length > 0) {
|
|
439
|
-
this.update((state) => {
|
|
440
|
-
state.assetsMetadata = {
|
|
441
|
-
...state.assetsMetadata,
|
|
442
|
-
...metadataUpdates,
|
|
443
|
-
};
|
|
444
|
-
});
|
|
427
|
+
const balanceExtra = stellarAssetInfoExtraToBalanceExtra(snapExtra);
|
|
428
|
+
extrasByAsset[assetId] = balanceExtra ?? { limit: '0' };
|
|
445
429
|
}
|
|
446
430
|
if (Object.keys(extrasByAsset).length > 0) {
|
|
447
431
|
this.messenger.call('MultichainBalancesController:mergeAccountBalanceExtras', accountId, extrasByAsset);
|
|
448
432
|
}
|
|
449
433
|
}, _MultichainAssetsController_getAccountAssetInfoFromSnap =
|
|
450
434
|
/**
|
|
451
|
-
* Calls the Stellar snap `
|
|
435
|
+
* Calls the Stellar snap `getAccountAssetInfo` client request handler.
|
|
452
436
|
*
|
|
453
437
|
* @param accountId - Account id.
|
|
454
438
|
* @param snapId - Stellar wallet snap id.
|
|
439
|
+
* @param scope - Stellar CAIP-2 chain id.
|
|
455
440
|
* @param assets - CAIP-19 assets to resolve.
|
|
456
|
-
* @returns Per-asset
|
|
441
|
+
* @returns Per-asset trust-line fields, or undefined on failure.
|
|
457
442
|
*/
|
|
458
|
-
async function _MultichainAssetsController_getAccountAssetInfoFromSnap(accountId, snapId, assets) {
|
|
443
|
+
async function _MultichainAssetsController_getAccountAssetInfoFromSnap(accountId, snapId, scope, assets) {
|
|
459
444
|
try {
|
|
460
445
|
return (await this.messenger.call('SnapController:handleRequest', {
|
|
461
446
|
snapId: snapId,
|
|
462
447
|
origin: 'metamask',
|
|
463
|
-
handler: HandlerType.
|
|
448
|
+
handler: HandlerType.OnClientRequest,
|
|
464
449
|
request: {
|
|
465
450
|
jsonrpc: '2.0',
|
|
466
|
-
method:
|
|
451
|
+
method: STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,
|
|
467
452
|
params: {
|
|
468
453
|
accountId,
|
|
454
|
+
scope,
|
|
469
455
|
assets,
|
|
470
456
|
},
|
|
471
457
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsController.mjs","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountAssetListUpdatedEvent,\n AccountsControllerAccountBalancesUpdatesEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n CaipAssetType,\n CaipAssetTypeOrId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerState,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n GetPermissions,\n PermissionConstraint,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n} from '@metamask/snaps-controllers';\nimport type { FungibleAssetMetadata, Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { isCaipAssetType, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MutexInterface } from 'async-mutex';\nimport { Mutex } from 'async-mutex';\n\nimport type { MultichainBalancesControllerMergeAccountBalanceExtrasAction } from '../MultichainBalancesController';\nimport type { MultichainAssetsControllerMethodActions } from './MultichainAssetsController-method-action-types';\nimport {\n KEYRING_GET_ACCOUNT_ASSET_INFO_METHOD,\n isStellarMultichainAccount,\n stellarAssetInfoExtraToBalanceExtra,\n} from '../multichain/stellarAccountAssetInfo';\nimport type {\n StellarAccountAssetInfoExtra,\n StellarGetAccountAssetInfoResponse,\n} from '../multichain/stellarAccountAssetInfo';\nimport { isStellarClassicAssetCaip19 } from '../multichain/stellarTrustline';\nimport { getChainIdsCaveat } from './utils';\n\nconst controllerName = 'MultichainAssetsController';\n\nexport type MultichainAssetsControllerState = {\n assetsMetadata: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n accountsAssets: { [account: string]: CaipAssetType[] };\n allIgnoredAssets: { [account: string]: CaipAssetType[] };\n};\n\n// Represents the response of the asset snap's onAssetLookup handler\nexport type AssetMetadataResponse = {\n assets: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n};\n\nexport type MultichainAssetsControllerAccountAssetListUpdatedEvent = {\n type: `${typeof controllerName}:accountAssetListUpdated`;\n payload: AccountsControllerAccountAssetListUpdatedEvent['payload'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsController} state.\n */\nexport function getDefaultMultichainAssetsControllerState(): MultichainAssetsControllerState {\n return {\n accountsAssets: {},\n assetsMetadata: {},\n allIgnoredAssets: {},\n };\n}\n\n/**\n * Returns the state of the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsControllerState\n>;\n\n/**\n * Event emitted when the state of the {@link MultichainAssetsController} changes.\n */\nexport type MultichainAssetsControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerActions =\n | MultichainAssetsControllerGetStateAction\n | MultichainAssetsControllerMethodActions;\n\n/**\n * Events emitted by {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerEvents =\n | MultichainAssetsControllerStateChangeEvent\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n\n/**\n * A function executed within a mutually exclusive lock, with\n * a mutex releaser in its option bag.\n *\n * @param releaseLock - A function to release the lock.\n */\ntype MutuallyExclusiveCallback<Result> = ({\n releaseLock,\n}: {\n releaseLock: MutexInterface.Releaser;\n}) => Promise<Result>;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction\n | PhishingControllerBulkScanTokensAction\n | MultichainBalancesControllerMergeAccountBalanceExtrasAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountAssetListUpdatedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | ControllerStateChangedEvent<'KeyringController', KeyringControllerState>;\n\n/**\n * Messenger type for the MultichainAssetsController.\n */\nexport type MultichainAssetsControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsControllerActions | AllowedActions,\n MultichainAssetsControllerEvents | AllowedEvents\n>;\n\n/**\n * {@link MultichainAssetsController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nconst assetsControllerMetadata: StateMetadata<MultichainAssetsControllerState> =\n {\n assetsMetadata: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n accountsAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n allIgnoredAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n };\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getAssetMetadata',\n 'ignoreAssets',\n 'addAssets',\n] as const;\n\n/** Phishing API allows at most this many token addresses per bulk scan request. */\nconst BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE = 100;\n\n/**\n * Default interval for re-scanning stored SPL (`token:`) assets with Blockaid.\n * Once per day limits API load while still catching tokens reclassified after add.\n */\nconst DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ntype ChainTokenEntry = { asset: CaipAssetType; address: string };\n\ntype BulkTokenScanBatchOutcome =\n | {\n status: 'fulfilled';\n response: BulkTokenScanResponse;\n entries: ChainTokenEntry[];\n }\n | { status: 'rejected'; entries: ChainTokenEntry[] };\n\nexport class MultichainAssetsController extends StaticIntervalPollingController<null>()<\n typeof controllerName,\n MultichainAssetsControllerState,\n MultichainAssetsControllerMessenger\n> {\n // Mapping of CAIP-2 Chain ID to Asset Snaps.\n #snaps: Record<CaipChainId, Snap[]>;\n\n readonly #controllerOperationMutex = new Mutex();\n\n constructor({\n messenger,\n state = {},\n blockaidTokenRescanInterval = DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS,\n }: {\n messenger: MultichainAssetsControllerMessenger;\n state?: Partial<MultichainAssetsControllerState>;\n /** Blockaid re-scan interval (ms); default daily. `0` disables. */\n blockaidTokenRescanInterval?: number;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: assetsControllerMetadata,\n state: {\n ...getDefaultMultichainAssetsControllerState(),\n ...state,\n },\n });\n\n this.#snaps = {};\n\n if (blockaidTokenRescanInterval > 0) {\n this.setIntervalLength(blockaidTokenRescanInterval);\n this.startPolling(null);\n }\n\n this.messenger.subscribe(\n 'AccountsController:accountAdded',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountAddedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountRemoved',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountRemovedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (event) => await this.#handleAccountAssetListUpdatedEvent(event),\n );\n this.messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (event) => {\n // eslint-disable-next-line no-void\n void this.#handleAccountBalancesUpdatedForEnrichment(event);\n },\n );\n\n // Bootstrap trust-line `extra` after unlock (and when already unlocked on first state event).\n let previousKeyringIsUnlocked: boolean | undefined;\n this.messenger.subscribe(\n 'KeyringController:stateChanged',\n (keyringState: KeyringControllerState) => {\n const { isUnlocked } = keyringState;\n if (previousKeyringIsUnlocked === undefined) {\n previousKeyringIsUnlocked = isUnlocked;\n if (isUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n return;\n }\n const justUnlocked = isUnlocked && !previousKeyringIsUnlocked;\n previousKeyringIsUnlocked = isUnlocked;\n if (justUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n async _executePoll(_input: null): Promise<void> {\n await this.#withControllerLock(async () => {\n const assetsByAccount: Record<\n string,\n { added: CaipAssetType[]; removed: CaipAssetType[] }\n > = {};\n\n for (const [accountId, assets] of Object.entries(\n this.state.accountsAssets,\n )) {\n const splTokens = assets.filter((asset) => {\n if (!isCaipAssetType(asset)) {\n return false;\n }\n try {\n return parseCaipAssetType(asset).assetNamespace === 'token';\n } catch {\n return false;\n }\n });\n\n if (splTokens.length === 0) {\n continue;\n }\n\n const malicious = await this.#findMaliciousTokensAmong(splTokens);\n if (malicious.length > 0) {\n this.ignoreAssets(malicious, accountId);\n assetsByAccount[accountId] = {\n added: [],\n removed: malicious,\n };\n }\n }\n\n if (Object.keys(assetsByAccount).length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: assetsByAccount,\n });\n }\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdatedEvent(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n return this.#withControllerLock(async () =>\n this.#handleAccountAssetListUpdated(event),\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleOnAccountAddedEvent(account: InternalAccount) {\n return this.#withControllerLock(async () =>\n this.#handleOnAccountAdded(account),\n );\n }\n\n /**\n * Returns the metadata for the given asset\n *\n * @param asset - The asset to get metadata for\n * @returns The metadata for the asset or undefined if not found.\n */\n getAssetMetadata(asset: CaipAssetType): FungibleAssetMetadata | undefined {\n return this.state.assetsMetadata[asset];\n }\n\n /**\n * Ignores a batch of assets for a specific account.\n *\n * @param assetsToIgnore - Array of asset IDs to ignore.\n * @param accountId - The account ID to ignore assets for.\n */\n ignoreAssets(assetsToIgnore: CaipAssetType[], accountId: string): void {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = state.accountsAssets[\n accountId\n ].filter((asset) => !assetsToIgnore.includes(asset));\n }\n\n if (!state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = [];\n }\n\n const newIgnoredAssets = assetsToIgnore.filter(\n (asset) => !state.allIgnoredAssets[accountId].includes(asset),\n );\n state.allIgnoredAssets[accountId].push(...newIgnoredAssets);\n });\n }\n\n /**\n * Adds multiple assets to the stored asset list for a specific account.\n * All assets must belong to the same chain.\n *\n * @param assetIds - Array of CAIP asset IDs to add (must be from same chain).\n * @param accountId - The account ID to add the assets to.\n * @returns The updated asset list for the account.\n * @throws Error if assets are from different chains.\n */\n async addAssets(\n assetIds: CaipAssetType[],\n accountId: string,\n ): Promise<CaipAssetType[]> {\n if (assetIds.length === 0) {\n return this.state.accountsAssets[accountId] || [];\n }\n\n // Validate that all assets are from the same chain\n const chainIds = new Set(\n assetIds.map((assetId) => parseCaipAssetType(assetId).chainId),\n );\n if (chainIds.size > 1) {\n throw new Error(\n `All assets must belong to the same chain. Found assets from chains: ${Array.from(chainIds).join(', ')}`,\n );\n }\n\n return this.#withControllerLock(async () => {\n // Refresh metadata for all assets\n await this.#refreshAssetsMetadata(assetIds);\n\n const addedAssets: CaipAssetType[] = [];\n\n this.update((state) => {\n // Initialize account assets if it doesn't exist\n if (!state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = [];\n }\n\n // Add assets if they don't already exist\n for (const assetId of assetIds) {\n if (!state.accountsAssets[accountId].includes(assetId)) {\n state.accountsAssets[accountId].push(assetId);\n addedAssets.push(assetId);\n }\n }\n\n // Remove from ignored list if they exist there (inline logic like EVM)\n if (state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = state.allIgnoredAssets[\n accountId\n ].filter((asset) => !assetIds.includes(asset));\n\n // Clean up empty arrays\n if (state.allIgnoredAssets[accountId].length === 0) {\n delete state.allIgnoredAssets[accountId];\n }\n }\n\n });\n\n // Publish event to notify other controllers (balances, rates) about the new assets\n if (addedAssets.length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [accountId]: {\n added: addedAssets,\n removed: [],\n },\n },\n });\n // Let MultichainBalancesController create balance rows before merging trust-line `extra`.\n await Promise.resolve();\n await this.#enrichStellarAccountAssetInfo(accountId, addedAssets);\n }\n\n return this.state.accountsAssets[accountId] || [];\n });\n }\n\n /**\n * Checks if an asset is ignored for a specific account.\n *\n * @param asset - The asset ID to check.\n * @param accountId - The account ID to check for.\n * @returns True if the asset is ignored, false otherwise.\n */\n #isAssetIgnored(asset: CaipAssetType, accountId: string): boolean {\n return this.state.allIgnoredAssets[accountId]?.includes(asset) ?? false;\n }\n\n /**\n * Function to update the assets list for an account\n *\n * @param event - The list of assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdated(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n this.#assertControllerMutexIsLocked();\n\n const assetsForMetadataRefresh = new Set<CaipAssetType>([]);\n const accountsAndAssetsToUpdate: AccountAssetListUpdatedEventPayload['assets'] =\n {};\n for (const [accountId, { added, removed }] of Object.entries(\n event.assets,\n )) {\n if (added.length > 0 || removed.length > 0) {\n const existing = this.state.accountsAssets[accountId] || [];\n\n // In case accountsAndAssetsToUpdate event is fired with \"added\" assets that already exist, we don't want to add them again\n // Also filter out ignored assets\n const preFilteredToBeAddedAssets = added.filter(\n (asset) =>\n !existing.includes(asset) &&\n isCaipAssetType(asset) &&\n !this.#isAssetIgnored(asset, accountId),\n );\n\n // Filter out tokens that cannot be verified or are flagged malicious\n const filteredToBeAddedAssets =\n await this.#filterBlockaidSpamTokensOnAdd(preFilteredToBeAddedAssets);\n\n // In case accountsAndAssetsToUpdate event is fired with \"removed\" assets that don't exist, we don't want to remove them\n const filteredToBeRemovedAssets = removed.filter(\n (asset) => existing.includes(asset) && isCaipAssetType(asset),\n );\n\n if (\n filteredToBeAddedAssets.length > 0 ||\n filteredToBeRemovedAssets.length > 0\n ) {\n accountsAndAssetsToUpdate[accountId] = {\n added: filteredToBeAddedAssets,\n removed: filteredToBeRemovedAssets,\n };\n }\n\n for (const asset of existing) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeAddedAssets) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeRemovedAssets) {\n assetsForMetadataRefresh.delete(asset);\n }\n }\n }\n\n this.update((state) => {\n for (const [accountId, { added, removed: removedAssets }] of Object.entries(\n accountsAndAssetsToUpdate,\n )) {\n const assets = new Set([\n ...(state.accountsAssets[accountId] || []),\n ...added,\n ]);\n for (const asset of removedAssets) {\n assets.delete(asset);\n }\n\n state.accountsAssets[accountId] = Array.from(assets);\n }\n });\n\n // Trigger fetching metadata for new assets\n await this.#refreshAssetsMetadata(Array.from(assetsForMetadataRefresh));\n\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: accountsAndAssetsToUpdate,\n });\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles changes when a new account has been added.\n *\n * @param account - The new account being added.\n */\n async #handleOnAccountAdded(account: InternalAccount): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n this.#assertControllerMutexIsLocked();\n\n // Get assets list\n if (account.metadata.snap) {\n const allAssets = await this.#getAssetsList(\n account.id,\n account.metadata.snap.id,\n );\n const caipAssets = allAssets.filter(isCaipAssetType);\n const filteredCaip =\n await this.#filterBlockaidSpamTokensOnAdd(caipAssets);\n const filteredCaipSet = new Set(filteredCaip);\n const assets = allAssets.filter(\n (asset) => !isCaipAssetType(asset) || filteredCaipSet.has(asset),\n );\n await this.#refreshAssetsMetadata(assets);\n this.update((state) => {\n state.accountsAssets[account.id] = assets;\n });\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [account.id]: {\n added: assets,\n removed: [],\n },\n },\n });\n\n await this.#enrichStellarAccountAssetInfo(account.id, filteredCaip);\n }\n }\n\n /**\n * After unlock, enrich trust-line `extra` for all Stellar classics already in the portfolio.\n */\n async #bootstrapStellarTrustlineExtras(): Promise<void> {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n for (const account of accounts) {\n if (!isStellarMultichainAccount(account)) {\n continue;\n }\n const classics = (this.state.accountsAssets[account.id] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length > 0) {\n await this.#enrichStellarAccountAssetInfo(account.id, classics);\n }\n }\n }\n\n /**\n * After snap balance events, fetch Stellar asset info (metadata + trust-line `extra`).\n *\n * @param payload - Keyring balance update payload.\n */\n async #handleAccountBalancesUpdatedForEnrichment(\n payload: AccountBalancesUpdatedEventPayload,\n ): Promise<void> {\n // Yield so MultichainBalancesController applies balance rows first (MAC inits before MBC in extension).\n await Promise.resolve();\n\n for (const accountId of Object.keys(payload.balances)) {\n const classics = (this.state.accountsAssets[accountId] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length === 0) {\n continue;\n }\n await this.#enrichStellarAccountAssetInfo(accountId, classics);\n }\n }\n\n /**\n * Fetches Stellar-only `keyring_getAccountAssetInfo` and merges metadata + balance `extra`.\n *\n * @param accountId - Account id.\n * @param assetIds - Assets to enrich.\n */\n async #enrichStellarAccountAssetInfo(\n accountId: string,\n assetIds: CaipAssetType[],\n ): Promise<void> {\n const stellarClassicIds = assetIds.filter(isStellarClassicAssetCaip19);\n if (stellarClassicIds.length === 0) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n const account = accounts.find((a) => a.id === accountId);\n if (!account || !isStellarMultichainAccount(account)) {\n return;\n }\n\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n return;\n }\n\n const info = await this.#getAccountAssetInfoFromSnap(\n accountId,\n snapId,\n stellarClassicIds,\n );\n if (!info) {\n return;\n }\n\n const metadataUpdates: Record<CaipAssetType, FungibleAssetMetadata> = {};\n const extrasByAsset: Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra | undefined\n > = {};\n\n for (const assetId of stellarClassicIds) {\n const entry = info[assetId];\n if (!entry) {\n // Snap omits assets with no on-chain row (portfolio import without trust line).\n extrasByAsset[assetId] = { limit: '0' };\n continue;\n }\n metadataUpdates[assetId] = entry.metadata;\n const balanceExtra = stellarAssetInfoExtraToBalanceExtra(entry.extra);\n if (balanceExtra === undefined) {\n // Snap omits extra when there is no on-chain trust line (portfolio import).\n extrasByAsset[assetId] = { limit: '0' };\n } else {\n extrasByAsset[assetId] = balanceExtra;\n }\n }\n\n if (Object.keys(metadataUpdates).length > 0) {\n this.update((state) => {\n state.assetsMetadata = {\n ...state.assetsMetadata,\n ...metadataUpdates,\n };\n });\n }\n\n if (Object.keys(extrasByAsset).length > 0) {\n this.messenger.call(\n 'MultichainBalancesController:mergeAccountBalanceExtras',\n accountId,\n extrasByAsset,\n );\n }\n }\n\n /**\n * Calls the Stellar snap `keyring_getAccountAssetInfo` handler.\n *\n * @param accountId - Account id.\n * @param snapId - Stellar wallet snap id.\n * @param assets - CAIP-19 assets to resolve.\n * @returns Per-asset metadata and optional trust-line extra, or undefined on failure.\n */\n async #getAccountAssetInfoFromSnap(\n accountId: string,\n snapId: string,\n assets: CaipAssetType[],\n ): Promise<StellarGetAccountAssetInfoResponse | undefined> {\n try {\n return (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request: {\n jsonrpc: '2.0',\n method: KEYRING_GET_ACCOUNT_ASSET_INFO_METHOD,\n params: {\n accountId,\n assets,\n },\n },\n })) as StellarGetAccountAssetInfoResponse;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The new account id being removed.\n */\n async #handleOnAccountRemovedEvent(accountId: string): Promise<void> {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n delete state.accountsAssets[accountId];\n }\n if (state.allIgnoredAssets[accountId]) {\n delete state.allIgnoredAssets[accountId];\n }\n // TODO: We are not deleting the assetsMetadata because we will soon make this controller extends StaticIntervalPollingController\n // and update all assetsMetadata once a day.\n });\n }\n\n /**\n * Refreshes the assets snaps and metadata for the given list of assets\n *\n * @param assets - The assets to refresh\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #refreshAssetsMetadata(assets: CaipAssetType[]) {\n this.#assertControllerMutexIsLocked();\n\n const assetsWithoutMetadata: CaipAssetType[] = assets.filter(\n (asset) => !this.state.assetsMetadata[asset],\n );\n\n // Call the snap to get the metadata\n if (assetsWithoutMetadata.length > 0) {\n // Check if for every asset in assetsWithoutMetadata there is a snap in snaps by chainId else call getAssetSnaps\n if (\n !assetsWithoutMetadata.every((asset: CaipAssetType) => {\n const { chainId } = parseCaipAssetType(asset);\n return Boolean(this.#getAssetSnapFor(chainId));\n })\n ) {\n this.#snaps = this.#getAssetSnaps();\n }\n await this.#updateAssetsMetadata(assetsWithoutMetadata);\n }\n }\n\n /**\n * Updates the assets metadata for the given list of assets\n *\n * @param assets - The assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #updateAssetsMetadata(assets: CaipAssetType[]) {\n // Creates a mapping of scope to their respective assets list.\n const assetsByScope: Record<CaipChainId, CaipAssetType[]> = {};\n for (const asset of assets) {\n const { chainId } = parseCaipAssetType(asset);\n if (!assetsByScope[chainId]) {\n assetsByScope[chainId] = [];\n }\n assetsByScope[chainId].push(asset);\n }\n\n let newMetadata: Record<CaipAssetType, FungibleAssetMetadata> = {};\n for (const chainId of Object.keys(assetsByScope) as CaipChainId[]) {\n const assetsForChain = assetsByScope[chainId];\n // Now fetch metadata from the associated asset Snaps:\n const snap = this.#getAssetSnapFor(chainId);\n if (snap) {\n const metadata = await this.#getAssetsMetadataFrom(\n assetsForChain,\n snap.id,\n );\n newMetadata = {\n ...newMetadata,\n ...(metadata?.assets ?? {}),\n };\n }\n }\n this.update((state) => {\n state.assetsMetadata = {\n ...this.state.assetsMetadata,\n ...newMetadata,\n };\n });\n }\n\n /**\n * Creates a mapping of CAIP-2 Chain ID to Asset Snaps.\n *\n * @returns A mapping of CAIP-2 Chain ID to Asset Snaps.\n */\n #getAssetSnaps(): Record<CaipChainId, Snap[]> {\n const snaps: Record<CaipChainId, Snap[]> = {};\n const allSnaps = this.#getAllSnaps();\n const allPermissions = allSnaps.map((snap) =>\n this.#getSnapsPermissions(snap.id),\n );\n\n for (const [index, permission] of allPermissions.entries()) {\n let scopes;\n for (const singlePermissionConstraint of Object.values(permission)) {\n scopes = getChainIdsCaveat(singlePermissionConstraint);\n if (!scopes) {\n continue;\n }\n for (const scope of scopes as CaipChainId[]) {\n if (!snaps[scope]) {\n snaps[scope] = [];\n }\n snaps[scope].push(allSnaps[index]);\n }\n }\n }\n return snaps;\n }\n\n /**\n * Returns the first asset snap for the given scope\n *\n * @param scope - The scope to get the asset snap for\n * @returns The asset snap for the given scope\n */\n #getAssetSnapFor(scope: CaipChainId): Snap | undefined {\n const allSnaps = this.#snaps[scope];\n // Pick only the first one, we ignore the other Snaps if there are multiple candidates for now.\n return allSnaps?.[0]; // Will be undefined if there's no Snaps candidate for this scope.\n }\n\n /**\n * Returns all the asset snaps\n *\n * @returns All the asset snaps\n */\n #getAllSnaps(): Snap[] {\n return this.messenger.call('SnapController:getRunnableSnaps');\n }\n\n /**\n * Returns the permissions for the given origin\n *\n * @param origin - The origin to get the permissions for\n * @returns The permissions for the given origin\n */\n #getSnapsPermissions(\n origin: string,\n ): SubjectPermissions<PermissionConstraint> {\n return this.messenger.call(\n 'PermissionController:getPermissions',\n origin,\n ) as SubjectPermissions<PermissionConstraint>;\n }\n\n /**\n * Returns the metadata for the given assets\n *\n * @param assets - The assets to get metadata for\n * @param snapId - The snap ID to get metadata from\n * @returns The metadata for the assets\n */\n async #getAssetsMetadataFrom(\n assets: CaipAssetType[],\n snapId: string,\n ): Promise<AssetMetadataResponse | undefined> {\n try {\n const response = (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetsLookup,\n request: {\n jsonrpc: '2.0',\n method: 'onAssetLookup',\n params: {\n assets,\n },\n },\n })) as AssetMetadataResponse;\n return response;\n } catch (error) {\n // Ignore\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Groups `token:` CAIP assets by chain namespace for bulk scan.\n *\n * @param assets - CAIP assets to inspect.\n * @returns Map of chain namespace to token entries.\n */\n #groupTokenAssetsByChain(\n assets: CaipAssetType[],\n ): Record<string, ChainTokenEntry[]> {\n const tokensByChain: Record<string, ChainTokenEntry[]> = {};\n\n for (const asset of assets) {\n const { assetNamespace, assetReference, chain } =\n parseCaipAssetType(asset);\n\n if (assetNamespace === 'token') {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n }\n\n return tokensByChain;\n }\n\n async #runBatchedBulkTokenScans(\n chainName: string,\n tokenEntries: ChainTokenEntry[],\n ): Promise<BulkTokenScanBatchOutcome[]> {\n const batches: ChainTokenEntry[][] = [];\n for (\n let i = 0;\n i < tokenEntries.length;\n i += BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE\n ) {\n batches.push(\n tokenEntries.slice(i, i + BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE),\n );\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.messenger.call('PhishingController:bulkScanTokens', {\n chainId: chainName,\n tokens: batch.map((entry) => entry.address),\n }),\n ),\n );\n\n return batches.map((entries, index) => {\n const result = batchResults[index];\n if (result.status === 'fulfilled') {\n return {\n status: 'fulfilled' as const,\n response: result.value,\n entries,\n };\n }\n return { status: 'rejected' as const, entries };\n });\n }\n\n /**\n * Fail-open Blockaid filter for newly detected `token:` assets (native/other namespaces unchanged).\n *\n * @param assets - CAIP assets to filter.\n * @returns Filtered list, original order preserved.\n */\n async #filterBlockaidSpamTokensOnAdd(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n if (Object.keys(tokensByChain).length === 0) {\n return [...assets];\n }\n\n const rejectedAssets = new Set<CaipAssetType>();\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n // Fail-open: if API fails, allow all tokens in this batch through\n continue;\n }\n for (const entry of outcome.entries) {\n const scanned = outcome.response[entry.address];\n // Reject only if we have a definitive malicious result\n if (\n scanned?.result_type &&\n scanned.result_type === TokenScanResultType.Malicious\n ) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * SPL `token:` assets in state that Blockaid marks malicious (failed batches skipped).\n *\n * @param assets - CAIP `token:` assets to scan.\n * @returns Subset marked malicious.\n */\n async #findMaliciousTokensAmong(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n const maliciousAssets: CaipAssetType[] = [];\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n continue;\n }\n for (const entry of outcome.entries) {\n if (\n outcome.response[entry.address]?.result_type ===\n TokenScanResultType.Malicious\n ) {\n maliciousAssets.push(entry.asset);\n }\n }\n }\n }\n\n return maliciousAssets;\n }\n\n /**\n * Get assets list for an account\n *\n * @param accountId - AccountId to get assets for\n * @param snapId - Snap ID for the account\n * @returns list of assets\n */\n async #getAssetsList(\n accountId: string,\n snapId: string,\n ): Promise<CaipAssetTypeOrId[]> {\n return await this.#getClient(snapId).listAccountAssets(accountId);\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n\n /**\n * Assert that the controller mutex is locked.\n *\n * @throws If the controller mutex is not locked.\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n #assertControllerMutexIsLocked() {\n if (!this.#controllerOperationMutex.isLocked()) {\n throw new Error(\n 'MultichainAssetsControllerError - Attempt to update state',\n );\n }\n }\n\n /**\n * Lock the controller mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * This wrapper ensures that each mutable operation that interacts with the\n * controller and that changes its state is executed in a mutually exclusive way,\n * preventing unsafe concurrent access that could lead to unpredictable behavior.\n *\n * @param callback - The function to execute while the controller mutex is locked.\n * @returns The result of the function.\n */\n async #withControllerLock<Result>(\n callback: MutuallyExclusiveCallback<Result>,\n ): Promise<Result> {\n return withLock(this.#controllerOperationMutex, callback);\n }\n}\n\n/**\n * Lock the given mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * @param mutex - The mutex to lock.\n * @param callback - The function to execute while the mutex is locked.\n * @returns The result of the function.\n */\nasync function withLock<Result>(\n mutex: Mutex,\n callback: MutuallyExclusiveCallback<Result>,\n): Promise<Result> {\n const releaseLock = await mutex.acquire();\n\n try {\n return await callback({ releaseLock });\n } finally {\n releaseLock();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainAssetsController.mjs","sourceRoot":"","sources":["../../src/MultichainAssetsController/MultichainAssetsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountAssetListUpdatedEvent,\n AccountsControllerAccountBalancesUpdatesEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n ControllerStateChangedEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n CaipAssetType,\n CaipAssetTypeOrId,\n} from '@metamask/keyring-api';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerState,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n GetPermissions,\n PermissionConstraint,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n} from '@metamask/snaps-controllers';\nimport type { FungibleAssetMetadata, Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { isCaipAssetType, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { MutexInterface } from 'async-mutex';\nimport { Mutex } from 'async-mutex';\n\nimport type { MultichainBalancesControllerMergeAccountBalanceExtrasAction } from '../MultichainBalancesController';\nimport type { MultichainAssetsControllerMethodActions } from './MultichainAssetsController-method-action-types';\nimport {\n STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,\n isStellarMultichainAccount,\n stellarAssetInfoExtraToBalanceExtra,\n} from '../multichain/stellarAccountAssetInfo';\nimport type {\n StellarAccountAssetInfoExtra,\n StellarGetAccountAssetInfoResponse,\n} from '../multichain/stellarAccountAssetInfo';\nimport { isStellarClassicAssetCaip19 } from '../multichain/stellarTrustline';\nimport { getChainIdsCaveat } from './utils';\n\nconst controllerName = 'MultichainAssetsController';\n\nexport type MultichainAssetsControllerState = {\n assetsMetadata: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n accountsAssets: { [account: string]: CaipAssetType[] };\n allIgnoredAssets: { [account: string]: CaipAssetType[] };\n};\n\n// Represents the response of the asset snap's onAssetLookup handler\nexport type AssetMetadataResponse = {\n assets: {\n [asset: CaipAssetType]: FungibleAssetMetadata;\n };\n};\n\nexport type MultichainAssetsControllerAccountAssetListUpdatedEvent = {\n type: `${typeof controllerName}:accountAssetListUpdated`;\n payload: AccountsControllerAccountAssetListUpdatedEvent['payload'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsController} state.\n */\nexport function getDefaultMultichainAssetsControllerState(): MultichainAssetsControllerState {\n return {\n accountsAssets: {},\n assetsMetadata: {},\n allIgnoredAssets: {},\n };\n}\n\n/**\n * Returns the state of the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsControllerState\n>;\n\n/**\n * Event emitted when the state of the {@link MultichainAssetsController} changes.\n */\nexport type MultichainAssetsControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerActions =\n | MultichainAssetsControllerGetStateAction\n | MultichainAssetsControllerMethodActions;\n\n/**\n * Events emitted by {@link MultichainAssetsController}.\n */\nexport type MultichainAssetsControllerEvents =\n | MultichainAssetsControllerStateChangeEvent\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n\n/**\n * A function executed within a mutually exclusive lock, with\n * a mutex releaser in its option bag.\n *\n * @param releaseLock - A function to release the lock.\n */\ntype MutuallyExclusiveCallback<Result> = ({\n releaseLock,\n}: {\n releaseLock: MutexInterface.Releaser;\n}) => Promise<Result>;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction\n | PhishingControllerBulkScanTokensAction\n | MultichainBalancesControllerMergeAccountBalanceExtrasAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountAssetListUpdatedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | ControllerStateChangedEvent<'KeyringController', KeyringControllerState>;\n\n/**\n * Messenger type for the MultichainAssetsController.\n */\nexport type MultichainAssetsControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsControllerActions | AllowedActions,\n MultichainAssetsControllerEvents | AllowedEvents\n>;\n\n/**\n * {@link MultichainAssetsController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nconst assetsControllerMetadata: StateMetadata<MultichainAssetsControllerState> =\n {\n assetsMetadata: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n accountsAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n allIgnoredAssets: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n };\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getAssetMetadata',\n 'ignoreAssets',\n 'addAssets',\n] as const;\n\n/** Phishing API allows at most this many token addresses per bulk scan request. */\nconst BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE = 100;\n\n/**\n * Default interval for re-scanning stored SPL (`token:`) assets with Blockaid.\n * Once per day limits API load while still catching tokens reclassified after add.\n */\nconst DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ntype ChainTokenEntry = { asset: CaipAssetType; address: string };\n\ntype BulkTokenScanBatchOutcome =\n | {\n status: 'fulfilled';\n response: BulkTokenScanResponse;\n entries: ChainTokenEntry[];\n }\n | { status: 'rejected'; entries: ChainTokenEntry[] };\n\nexport class MultichainAssetsController extends StaticIntervalPollingController<null>()<\n typeof controllerName,\n MultichainAssetsControllerState,\n MultichainAssetsControllerMessenger\n> {\n // Mapping of CAIP-2 Chain ID to Asset Snaps.\n #snaps: Record<CaipChainId, Snap[]>;\n\n readonly #controllerOperationMutex = new Mutex();\n\n constructor({\n messenger,\n state = {},\n blockaidTokenRescanInterval = DEFAULT_BLOCKAID_TOKEN_RESCAN_INTERVAL_MS,\n }: {\n messenger: MultichainAssetsControllerMessenger;\n state?: Partial<MultichainAssetsControllerState>;\n /** Blockaid re-scan interval (ms); default daily. `0` disables. */\n blockaidTokenRescanInterval?: number;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: assetsControllerMetadata,\n state: {\n ...getDefaultMultichainAssetsControllerState(),\n ...state,\n },\n });\n\n this.#snaps = {};\n\n if (blockaidTokenRescanInterval > 0) {\n this.setIntervalLength(blockaidTokenRescanInterval);\n this.startPolling(null);\n }\n\n this.messenger.subscribe(\n 'AccountsController:accountAdded',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountAddedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountRemoved',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (account) => await this.#handleOnAccountRemovedEvent(account),\n );\n this.messenger.subscribe(\n 'AccountsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (event) => await this.#handleAccountAssetListUpdatedEvent(event),\n );\n this.messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (event) => {\n // eslint-disable-next-line no-void\n void this.#handleAccountBalancesUpdatedForEnrichment(event);\n },\n );\n\n // Bootstrap trust-line `extra` after unlock (and when already unlocked on first state event).\n let previousKeyringIsUnlocked: boolean | undefined;\n this.messenger.subscribe(\n 'KeyringController:stateChanged',\n (keyringState: KeyringControllerState) => {\n const { isUnlocked } = keyringState;\n if (previousKeyringIsUnlocked === undefined) {\n previousKeyringIsUnlocked = isUnlocked;\n if (isUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n return;\n }\n const justUnlocked = isUnlocked && !previousKeyringIsUnlocked;\n previousKeyringIsUnlocked = isUnlocked;\n if (justUnlocked) {\n // eslint-disable-next-line no-void\n void this.#bootstrapStellarTrustlineExtras();\n }\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n async _executePoll(_input: null): Promise<void> {\n await this.#withControllerLock(async () => {\n const assetsByAccount: Record<\n string,\n { added: CaipAssetType[]; removed: CaipAssetType[] }\n > = {};\n\n for (const [accountId, assets] of Object.entries(\n this.state.accountsAssets,\n )) {\n const splTokens = assets.filter((asset) => {\n if (!isCaipAssetType(asset)) {\n return false;\n }\n try {\n return parseCaipAssetType(asset).assetNamespace === 'token';\n } catch {\n return false;\n }\n });\n\n if (splTokens.length === 0) {\n continue;\n }\n\n const malicious = await this.#findMaliciousTokensAmong(splTokens);\n if (malicious.length > 0) {\n this.ignoreAssets(malicious, accountId);\n assetsByAccount[accountId] = {\n added: [],\n removed: malicious,\n };\n }\n }\n\n if (Object.keys(assetsByAccount).length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: assetsByAccount,\n });\n }\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdatedEvent(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n return this.#withControllerLock(async () =>\n this.#handleAccountAssetListUpdated(event),\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleOnAccountAddedEvent(account: InternalAccount) {\n return this.#withControllerLock(async () =>\n this.#handleOnAccountAdded(account),\n );\n }\n\n /**\n * Returns the metadata for the given asset\n *\n * @param asset - The asset to get metadata for\n * @returns The metadata for the asset or undefined if not found.\n */\n getAssetMetadata(asset: CaipAssetType): FungibleAssetMetadata | undefined {\n return this.state.assetsMetadata[asset];\n }\n\n /**\n * Ignores a batch of assets for a specific account.\n *\n * @param assetsToIgnore - Array of asset IDs to ignore.\n * @param accountId - The account ID to ignore assets for.\n */\n ignoreAssets(assetsToIgnore: CaipAssetType[], accountId: string): void {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = state.accountsAssets[\n accountId\n ].filter((asset) => !assetsToIgnore.includes(asset));\n }\n\n if (!state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = [];\n }\n\n const newIgnoredAssets = assetsToIgnore.filter(\n (asset) => !state.allIgnoredAssets[accountId].includes(asset),\n );\n state.allIgnoredAssets[accountId].push(...newIgnoredAssets);\n });\n }\n\n /**\n * Adds multiple assets to the stored asset list for a specific account.\n * All assets must belong to the same chain.\n *\n * @param assetIds - Array of CAIP asset IDs to add (must be from same chain).\n * @param accountId - The account ID to add the assets to.\n * @returns The updated asset list for the account.\n * @throws Error if assets are from different chains.\n */\n async addAssets(\n assetIds: CaipAssetType[],\n accountId: string,\n ): Promise<CaipAssetType[]> {\n if (assetIds.length === 0) {\n return this.state.accountsAssets[accountId] || [];\n }\n\n // Validate that all assets are from the same chain\n const chainIds = new Set(\n assetIds.map((assetId) => parseCaipAssetType(assetId).chainId),\n );\n if (chainIds.size > 1) {\n throw new Error(\n `All assets must belong to the same chain. Found assets from chains: ${Array.from(chainIds).join(', ')}`,\n );\n }\n\n return this.#withControllerLock(async () => {\n // Refresh metadata for all assets\n await this.#refreshAssetsMetadata(assetIds);\n\n const addedAssets: CaipAssetType[] = [];\n\n this.update((state) => {\n // Initialize account assets if it doesn't exist\n if (!state.accountsAssets[accountId]) {\n state.accountsAssets[accountId] = [];\n }\n\n // Add assets if they don't already exist\n for (const assetId of assetIds) {\n if (!state.accountsAssets[accountId].includes(assetId)) {\n state.accountsAssets[accountId].push(assetId);\n addedAssets.push(assetId);\n }\n }\n\n // Remove from ignored list if they exist there (inline logic like EVM)\n if (state.allIgnoredAssets[accountId]) {\n state.allIgnoredAssets[accountId] = state.allIgnoredAssets[\n accountId\n ].filter((asset) => !assetIds.includes(asset));\n\n // Clean up empty arrays\n if (state.allIgnoredAssets[accountId].length === 0) {\n delete state.allIgnoredAssets[accountId];\n }\n }\n\n });\n\n // Publish event to notify other controllers (balances, rates) about the new assets\n if (addedAssets.length > 0) {\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [accountId]: {\n added: addedAssets,\n removed: [],\n },\n },\n });\n // Let MultichainBalancesController create balance rows before merging trust-line `extra`.\n await Promise.resolve();\n await this.#enrichStellarAccountAssetInfo(accountId, addedAssets);\n }\n\n return this.state.accountsAssets[accountId] || [];\n });\n }\n\n /**\n * Checks if an asset is ignored for a specific account.\n *\n * @param asset - The asset ID to check.\n * @param accountId - The account ID to check for.\n * @returns True if the asset is ignored, false otherwise.\n */\n #isAssetIgnored(asset: CaipAssetType, accountId: string): boolean {\n return this.state.allIgnoredAssets[accountId]?.includes(asset) ?? false;\n }\n\n /**\n * Function to update the assets list for an account\n *\n * @param event - The list of assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #handleAccountAssetListUpdated(\n event: AccountAssetListUpdatedEventPayload,\n ) {\n this.#assertControllerMutexIsLocked();\n\n const assetsForMetadataRefresh = new Set<CaipAssetType>([]);\n const accountsAndAssetsToUpdate: AccountAssetListUpdatedEventPayload['assets'] =\n {};\n for (const [accountId, { added, removed }] of Object.entries(\n event.assets,\n )) {\n if (added.length > 0 || removed.length > 0) {\n const existing = this.state.accountsAssets[accountId] || [];\n\n // In case accountsAndAssetsToUpdate event is fired with \"added\" assets that already exist, we don't want to add them again\n // Also filter out ignored assets\n const preFilteredToBeAddedAssets = added.filter(\n (asset) =>\n !existing.includes(asset) &&\n isCaipAssetType(asset) &&\n !this.#isAssetIgnored(asset, accountId),\n );\n\n // Filter out tokens that cannot be verified or are flagged malicious\n const filteredToBeAddedAssets =\n await this.#filterBlockaidSpamTokensOnAdd(preFilteredToBeAddedAssets);\n\n // In case accountsAndAssetsToUpdate event is fired with \"removed\" assets that don't exist, we don't want to remove them\n const filteredToBeRemovedAssets = removed.filter(\n (asset) => existing.includes(asset) && isCaipAssetType(asset),\n );\n\n if (\n filteredToBeAddedAssets.length > 0 ||\n filteredToBeRemovedAssets.length > 0\n ) {\n accountsAndAssetsToUpdate[accountId] = {\n added: filteredToBeAddedAssets,\n removed: filteredToBeRemovedAssets,\n };\n }\n\n for (const asset of existing) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeAddedAssets) {\n assetsForMetadataRefresh.add(asset);\n }\n for (const asset of filteredToBeRemovedAssets) {\n assetsForMetadataRefresh.delete(asset);\n }\n }\n }\n\n this.update((state) => {\n for (const [accountId, { added, removed: removedAssets }] of Object.entries(\n accountsAndAssetsToUpdate,\n )) {\n const assets = new Set([\n ...(state.accountsAssets[accountId] || []),\n ...added,\n ]);\n for (const asset of removedAssets) {\n assets.delete(asset);\n }\n\n state.accountsAssets[accountId] = Array.from(assets);\n }\n });\n\n // Trigger fetching metadata for new assets\n await this.#refreshAssetsMetadata(Array.from(assetsForMetadataRefresh));\n\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: accountsAndAssetsToUpdate,\n });\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles changes when a new account has been added.\n *\n * @param account - The new account being added.\n */\n async #handleOnAccountAdded(account: InternalAccount): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n this.#assertControllerMutexIsLocked();\n\n // Get assets list\n if (account.metadata.snap) {\n const allAssets = await this.#getAssetsList(\n account.id,\n account.metadata.snap.id,\n );\n const caipAssets = allAssets.filter(isCaipAssetType);\n const filteredCaip =\n await this.#filterBlockaidSpamTokensOnAdd(caipAssets);\n const filteredCaipSet = new Set(filteredCaip);\n const assets = allAssets.filter(\n (asset) => !isCaipAssetType(asset) || filteredCaipSet.has(asset),\n );\n await this.#refreshAssetsMetadata(assets);\n this.update((state) => {\n state.accountsAssets[account.id] = assets;\n });\n this.messenger.publish(`${controllerName}:accountAssetListUpdated`, {\n assets: {\n [account.id]: {\n added: assets,\n removed: [],\n },\n },\n });\n\n await this.#enrichStellarAccountAssetInfo(account.id, filteredCaip);\n }\n }\n\n /**\n * After unlock, enrich trust-line `extra` for all Stellar classics already in the portfolio.\n */\n async #bootstrapStellarTrustlineExtras(): Promise<void> {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n for (const account of accounts) {\n if (!isStellarMultichainAccount(account)) {\n continue;\n }\n const classics = (this.state.accountsAssets[account.id] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length > 0) {\n await this.#enrichStellarAccountAssetInfo(account.id, classics);\n }\n }\n }\n\n /**\n * After snap balance events, fetch Stellar trust-line `extra` via `getAccountAssetInfo`.\n *\n * @param payload - Keyring balance update payload.\n */\n async #handleAccountBalancesUpdatedForEnrichment(\n payload: AccountBalancesUpdatedEventPayload,\n ): Promise<void> {\n // Yield so MultichainBalancesController applies balance rows first (MAC inits before MBC in extension).\n await Promise.resolve();\n\n for (const accountId of Object.keys(payload.balances)) {\n const classics = (this.state.accountsAssets[accountId] ?? []).filter(\n isStellarClassicAssetCaip19,\n );\n if (classics.length === 0) {\n continue;\n }\n await this.#enrichStellarAccountAssetInfo(accountId, classics);\n }\n }\n\n /**\n * Fetches Stellar-only `getAccountAssetInfo` client request and merges trust-line `extra` into balances.\n *\n * @param accountId - Account id.\n * @param assetIds - Assets to enrich.\n */\n async #enrichStellarAccountAssetInfo(\n accountId: string,\n assetIds: CaipAssetType[],\n ): Promise<void> {\n const stellarClassicIds = assetIds.filter(isStellarClassicAssetCaip19);\n if (stellarClassicIds.length === 0) {\n return;\n }\n\n const accounts = this.messenger.call(\n 'AccountsController:listMultichainAccounts',\n );\n const account = accounts.find((a) => a.id === accountId);\n if (!account || !isStellarMultichainAccount(account)) {\n return;\n }\n\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n return;\n }\n\n const info = await this.#getAccountAssetInfoFromSnap(\n accountId,\n snapId,\n account.scopes[0] as CaipChainId,\n stellarClassicIds,\n );\n if (!info) {\n return;\n }\n\n const extrasByAsset: Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra | undefined\n > = {};\n\n for (const assetId of stellarClassicIds) {\n const snapExtra = info[assetId];\n if (snapExtra === undefined) {\n // Snap omits assets with no on-chain row (portfolio import without trust line).\n extrasByAsset[assetId] = { limit: '0' };\n continue;\n }\n const balanceExtra = stellarAssetInfoExtraToBalanceExtra(snapExtra);\n extrasByAsset[assetId] = balanceExtra ?? { limit: '0' };\n }\n\n if (Object.keys(extrasByAsset).length > 0) {\n this.messenger.call(\n 'MultichainBalancesController:mergeAccountBalanceExtras',\n accountId,\n extrasByAsset,\n );\n }\n }\n\n /**\n * Calls the Stellar snap `getAccountAssetInfo` client request handler.\n *\n * @param accountId - Account id.\n * @param snapId - Stellar wallet snap id.\n * @param scope - Stellar CAIP-2 chain id.\n * @param assets - CAIP-19 assets to resolve.\n * @returns Per-asset trust-line fields, or undefined on failure.\n */\n async #getAccountAssetInfoFromSnap(\n accountId: string,\n snapId: string,\n scope: CaipChainId,\n assets: CaipAssetType[],\n ): Promise<StellarGetAccountAssetInfoResponse | undefined> {\n try {\n return (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnClientRequest,\n request: {\n jsonrpc: '2.0',\n method: STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD,\n params: {\n accountId,\n scope,\n assets,\n },\n },\n })) as StellarGetAccountAssetInfoResponse;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The new account id being removed.\n */\n async #handleOnAccountRemovedEvent(accountId: string): Promise<void> {\n this.update((state) => {\n if (state.accountsAssets[accountId]) {\n delete state.accountsAssets[accountId];\n }\n if (state.allIgnoredAssets[accountId]) {\n delete state.allIgnoredAssets[accountId];\n }\n // TODO: We are not deleting the assetsMetadata because we will soon make this controller extends StaticIntervalPollingController\n // and update all assetsMetadata once a day.\n });\n }\n\n /**\n * Refreshes the assets snaps and metadata for the given list of assets\n *\n * @param assets - The assets to refresh\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #refreshAssetsMetadata(assets: CaipAssetType[]) {\n this.#assertControllerMutexIsLocked();\n\n const assetsWithoutMetadata: CaipAssetType[] = assets.filter(\n (asset) => !this.state.assetsMetadata[asset],\n );\n\n // Call the snap to get the metadata\n if (assetsWithoutMetadata.length > 0) {\n // Check if for every asset in assetsWithoutMetadata there is a snap in snaps by chainId else call getAssetSnaps\n if (\n !assetsWithoutMetadata.every((asset: CaipAssetType) => {\n const { chainId } = parseCaipAssetType(asset);\n return Boolean(this.#getAssetSnapFor(chainId));\n })\n ) {\n this.#snaps = this.#getAssetSnaps();\n }\n await this.#updateAssetsMetadata(assetsWithoutMetadata);\n }\n }\n\n /**\n * Updates the assets metadata for the given list of assets\n *\n * @param assets - The assets to update\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n async #updateAssetsMetadata(assets: CaipAssetType[]) {\n // Creates a mapping of scope to their respective assets list.\n const assetsByScope: Record<CaipChainId, CaipAssetType[]> = {};\n for (const asset of assets) {\n const { chainId } = parseCaipAssetType(asset);\n if (!assetsByScope[chainId]) {\n assetsByScope[chainId] = [];\n }\n assetsByScope[chainId].push(asset);\n }\n\n let newMetadata: Record<CaipAssetType, FungibleAssetMetadata> = {};\n for (const chainId of Object.keys(assetsByScope) as CaipChainId[]) {\n const assetsForChain = assetsByScope[chainId];\n // Now fetch metadata from the associated asset Snaps:\n const snap = this.#getAssetSnapFor(chainId);\n if (snap) {\n const metadata = await this.#getAssetsMetadataFrom(\n assetsForChain,\n snap.id,\n );\n newMetadata = {\n ...newMetadata,\n ...(metadata?.assets ?? {}),\n };\n }\n }\n this.update((state) => {\n state.assetsMetadata = {\n ...this.state.assetsMetadata,\n ...newMetadata,\n };\n });\n }\n\n /**\n * Creates a mapping of CAIP-2 Chain ID to Asset Snaps.\n *\n * @returns A mapping of CAIP-2 Chain ID to Asset Snaps.\n */\n #getAssetSnaps(): Record<CaipChainId, Snap[]> {\n const snaps: Record<CaipChainId, Snap[]> = {};\n const allSnaps = this.#getAllSnaps();\n const allPermissions = allSnaps.map((snap) =>\n this.#getSnapsPermissions(snap.id),\n );\n\n for (const [index, permission] of allPermissions.entries()) {\n let scopes;\n for (const singlePermissionConstraint of Object.values(permission)) {\n scopes = getChainIdsCaveat(singlePermissionConstraint);\n if (!scopes) {\n continue;\n }\n for (const scope of scopes as CaipChainId[]) {\n if (!snaps[scope]) {\n snaps[scope] = [];\n }\n snaps[scope].push(allSnaps[index]);\n }\n }\n }\n return snaps;\n }\n\n /**\n * Returns the first asset snap for the given scope\n *\n * @param scope - The scope to get the asset snap for\n * @returns The asset snap for the given scope\n */\n #getAssetSnapFor(scope: CaipChainId): Snap | undefined {\n const allSnaps = this.#snaps[scope];\n // Pick only the first one, we ignore the other Snaps if there are multiple candidates for now.\n return allSnaps?.[0]; // Will be undefined if there's no Snaps candidate for this scope.\n }\n\n /**\n * Returns all the asset snaps\n *\n * @returns All the asset snaps\n */\n #getAllSnaps(): Snap[] {\n return this.messenger.call('SnapController:getRunnableSnaps');\n }\n\n /**\n * Returns the permissions for the given origin\n *\n * @param origin - The origin to get the permissions for\n * @returns The permissions for the given origin\n */\n #getSnapsPermissions(\n origin: string,\n ): SubjectPermissions<PermissionConstraint> {\n return this.messenger.call(\n 'PermissionController:getPermissions',\n origin,\n ) as SubjectPermissions<PermissionConstraint>;\n }\n\n /**\n * Returns the metadata for the given assets\n *\n * @param assets - The assets to get metadata for\n * @param snapId - The snap ID to get metadata from\n * @returns The metadata for the assets\n */\n async #getAssetsMetadataFrom(\n assets: CaipAssetType[],\n snapId: string,\n ): Promise<AssetMetadataResponse | undefined> {\n try {\n const response = (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetsLookup,\n request: {\n jsonrpc: '2.0',\n method: 'onAssetLookup',\n params: {\n assets,\n },\n },\n })) as AssetMetadataResponse;\n return response;\n } catch (error) {\n // Ignore\n console.error(error);\n return undefined;\n }\n }\n\n /**\n * Groups `token:` CAIP assets by chain namespace for bulk scan.\n *\n * @param assets - CAIP assets to inspect.\n * @returns Map of chain namespace to token entries.\n */\n #groupTokenAssetsByChain(\n assets: CaipAssetType[],\n ): Record<string, ChainTokenEntry[]> {\n const tokensByChain: Record<string, ChainTokenEntry[]> = {};\n\n for (const asset of assets) {\n const { assetNamespace, assetReference, chain } =\n parseCaipAssetType(asset);\n\n if (assetNamespace === 'token') {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n }\n\n return tokensByChain;\n }\n\n async #runBatchedBulkTokenScans(\n chainName: string,\n tokenEntries: ChainTokenEntry[],\n ): Promise<BulkTokenScanBatchOutcome[]> {\n const batches: ChainTokenEntry[][] = [];\n for (\n let i = 0;\n i < tokenEntries.length;\n i += BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE\n ) {\n batches.push(\n tokenEntries.slice(i, i + BLOCKAID_BULK_TOKEN_SCAN_BATCH_SIZE),\n );\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.messenger.call('PhishingController:bulkScanTokens', {\n chainId: chainName,\n tokens: batch.map((entry) => entry.address),\n }),\n ),\n );\n\n return batches.map((entries, index) => {\n const result = batchResults[index];\n if (result.status === 'fulfilled') {\n return {\n status: 'fulfilled' as const,\n response: result.value,\n entries,\n };\n }\n return { status: 'rejected' as const, entries };\n });\n }\n\n /**\n * Fail-open Blockaid filter for newly detected `token:` assets (native/other namespaces unchanged).\n *\n * @param assets - CAIP assets to filter.\n * @returns Filtered list, original order preserved.\n */\n async #filterBlockaidSpamTokensOnAdd(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n if (Object.keys(tokensByChain).length === 0) {\n return [...assets];\n }\n\n const rejectedAssets = new Set<CaipAssetType>();\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n // Fail-open: if API fails, allow all tokens in this batch through\n continue;\n }\n for (const entry of outcome.entries) {\n const scanned = outcome.response[entry.address];\n // Reject only if we have a definitive malicious result\n if (\n scanned?.result_type &&\n scanned.result_type === TokenScanResultType.Malicious\n ) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * SPL `token:` assets in state that Blockaid marks malicious (failed batches skipped).\n *\n * @param assets - CAIP `token:` assets to scan.\n * @returns Subset marked malicious.\n */\n async #findMaliciousTokensAmong(\n assets: CaipAssetType[],\n ): Promise<CaipAssetType[]> {\n const tokensByChain = this.#groupTokenAssetsByChain(assets);\n\n const maliciousAssets: CaipAssetType[] = [];\n\n for (const [chainName, tokenEntries] of Object.entries(tokensByChain)) {\n const batchOutcomes = await this.#runBatchedBulkTokenScans(\n chainName,\n tokenEntries,\n );\n\n for (const outcome of batchOutcomes) {\n if (outcome.status === 'rejected') {\n continue;\n }\n for (const entry of outcome.entries) {\n if (\n outcome.response[entry.address]?.result_type ===\n TokenScanResultType.Malicious\n ) {\n maliciousAssets.push(entry.asset);\n }\n }\n }\n }\n\n return maliciousAssets;\n }\n\n /**\n * Get assets list for an account\n *\n * @param accountId - AccountId to get assets for\n * @param snapId - Snap ID for the account\n * @returns list of assets\n */\n async #getAssetsList(\n accountId: string,\n snapId: string,\n ): Promise<CaipAssetTypeOrId[]> {\n return await this.#getClient(snapId).listAccountAssets(accountId);\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messenger.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n\n /**\n * Assert that the controller mutex is locked.\n *\n * @throws If the controller mutex is not locked.\n */\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n #assertControllerMutexIsLocked() {\n if (!this.#controllerOperationMutex.isLocked()) {\n throw new Error(\n 'MultichainAssetsControllerError - Attempt to update state',\n );\n }\n }\n\n /**\n * Lock the controller mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * This wrapper ensures that each mutable operation that interacts with the\n * controller and that changes its state is executed in a mutually exclusive way,\n * preventing unsafe concurrent access that could lead to unpredictable behavior.\n *\n * @param callback - The function to execute while the controller mutex is locked.\n * @returns The result of the function.\n */\n async #withControllerLock<Result>(\n callback: MutuallyExclusiveCallback<Result>,\n ): Promise<Result> {\n return withLock(this.#controllerOperationMutex, callback);\n }\n}\n\n/**\n * Lock the given mutex before executing the given function,\n * and release it after the function is resolved or after an\n * error is thrown.\n *\n * @param mutex - The mutex to lock.\n * @param callback - The function to execute while the mutex is locked.\n * @returns The result of the function.\n */\nasync function withLock<Result>(\n mutex: Mutex,\n callback: MutuallyExclusiveCallback<Result>,\n): Promise<Result> {\n const releaseLock = await mutex.acquire();\n\n try {\n return await callback({ releaseLock });\n } finally {\n releaseLock();\n }\n}\n"]}
|
|
@@ -3,11 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isStellarClassicTrustlineInactiveForAsset = exports.isStellarTrustlineInactiveFromBalanceExtra = exports.stellarAssetInfoExtraToBalanceExtra = exports.isStellarMultichainAccount = exports.
|
|
6
|
+
exports.isStellarClassicTrustlineInactiveForAsset = exports.isStellarTrustlineInactiveFromBalanceExtra = exports.stellarAssetInfoExtraToBalanceExtra = exports.isStellarMultichainAccount = exports.STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD = void 0;
|
|
7
7
|
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
8
|
const stellarTrustline_1 = require("./stellarTrustline.cjs");
|
|
9
|
-
/** Stellar snap
|
|
10
|
-
exports.
|
|
9
|
+
/** Stellar snap clientRequest method for trust-line enrichment. */
|
|
10
|
+
exports.STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD = 'getAccountAssetInfo';
|
|
11
11
|
/**
|
|
12
12
|
* Returns true when the account is a Stellar snap-backed multichain account.
|
|
13
13
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stellarAccountAssetInfo.cjs","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"stellarAccountAssetInfo.cjs","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":";;;;;;AAEA,gEAAqC;AAErC,6DAAiE;AAEjE,mEAAmE;AACtD,QAAA,4CAA4C,GACvD,qBAA8B,CAAC;AAcjC;;;;GAIG;AACH,SAAgB,0BAA0B,CAAC,OAAwB;IACjE,OAAO,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC7C,CAAC;AAFD,gEAEC;AAED;;;;;GAKG;AACH,SAAgB,mCAAmC,CACjD,KAA+C;IAE/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAjBD,kFAiBC;AAED;;;;;GAKG;AACH,SAAgB,0CAA0C,CACxD,KAA+C;IAE/C,IAAI,KAAK,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,sBAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAfD,gGAeC;AAED;;;;;;;;GAQG;AACH,SAAgB,yCAAyC,CACvD,OAAsB,EACtB,YAAsD,EACtD,aAAa,GAAG,KAAK;IAErB,IAAI,CAAC,IAAA,8CAA2B,EAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,0CAA0C,CAAC,YAAY,CAAC,CAAC;AAClE,CAAC;AAfD,8FAeC","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAssetType } from '@metamask/utils';\nimport BigNumber from 'bignumber.js';\n\nimport { isStellarClassicAssetCaip19 } from './stellarTrustline';\n\n/** Stellar snap clientRequest method for trust-line enrichment. */\nexport const STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD =\n 'getAccountAssetInfo' as const;\n\n/** Optional balance fields for Stellar classic trust lines (unify-ready `extra`). */\nexport type StellarAccountAssetInfoExtra = {\n limit?: string;\n authorized?: boolean;\n sponsored?: boolean;\n};\n\nexport type StellarGetAccountAssetInfoResponse = Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra\n>;\n\n/**\n * Returns true when the account is a Stellar snap-backed multichain account.\n *\n * @param account - Internal account from AccountsController.\n */\nexport function isStellarMultichainAccount(account: InternalAccount): boolean {\n return account.type.startsWith('stellar:');\n}\n\n/**\n * Converts snap trust-line extra into JSON-safe balance `extra`.\n *\n * @param extra - Trust-line fields from the Stellar snap.\n * @returns Record suitable for MultichainBalancesController balance rows.\n */\nexport function stellarAssetInfoExtraToBalanceExtra(\n extra: StellarAccountAssetInfoExtra | undefined,\n): StellarAccountAssetInfoExtra | undefined {\n if (extra === undefined) {\n return undefined;\n }\n const result: StellarAccountAssetInfoExtra = {};\n if (extra.limit !== undefined) {\n result.limit = extra.limit;\n }\n if (extra.authorized !== undefined) {\n result.authorized = extra.authorized;\n }\n if (extra.sponsored !== undefined) {\n result.sponsored = extra.sponsored;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Whether a Stellar classic asset should show the “no trustline” state from balance `extra`.\n * Missing `extra` or zero/absent `limit` means inactive; active when `limit` > 0.\n *\n * @param extra - Balance `extra` from MultichainBalancesController.\n */\nexport function isStellarTrustlineInactiveFromBalanceExtra(\n extra: StellarAccountAssetInfoExtra | undefined,\n): boolean {\n if (extra?.limit === undefined) {\n return true;\n }\n const { limit } = extra;\n if (typeof limit !== 'string') {\n return true;\n }\n try {\n return new BigNumber(limit).lte(0);\n } catch {\n return true;\n }\n}\n\n/**\n * Whether a portfolio Stellar classic should be treated as trustline-inactive.\n * Uses balance `extra` when present. Portfolio import with no balance row is inactive.\n * A balance row without `extra` is treated as pending (not inactive) until enrich merges `extra`.\n *\n * @param assetId - CAIP-19 asset id.\n * @param balanceExtra - Optional `extra` on the balance row.\n * @param hasBalanceRow - Whether MultichainBalancesController has a row for this asset.\n */\nexport function isStellarClassicTrustlineInactiveForAsset(\n assetId: CaipAssetType,\n balanceExtra: StellarAccountAssetInfoExtra | undefined,\n hasBalanceRow = false,\n): boolean {\n if (!isStellarClassicAssetCaip19(assetId)) {\n return false;\n }\n if (!hasBalanceRow) {\n return true;\n }\n if (balanceExtra === undefined) {\n return false;\n }\n return isStellarTrustlineInactiveFromBalanceExtra(balanceExtra);\n}\n"]}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
2
|
-
import type { FungibleAssetMetadata } from "@metamask/snaps-sdk";
|
|
3
2
|
import type { CaipAssetType } from "@metamask/utils";
|
|
4
|
-
/** Stellar snap
|
|
5
|
-
export declare const
|
|
3
|
+
/** Stellar snap clientRequest method for trust-line enrichment. */
|
|
4
|
+
export declare const STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD: "getAccountAssetInfo";
|
|
6
5
|
/** Optional balance fields for Stellar classic trust lines (unify-ready `extra`). */
|
|
7
6
|
export type StellarAccountAssetInfoExtra = {
|
|
8
7
|
limit?: string;
|
|
9
8
|
authorized?: boolean;
|
|
10
9
|
sponsored?: boolean;
|
|
11
10
|
};
|
|
12
|
-
export type
|
|
13
|
-
metadata: FungibleAssetMetadata;
|
|
14
|
-
extra?: StellarAccountAssetInfoExtra;
|
|
15
|
-
};
|
|
16
|
-
export type StellarGetAccountAssetInfoResponse = Record<CaipAssetType, StellarAccountAssetInfoEntry>;
|
|
11
|
+
export type StellarGetAccountAssetInfoResponse = Record<CaipAssetType, StellarAccountAssetInfoExtra>;
|
|
17
12
|
/**
|
|
18
13
|
* Returns true when the account is a Stellar snap-backed multichain account.
|
|
19
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stellarAccountAssetInfo.d.cts","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"stellarAccountAssetInfo.d.cts","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAwB;AAKrD,mEAAmE;AACnE,eAAO,MAAM,4CAA4C,uBACzB,CAAC;AAEjC,qFAAqF;AACrF,MAAM,MAAM,4BAA4B,GAAG;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG,MAAM,CACrD,aAAa,EACb,4BAA4B,CAC7B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAE5E;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,4BAA4B,GAAG,SAAS,GAC9C,4BAA4B,GAAG,SAAS,CAe1C;AAED;;;;;GAKG;AACH,wBAAgB,0CAA0C,CACxD,KAAK,EAAE,4BAA4B,GAAG,SAAS,GAC9C,OAAO,CAaT;AAED;;;;;;;;GAQG;AACH,wBAAgB,yCAAyC,CACvD,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,4BAA4B,GAAG,SAAS,EACtD,aAAa,UAAQ,GACpB,OAAO,CAWT"}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
2
|
-
import type { FungibleAssetMetadata } from "@metamask/snaps-sdk";
|
|
3
2
|
import type { CaipAssetType } from "@metamask/utils";
|
|
4
|
-
/** Stellar snap
|
|
5
|
-
export declare const
|
|
3
|
+
/** Stellar snap clientRequest method for trust-line enrichment. */
|
|
4
|
+
export declare const STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD: "getAccountAssetInfo";
|
|
6
5
|
/** Optional balance fields for Stellar classic trust lines (unify-ready `extra`). */
|
|
7
6
|
export type StellarAccountAssetInfoExtra = {
|
|
8
7
|
limit?: string;
|
|
9
8
|
authorized?: boolean;
|
|
10
9
|
sponsored?: boolean;
|
|
11
10
|
};
|
|
12
|
-
export type
|
|
13
|
-
metadata: FungibleAssetMetadata;
|
|
14
|
-
extra?: StellarAccountAssetInfoExtra;
|
|
15
|
-
};
|
|
16
|
-
export type StellarGetAccountAssetInfoResponse = Record<CaipAssetType, StellarAccountAssetInfoEntry>;
|
|
11
|
+
export type StellarGetAccountAssetInfoResponse = Record<CaipAssetType, StellarAccountAssetInfoExtra>;
|
|
17
12
|
/**
|
|
18
13
|
* Returns true when the account is a Stellar snap-backed multichain account.
|
|
19
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stellarAccountAssetInfo.d.mts","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"stellarAccountAssetInfo.d.mts","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAwB;AAKrD,mEAAmE;AACnE,eAAO,MAAM,4CAA4C,uBACzB,CAAC;AAEjC,qFAAqF;AACrF,MAAM,MAAM,4BAA4B,GAAG;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG,MAAM,CACrD,aAAa,EACb,4BAA4B,CAC7B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAE5E;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,4BAA4B,GAAG,SAAS,GAC9C,4BAA4B,GAAG,SAAS,CAe1C;AAED;;;;;GAKG;AACH,wBAAgB,0CAA0C,CACxD,KAAK,EAAE,4BAA4B,GAAG,SAAS,GAC9C,OAAO,CAaT;AAED;;;;;;;;GAQG;AACH,wBAAgB,yCAAyC,CACvD,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,4BAA4B,GAAG,SAAS,EACtD,aAAa,UAAQ,GACpB,OAAO,CAWT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
2
|
import { isStellarClassicAssetCaip19 } from "./stellarTrustline.mjs";
|
|
3
|
-
/** Stellar snap
|
|
4
|
-
export const
|
|
3
|
+
/** Stellar snap clientRequest method for trust-line enrichment. */
|
|
4
|
+
export const STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD = 'getAccountAssetInfo';
|
|
5
5
|
/**
|
|
6
6
|
* Returns true when the account is a Stellar snap-backed multichain account.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stellarAccountAssetInfo.mjs","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stellarAccountAssetInfo.mjs","sourceRoot":"","sources":["../../src/multichain/stellarAccountAssetInfo.ts"],"names":[],"mappings":"AAEA,OAAO,SAAS,qBAAqB;AAErC,OAAO,EAAE,2BAA2B,EAAE,+BAA2B;AAEjE,mEAAmE;AACnE,MAAM,CAAC,MAAM,4CAA4C,GACvD,qBAA8B,CAAC;AAcjC;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAwB;IACjE,OAAO,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mCAAmC,CACjD,KAA+C;IAE/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0CAA0C,CACxD,KAA+C;IAE/C,IAAI,KAAK,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yCAAyC,CACvD,OAAsB,EACtB,YAAsD,EACtD,aAAa,GAAG,KAAK;IAErB,IAAI,CAAC,2BAA2B,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,0CAA0C,CAAC,YAAY,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAssetType } from '@metamask/utils';\nimport BigNumber from 'bignumber.js';\n\nimport { isStellarClassicAssetCaip19 } from './stellarTrustline';\n\n/** Stellar snap clientRequest method for trust-line enrichment. */\nexport const STELLAR_GET_ACCOUNT_ASSET_INFO_CLIENT_METHOD =\n 'getAccountAssetInfo' as const;\n\n/** Optional balance fields for Stellar classic trust lines (unify-ready `extra`). */\nexport type StellarAccountAssetInfoExtra = {\n limit?: string;\n authorized?: boolean;\n sponsored?: boolean;\n};\n\nexport type StellarGetAccountAssetInfoResponse = Record<\n CaipAssetType,\n StellarAccountAssetInfoExtra\n>;\n\n/**\n * Returns true when the account is a Stellar snap-backed multichain account.\n *\n * @param account - Internal account from AccountsController.\n */\nexport function isStellarMultichainAccount(account: InternalAccount): boolean {\n return account.type.startsWith('stellar:');\n}\n\n/**\n * Converts snap trust-line extra into JSON-safe balance `extra`.\n *\n * @param extra - Trust-line fields from the Stellar snap.\n * @returns Record suitable for MultichainBalancesController balance rows.\n */\nexport function stellarAssetInfoExtraToBalanceExtra(\n extra: StellarAccountAssetInfoExtra | undefined,\n): StellarAccountAssetInfoExtra | undefined {\n if (extra === undefined) {\n return undefined;\n }\n const result: StellarAccountAssetInfoExtra = {};\n if (extra.limit !== undefined) {\n result.limit = extra.limit;\n }\n if (extra.authorized !== undefined) {\n result.authorized = extra.authorized;\n }\n if (extra.sponsored !== undefined) {\n result.sponsored = extra.sponsored;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Whether a Stellar classic asset should show the “no trustline” state from balance `extra`.\n * Missing `extra` or zero/absent `limit` means inactive; active when `limit` > 0.\n *\n * @param extra - Balance `extra` from MultichainBalancesController.\n */\nexport function isStellarTrustlineInactiveFromBalanceExtra(\n extra: StellarAccountAssetInfoExtra | undefined,\n): boolean {\n if (extra?.limit === undefined) {\n return true;\n }\n const { limit } = extra;\n if (typeof limit !== 'string') {\n return true;\n }\n try {\n return new BigNumber(limit).lte(0);\n } catch {\n return true;\n }\n}\n\n/**\n * Whether a portfolio Stellar classic should be treated as trustline-inactive.\n * Uses balance `extra` when present. Portfolio import with no balance row is inactive.\n * A balance row without `extra` is treated as pending (not inactive) until enrich merges `extra`.\n *\n * @param assetId - CAIP-19 asset id.\n * @param balanceExtra - Optional `extra` on the balance row.\n * @param hasBalanceRow - Whether MultichainBalancesController has a row for this asset.\n */\nexport function isStellarClassicTrustlineInactiveForAsset(\n assetId: CaipAssetType,\n balanceExtra: StellarAccountAssetInfoExtra | undefined,\n hasBalanceRow = false,\n): boolean {\n if (!isStellarClassicAssetCaip19(assetId)) {\n return false;\n }\n if (!hasBalanceRow) {\n return true;\n }\n if (balanceExtra === undefined) {\n return false;\n }\n return isStellarTrustlineInactiveFromBalanceExtra(balanceExtra);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controllers",
|
|
3
|
-
"version": "106.0.0-preview-
|
|
3
|
+
"version": "106.0.0-preview-498809ee9",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|