@dynamic-labs-sdk/metamask 1.33.3 → 1.33.4
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/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.esm.js +1 -1
- package/dist/core.esm.js.map +1 -1
- package/dist/core.native.esm.js +1 -1
- package/dist/core.native.esm.js.map +1 -1
- package/dist/exports/core.d.ts.map +1 -1
- package/dist/exports/index.d.ts.map +1 -1
- package/dist/forceImportMetaMaskSubPackages/forceImportMetaMaskSubPackages.d.ts +20 -0
- package/dist/forceImportMetaMaskSubPackages/forceImportMetaMaskSubPackages.d.ts.map +1 -0
- package/dist/forceImportMetaMaskSubPackages/index.d.ts +2 -0
- package/dist/forceImportMetaMaskSubPackages/index.d.ts.map +1 -0
- package/dist/{getOrCreateMetaMaskClientInstanceManager-C_GnRbzN.cjs → getOrCreateMetaMaskClientInstanceManager-1l7pzxGD.cjs} +2 -2
- package/dist/{getOrCreateMetaMaskClientInstanceManager-C_GnRbzN.cjs.map → getOrCreateMetaMaskClientInstanceManager-1l7pzxGD.cjs.map} +1 -1
- package/dist/{getOrCreateMetaMaskClientInstanceManager-dcSj1V8L.esm.js → getOrCreateMetaMaskClientInstanceManager-BSRgLSNK.esm.js} +2 -2
- package/dist/{getOrCreateMetaMaskClientInstanceManager-dcSj1V8L.esm.js.map → getOrCreateMetaMaskClientInstanceManager-BSRgLSNK.esm.js.map} +1 -1
- package/dist/{getOrCreateMetaMaskClientInstanceManager-BgCk57FL.native.esm.js → getOrCreateMetaMaskClientInstanceManager-Cq9yO98U.native.esm.js} +5 -2
- package/dist/{getOrCreateMetaMaskClientInstanceManager-BgCk57FL.native.esm.js.map → getOrCreateMetaMaskClientInstanceManager-Cq9yO98U.native.esm.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.native.esm.js +1 -1
- package/dist/index.native.esm.js.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +6 -3
package/dist/core.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_getOrCreateMetaMaskClientInstanceManager = require('./getOrCreateMetaMaskClientInstanceManager-
|
|
1
|
+
const require_getOrCreateMetaMaskClientInstanceManager = require('./getOrCreateMetaMaskClientInstanceManager-1l7pzxGD.cjs');
|
|
2
2
|
let _dynamic_labs_sdk_assert_package_version = require("@dynamic-labs-sdk/assert-package-version");
|
|
3
3
|
let _dynamic_labs_sdk_client_core = require("@dynamic-labs-sdk/client/core");
|
|
4
4
|
let _dynamic_labs_sdk_client = require("@dynamic-labs-sdk/client");
|
package/dist/core.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.cjs","names":["getMetaMaskScopeForNetworkId","MetaMaskUnscopedNetworkError","handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void","getOrCreateMetaMaskClientInstanceManager","getMetaMaskScopes","clearMetaMaskStorage","WalletProviderPriority","UnsupportedMetaMaskChainError","SUPPORTED_METAMASK_CHAINS","getMetaMaskScopeForNetworkId","getMetaMaskScopes","name","version"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\n\nassertPackageVersion(name, version);\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.cjs","names":["getMetaMaskScopeForNetworkId","MetaMaskUnscopedNetworkError","handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void","getOrCreateMetaMaskClientInstanceManager","getMetaMaskScopes","clearMetaMaskStorage","WalletProviderPriority","UnsupportedMetaMaskChainError","SUPPORTED_METAMASK_CHAINS","getMetaMaskScopeForNetworkId","getMetaMaskScopes","name","version"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\nimport { forceImportMetaMaskSubPackages } from '../forceImportMetaMaskSubPackages';\n\nassertPackageVersion(name, version);\nforceImportMetaMaskSubPackages();\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
package/dist/core.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as UnsupportedMetaMaskChainError, c as name, i as getMetaMaskScopeForNetworkId, l as version, n as clearMetaMaskStorage, o as SUPPORTED_METAMASK_CHAINS, r as getMetaMaskScopes, s as MetaMaskUnscopedNetworkError, t as getOrCreateMetaMaskClientInstanceManager } from "./getOrCreateMetaMaskClientInstanceManager-
|
|
1
|
+
import { a as UnsupportedMetaMaskChainError, c as name, i as getMetaMaskScopeForNetworkId, l as version, n as clearMetaMaskStorage, o as SUPPORTED_METAMASK_CHAINS, r as getMetaMaskScopes, s as MetaMaskUnscopedNetworkError, t as getOrCreateMetaMaskClientInstanceManager } from "./getOrCreateMetaMaskClientInstanceManager-BSRgLSNK.esm.js";
|
|
2
2
|
import { assertPackageVersion } from "@dynamic-labs-sdk/assert-package-version";
|
|
3
3
|
import { WalletProviderPriority, createWalletProviderEventEmitter, getActiveNetworkIdFromLastKnownRegistry, getCore, getDefaultClient, getWalletProviderRegistry, switchActiveNetworkInLastKnownRegistry } from "@dynamic-labs-sdk/client/core";
|
|
4
4
|
import { getNetworksData, getWalletAccounts, onEvent } from "@dynamic-labs-sdk/client";
|
package/dist/core.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.esm.js","names":["handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\n\nassertPackageVersion(name, version);\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.esm.js","names":["handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\nimport { forceImportMetaMaskSubPackages } from '../forceImportMetaMaskSubPackages';\n\nassertPackageVersion(name, version);\nforceImportMetaMaskSubPackages();\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
package/dist/core.native.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as UnsupportedMetaMaskChainError, c as name, i as getMetaMaskScopeForNetworkId, l as version, n as clearMetaMaskStorage, o as SUPPORTED_METAMASK_CHAINS, r as getMetaMaskScopes, s as MetaMaskUnscopedNetworkError, t as getOrCreateMetaMaskClientInstanceManager } from "./getOrCreateMetaMaskClientInstanceManager-
|
|
1
|
+
import { a as UnsupportedMetaMaskChainError, c as name, i as getMetaMaskScopeForNetworkId, l as version, n as clearMetaMaskStorage, o as SUPPORTED_METAMASK_CHAINS, r as getMetaMaskScopes, s as MetaMaskUnscopedNetworkError, t as getOrCreateMetaMaskClientInstanceManager } from "./getOrCreateMetaMaskClientInstanceManager-Cq9yO98U.native.esm.js";
|
|
2
2
|
import { assertPackageVersion } from "@dynamic-labs-sdk/assert-package-version";
|
|
3
3
|
import { WalletProviderPriority, createWalletProviderEventEmitter, getActiveNetworkIdFromLastKnownRegistry, getCore, getDefaultClient, getWalletProviderRegistry, switchActiveNetworkInLastKnownRegistry } from "@dynamic-labs-sdk/client/core";
|
|
4
4
|
import { getNetworksData, getWalletAccounts, onEvent } from "@dynamic-labs-sdk/client";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.native.esm.js","names":["handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\n\nassertPackageVersion(name, version);\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.native.esm.js","names":["handleDisconnected: () => void","handleNetworkChanged: (params: { networkId: string }) => void"],"sources":["../src/getScopeAccountsFromMetaMaskClient/getScopeAccountsFromMetaMaskClient.ts","../src/assertMetaMaskNetworkIsGranted/assertMetaMaskNetworkIsGranted.ts","../src/createMetaMaskWalletProviderEventEmitter/createMetaMaskWalletProviderEventEmitter.ts","../src/disconnectMetaMaskWalletProvider/disconnectMetaMaskWalletProvider.ts","../src/reconcileMetaMaskWalletProvider/reconcileMetaMaskWalletProvider.ts","../src/getGrantedMetaMaskScopes/getGrantedMetaMaskScopes.ts","../src/getNetworkIdFromMetaMaskScope/getNetworkIdFromMetaMaskScope.ts","../src/resolveActiveMetaMaskScope/resolveActiveMetaMaskScope.ts","../src/exports/core.ts"],"sourcesContent":["import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeObject = SessionScopes[keyof SessionScopes];\ntype ScopeAccounts = NonNullable<ScopeObject['accounts']>;\n\nexport type GetScopeAccountsFromMetaMaskClientParams = {\n metaMaskClient: MultichainCore;\n scope: Parameters<MultichainCore['connect']>[0][number];\n};\n\n/**\n * Reads the accounts MetaMask granted for a single CAIP-2 scope out of the\n * current session, replacing direct `provider.getSession()` access so chain\n * packages never touch the raw session shape. Empty when there's no session\n * or the scope wasn't granted.\n *\n * @example\n * ```ts\n * const accounts = await getScopeAccountsFromMetaMaskClient(\n * { metaMaskClient, scope: 'eip155:1' },\n * client\n * );\n * // ['eip155:1:0x...']\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a missing/empty-scope result is always traceable to the client that\n * requested it.\n * @returns The accounts granted for `scope`, or an empty array if there's no\n * session or the scope wasn't granted.\n * @see createMetaMaskMultichainClient\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const getScopeAccountsFromMetaMaskClient = async (\n { metaMaskClient, scope }: GetScopeAccountsFromMetaMaskClientParams,\n client: DynamicClient\n): Promise<ScopeAccounts> => {\n const session = await metaMaskClient.provider.getSession();\n const accounts = session?.sessionScopes[scope]?.accounts ?? [];\n\n // Account addresses are PII -- log only the count, never the accounts themselves.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved scope accounts', {\n accountCount: accounts.length,\n hasSession: session != null,\n scope,\n });\n\n return accounts;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { MetaMaskUnscopedNetworkError } from '../errors/MetaMaskUnscopedNetworkError';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type AssertMetaMaskNetworkIsGrantedParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n networkId: string;\n};\n\n/**\n * Guards a MetaMask wallet provider's `switchActiveNetwork` against ever\n * pointing at a network MetaMask didn't actually grant an account for.\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask may silently approve only a subset --\n * switching the active network to one outside that subset would leave every\n * subsequent signing/sending call targeting a scope the wallet will reject.\n *\n * @example\n * ```ts\n * await assertMetaMaskNetworkIsGranted(\n * { chain: 'SOL', metaMaskClient, networkId: '103' },\n * client\n * );\n * // Throws MetaMaskUnscopedNetworkError if MetaMask never granted an\n * // account for network \"103\" in the current session.\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against.\n * @returns A promise that resolves once the target network is confirmed granted.\n * @throws {MetaMaskUnscopedNetworkError} If `networkId` has no granted\n * account in the current session (including when it has no configured\n * MetaMask scope at all).\n * @see resolveActiveMetaMaskScope\n * @see MetaMaskUnscopedNetworkError\n * @notInstrumented\n */\nexport const assertMetaMaskNetworkIsGranted = async (\n { chain, metaMaskClient, networkId }: AssertMetaMaskNetworkIsGrantedParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const scope = getMetaMaskScopeForNetworkId({ chain, networkId }, client);\n const accounts = scope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope },\n client\n )\n : [];\n\n logger.debug('[MetaMask:Scopes] Checked whether target network is granted', {\n accountCount: accounts.length,\n chain,\n networkId,\n scope,\n });\n\n if (accounts.length === 0) {\n logger.warn('[MetaMask:Scopes] Rejected switch to an unscoped network', {\n chain,\n networkId,\n scope,\n });\n\n throw new MetaMaskUnscopedNetworkError({\n networkId,\n scope: scope ?? 'unknown',\n });\n }\n};\n","import {\n type WalletProviderEventEmitter,\n createWalletProviderEventEmitter,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * The `WalletProviderEventEmitter` returned by\n * `createMetaMaskWalletProviderEventEmitter`, plus `emitNetworkChanged`/\n * `emitDisconnected` methods that MetaMask's EVM/Solana wallet providers call\n * directly from their own `switchActiveNetwork`/`disconnectWalletAccount` --\n * MetaMask's multichain session never fires a live wallet event either of\n * those could otherwise bridge from.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @see createMetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n */\nexport type MetaMaskWalletProviderEventEmitter = WalletProviderEventEmitter & {\n emitDisconnected: () => void;\n emitNetworkChanged: (params: { networkId: string }) => void;\n};\n\n/**\n * MetaMask's multichain session never triggers `createWalletProviderEventEmitter`'s\n * usual external-listener flow -- there is no live wallet event to bridge, only our\n * own local actions (e.g. `switchActiveNetwork`) that need to notify subscribers\n * themselves. `setupEventListeners` here just captures the handler references so\n * they can be invoked directly, instead of from a real event source.\n *\n * @example\n * ```ts\n * const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n * metaMaskEvents.getEventEmitter().on('networkChanged', ({ networkId }) => {});\n * metaMaskEvents.emitNetworkChanged({ networkId: '137' });\n * ```\n * @returns A `MetaMaskWalletProviderEventEmitter` ready to emit synthetic\n * `networkChanged`/`disconnected` events.\n * @see MetaMaskWalletProviderEventEmitter\n * @see createWalletProviderEventEmitter\n * @notInstrumented\n */\nexport const createMetaMaskWalletProviderEventEmitter =\n (): MetaMaskWalletProviderEventEmitter => {\n let handleDisconnected: () => void;\n let handleNetworkChanged: (params: { networkId: string }) => void;\n\n const emitter = createWalletProviderEventEmitter({\n removeEventListeners: () => {},\n setupEventListeners: (handlers) => {\n handleDisconnected = handlers.handleDisconnected;\n handleNetworkChanged = handlers.handleNetworkChanged;\n },\n // `accountsChanged` is excluded: nothing wires it yet -- MetaMask's real\n // `metamask_accountsChanged` event exists but isn't bridged here (future work).\n supportedEvents: ['disconnected', 'networkChanged'],\n });\n\n // Captures the handlers eagerly, since nothing external ever calls\n // getEventEmitter() first the way a real wallet-event bridge would.\n emitter.getEventEmitter();\n\n return {\n ...emitter,\n emitDisconnected: () => handleDisconnected(),\n emitNetworkChanged: (params) => handleNetworkChanged(params),\n };\n };\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getCore,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nimport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\n\n/**\n * Params for {@link disconnectMetaMaskWalletProvider}, identifying which\n * chain's scopes to drop from the shared MetaMask session and which\n * chain-specific wallet provider to unregister alongside it.\n *\n * @example\n * ```ts\n * const params: DisconnectMetaMaskWalletProviderParams = {\n * chain: 'EVM',\n * walletProviderKey: 'metamask-evm',\n * };\n * ```\n * @see disconnectMetaMaskWalletProvider\n * @see getMetaMaskScopes\n */\nexport type DisconnectMetaMaskWalletProviderParams = {\n /** Chain of the wallet account being disconnected; scopes this chain's own scopes out of the shared session. */\n chain: Chain;\n /** Key of the chain-specific wallet provider to unregister. */\n walletProviderKey: string;\n};\n\n/**\n * Shared `disconnectWalletAccount` for every chain's MetaMask wallet provider\n * (EVM, Solana, ...). `getOrCreateMetaMaskClientInstanceManager` hands every chain\n * the SAME client instance -- one multichain session shared across chains --\n * so this only asks MetaMask to drop this chain's own scopes rather than\n * tearing the whole session down under a still-connected chain.\n *\n * `disconnect`'s teardown in `@metamask/connect-multichain` is itself\n * scope-aware: it only actually ends the shared session once every chain's\n * scopes are gone, reflected by `metaMaskClient.status` flipping to\n * `'disconnected'`. Only then do we clear the persisted session and evict\n * the cached client, so a chain that's still connected is left untouched.\n *\n * @example\n * ```ts\n * await disconnectMetaMaskWalletProvider(\n * { chain: 'EVM', walletProviderKey: 'metamask-evm' },\n * client\n * );\n * ```\n * @param params.chain - Chain of the wallet account being disconnected.\n * @param params.walletProviderKey - Key of the chain-specific wallet provider to unregister.\n * @param client - The Dynamic client instance. Required (rather than\n * defaulting to the last-initialized client) since this always runs from\n * inside an already-resolved chain wallet provider, which already has one.\n * @returns A promise that resolves once local cleanup is done. Never rejects\n * on the remote signal failing -- that's logged, not surfaced, since the\n * wallet account is being removed either way.\n * @see clearMetaMaskStorage\n * @see getMetaMaskScopes\n * @notInstrumented\n */\nexport const disconnectMetaMaskWalletProvider = async (\n { chain, walletProviderKey }: DisconnectMetaMaskWalletProviderParams,\n client: DynamicClient\n): Promise<void> => {\n const { logger } = getCore(client);\n const metaMaskClient = await getOrCreateMetaMaskClientInstanceManager(\n client\n ).getMetaMaskClient();\n const scopes = getMetaMaskScopes({ chain }, client);\n\n logger.debug('[MetaMask:Disconnect] Disconnecting wallet account', {\n chain,\n scopes,\n walletProviderKey,\n });\n\n try {\n await metaMaskClient.disconnect(scopes);\n } catch (error) {\n logger.error('[MetaMask:Disconnect] Remote signal failed', {\n error,\n walletProviderKey,\n });\n }\n\n getWalletProviderRegistry(client).unregister(walletProviderKey);\n\n logger.debug('[MetaMask:Disconnect] Shared session status after disconnect', {\n status: metaMaskClient.status,\n walletProviderKey,\n });\n\n if (metaMaskClient.status === 'disconnected') {\n await clearMetaMaskStorage(client);\n }\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getWalletAccounts, onEvent } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\n\n/**\n * Params for {@link reconcileMetaMaskWalletProvider}.\n *\n * @example\n * ```ts\n * const params: ReconcileMetaMaskWalletProviderParams = {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * };\n * ```\n * @see reconcileMetaMaskWalletProvider\n * @see WalletProvider\n */\nexport type ReconcileMetaMaskWalletProviderParams = {\n /**\n * Builds the connect-less SDK placeholder wallet provider (e.g.\n * `createMetaMaskEvmWalletProvider`). Only invoked once reconciliation\n * determines the placeholder must actually be registered, so a chain\n * extension never builds it just for being added.\n */\n walletProviderBuilder: (client: DynamicClient) => WalletProvider;\n /**\n * The placeholder's deterministic wallet provider key, computed without\n * building it (e.g. `getMetaMaskEvmSdkWalletProviderKey`).\n */\n walletProviderKey: string;\n};\n\n/**\n * Keeps a chain's MetaMask SDK wallet provider registered for as\n * long as the user has a wallet account under its exact key, and\n * unregisters it once that wallet account disappears (e.g. on disconnect).\n * This is needed because always adding the MetaMask SDK wallet provider\n * would conflict with the browser extension wallet provider, so we only add\n * it once the user has a wallet account that was connected via QR code.\n * The placeholder is only built (via `walletProviderBuilder`) the first time\n * it must be registered, mirroring how WalletConnect only builds a wallet\n * provider for a session that actually exists.\n *\n * @example\n * ```ts\n * reconcileMetaMaskWalletProvider(\n * {\n * walletProviderBuilder: createMetaMaskEvmWalletProvider,\n * walletProviderKey: getMetaMaskEvmSdkWalletProviderKey(),\n * },\n * client\n * );\n * ```\n * @param params.walletProviderBuilder - Builds the SDK placeholder wallet provider once it must be registered.\n * @param params.walletProviderKey - The placeholder's deterministic wallet provider key.\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUri\n * @see WalletProviderPriority\n * @notInstrumented\n */\nexport const reconcileMetaMaskWalletProvider = (\n { walletProviderBuilder, walletProviderKey }: ReconcileMetaMaskWalletProviderParams,\n client: DynamicClient = getDefaultClient()\n): void => {\n const walletProviderRegistry = getWalletProviderRegistry(client);\n\n const reconcile = (): void => {\n const isSdkPlaceholderRegistered =\n walletProviderRegistry.getByKey(walletProviderKey) !== undefined;\n const shouldBeRegistered = getWalletAccounts(client).some(\n (walletAccount) => walletAccount.walletProviderKey === walletProviderKey\n );\n\n if (isSdkPlaceholderRegistered && !shouldBeRegistered) {\n walletProviderRegistry.unregister(walletProviderKey);\n return;\n }\n\n if (!isSdkPlaceholderRegistered && shouldBeRegistered) {\n walletProviderRegistry.register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider: walletProviderBuilder(client),\n });\n }\n };\n\n onEvent(\n { event: 'walletAccountsChanged', listener: () => reconcile() },\n client\n );\n\n reconcile();\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore } from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\ntype Session = Awaited<ReturnType<MultichainCore['provider']['getSession']>>;\ntype SessionScopes = NonNullable<Session>['sessionScopes'];\ntype ScopeKey = keyof SessionScopes;\ntype ScopeAccounts = NonNullable<SessionScopes[ScopeKey]['accounts']>;\n\nexport type GrantedMetaMaskScope = {\n accounts: ScopeAccounts;\n scope: ScopeKey;\n};\n\nexport type GetGrantedMetaMaskScopesParams = {\n metaMaskClient: MultichainCore;\n};\n\n/**\n * Enumerates every CAIP-2 scope in the current session that MetaMask\n * actually granted at least one account for. Every scope requested at\n * `connect()` time (see `getMetaMaskScopes`) is sent as an *optional*\n * CAIP-25 scope, never a required one, so MetaMask is free to approve only a\n * subset -- `session.sessionScopes` still has a key for every requested\n * scope, just with an empty `accounts` array for the ones that weren't\n * granted. This filters those out, replacing direct `provider.getSession()`\n * access so chain packages never touch the raw session shape.\n *\n * @example\n * ```ts\n * const granted = await getGrantedMetaMaskScopes({ metaMaskClient }, client);\n * // [{ scope: 'eip155:1', accounts: ['eip155:1:0x...'] }]\n * ```\n *\n * @param client - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so an empty result is always traceable to the client that requested it.\n * @returns The scopes with at least one granted account, and their accounts.\n * @see createMetaMaskMultichainClient\n * @see resolveActiveMetaMaskScope\n * @notInstrumented\n */\nexport const getGrantedMetaMaskScopes = async (\n { metaMaskClient }: GetGrantedMetaMaskScopesParams,\n client: DynamicClient\n): Promise<GrantedMetaMaskScope[]> => {\n const session = await metaMaskClient.provider.getSession();\n const sessionScopes = session?.sessionScopes ?? ({} as SessionScopes);\n\n const grantedScopes = (\n Object.entries(sessionScopes) as [ScopeKey, SessionScopes[ScopeKey]][]\n )\n .filter(([, scopeData]) => (scopeData.accounts ?? []).length > 0)\n .map(([scope, scopeData]) => ({\n accounts: scopeData.accounts ?? [],\n scope,\n }));\n\n // Granted scopes carry account addresses, which are PII -- log only counts.\n getCore(client).logger.debug('[MetaMask:Scopes] Resolved granted scopes', {\n grantedScopeCount: grantedScopes.length,\n hasSession: session != null,\n });\n\n return grantedScopes;\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\n\nimport { SUPPORTED_METAMASK_CHAINS } from '../constants';\nimport { UnsupportedMetaMaskChainError } from '../errors/UnsupportedMetaMaskChainError';\n\nexport type GetNetworkIdFromMetaMaskScopeParams = {\n chain: Chain;\n scope: string;\n};\n\n/**\n * Reverse of `getMetaMaskScopeForNetworkId`: maps a granted CAIP-2 scope\n * back to the Dynamic `networkId` it came from, for the given chain.\n *\n * Returns `undefined` -- not a throw -- when `scope` doesn't belong to\n * `chain` (e.g. an `eip155:` scope while scanning for `SOL`). For `SOL`,\n * this also covers a `solana:` scope matching no configured network. This\n * is the normal, expected outcome when scanning a session's granted scopes\n * for a single chain: a MetaMask multichain session is shared across every\n * connected chain\n *\n * @example\n * ```ts\n * const networkId = getNetworkIdFromMetaMaskScope(\n * { chain: 'EVM', scope: 'eip155:1' },\n * client\n * );\n * // '1'\n * ```\n *\n * @returns The matching Dynamic `networkId`, or `undefined` if `scope`\n * doesn't belong to `chain` (or, for `SOL`, matches no configured network).\n * @see getMetaMaskScopeForNetworkId\n * @see resolveActiveMetaMaskScope\n * @throws {UnsupportedMetaMaskChainError} If `chain` isn't a chain MetaMask\n * scopes can be built for.\n * @notInstrumented\n */\nexport const getNetworkIdFromMetaMaskScope = (\n { chain, scope }: GetNetworkIdFromMetaMaskScopeParams,\n client: DynamicClient\n): string | undefined => {\n const [namespace, reference] = scope.split(':');\n\n if (chain === 'EVM') {\n return namespace === 'eip155' ? reference : undefined;\n }\n\n if (chain === 'SOL') {\n if (namespace !== 'solana') {\n return undefined;\n }\n\n return getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.genesisHash === reference\n )?.networkId;\n }\n\n throw new UnsupportedMetaMaskChainError({\n chain,\n supportedChains: SUPPORTED_METAMASK_CHAINS,\n });\n};\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n getActiveNetworkIdFromLastKnownRegistry,\n getCore,\n getDefaultClient,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport type { MultichainCore } from '@metamask/connect-multichain';\n\nimport { getGrantedMetaMaskScopes } from '../getGrantedMetaMaskScopes';\nimport { getMetaMaskScopeForNetworkId } from '../getMetaMaskScopeForNetworkId';\nimport { getMetaMaskScopes } from '../getMetaMaskScopes';\nimport { getNetworkIdFromMetaMaskScope } from '../getNetworkIdFromMetaMaskScope';\nimport { getScopeAccountsFromMetaMaskClient } from '../getScopeAccountsFromMetaMaskClient';\n\nexport type ResolveActiveMetaMaskScopeParams = {\n chain: Chain;\n metaMaskClient: MultichainCore;\n walletProviderKey: string;\n};\n\n/**\n * The network resolved as active for a MetaMask wallet provider, and the\n * CAIP-10 accounts MetaMask granted for it -- returned by\n * `resolveActiveMetaMaskScope` so callers don't need to re-derive the scope\n * or re-read the session themselves.\n *\n * @example\n * ```ts\n * const { accounts, networkId } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * ```\n * @see resolveActiveMetaMaskScope\n * @see getGrantedMetaMaskScopes\n */\nexport type ResolveActiveMetaMaskScopeResult = {\n /** CAIP-10 account ids -- same shape as `metaMaskClient.getScopeAccounts` returns. */\n accounts: string[];\n networkId: string;\n scope: string | undefined;\n};\n\n/**\n * Resolves the network a MetaMask wallet provider should treat as active,\n * self-healing when the last-known-active network (see\n * `getActiveNetworkIdFromLastKnownRegistry`) turns out to have no granted\n * account.\n *\n * Every configured network is requested as an *optional* CAIP-25 scope (see\n * `getMetaMaskScopes`), so MetaMask is free to grant an account for only a\n * subset -- and the registry's own default (the first configured network for\n * the chain) has no awareness of which subset that was. If the active\n * network's scope is empty, this scans every OTHER scope this chain\n * requested, restricted to the ones MetaMask actually granted, and adopts\n * whichever is found (preferring a non-testnet network) as the new active\n * network -- persisting the correction so future calls don't repeat the\n * scan. If nothing was granted for this chain at all, the original\n * (accounts: []) result is returned unchanged, preserving the existing\n * \"no address found\" behavior when there's truly nothing to fall back to.\n *\n * @example\n * ```ts\n * const { accounts } = await resolveActiveMetaMaskScope(\n * { chain: 'SOL', metaMaskClient, walletProviderKey },\n * client\n * );\n * // accounts is non-empty even if the registry's default network wasn't\n * // the one MetaMask actually granted.\n * ```\n *\n * @param [client] - The Dynamic client instance whose logger this reports\n * against. Required (rather than defaulting to the last-initialized client)\n * so a fallback decision is always traceable to the client that requested it.\n * @returns The resolved active network's id, CAIP-2 scope, and granted accounts.\n * @see assertMetaMaskNetworkIsGranted\n * @see getGrantedMetaMaskScopes\n * @notInstrumented\n */\nexport const resolveActiveMetaMaskScope = async (\n {\n chain,\n metaMaskClient,\n walletProviderKey,\n }: ResolveActiveMetaMaskScopeParams,\n client: DynamicClient = getDefaultClient()\n): Promise<ResolveActiveMetaMaskScopeResult> => {\n const { logger } = getCore(client);\n\n const { networkId: activeNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n const activeScope = getMetaMaskScopeForNetworkId(\n { chain, networkId: activeNetworkId },\n client\n );\n const activeAccounts = activeScope\n ? await getScopeAccountsFromMetaMaskClient(\n { metaMaskClient, scope: activeScope },\n client\n )\n : [];\n\n if (activeAccounts.length > 0) {\n logger.debug(\n '[MetaMask:Scopes] Active network scope already has granted accounts',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Active network scope has no granted accounts, scanning other requested scopes for this chain',\n { activeNetworkId, chain, scope: activeScope }\n );\n\n const requestedScopes = new Set<string>(getMetaMaskScopes({ chain }, client));\n const grantedScopes = await getGrantedMetaMaskScopes(\n {\n metaMaskClient,\n },\n client\n );\n\n // Both the testnet flag and the fallback's deterministic order come from\n // Dynamic's own configured network list, never MetaMask's -- the granted\n // scopes returned by the SDK are keyed off its own session object, whose\n // enumeration order is an implementation detail, not something to rely on\n // when multiple candidates are equally eligible.\n const configuredNetworks = getNetworksData(client).filter(\n (network) => network.chain === chain\n );\n const testnetByNetworkId = new Map(\n configuredNetworks.map((network) => [network.networkId, network.testnet])\n );\n const configuredOrderByNetworkId = new Map(\n configuredNetworks.map((network, index) => [network.networkId, index])\n );\n\n const candidates = grantedScopes\n .filter(({ scope }) => requestedScopes.has(scope))\n .flatMap(({ accounts, scope }) => {\n const networkId = getNetworkIdFromMetaMaskScope({ chain, scope }, client);\n\n return networkId ? [{ accounts, networkId, scope }] : [];\n })\n .sort(\n (a, b) =>\n (configuredOrderByNetworkId.get(a.networkId) ?? 0) -\n (configuredOrderByNetworkId.get(b.networkId) ?? 0)\n );\n\n const fallback =\n candidates.find(({ networkId }) => !testnetByNetworkId.get(networkId)) ??\n candidates[0];\n\n if (fallback === undefined) {\n logger.debug(\n '[MetaMask:Scopes] No granted scope with accounts found for chain',\n { activeNetworkId, chain, requestedScopes: [...requestedScopes] }\n );\n\n return {\n accounts: activeAccounts,\n networkId: activeNetworkId,\n scope: activeScope,\n };\n }\n\n logger.debug(\n '[MetaMask:Scopes] Falling back to a granted scope after the active scope had no accounts',\n {\n activeNetworkId,\n activeScope,\n chain,\n fallbackNetworkId: fallback.networkId,\n fallbackScope: fallback.scope,\n }\n );\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId: fallback.networkId,\n walletProviderKey,\n });\n\n return {\n accounts: fallback.accounts,\n networkId: fallback.networkId,\n scope: fallback.scope,\n };\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\nimport { forceImportMetaMaskSubPackages } from '../forceImportMetaMaskSubPackages';\n\nassertPackageVersion(name, version);\nforceImportMetaMaskSubPackages();\n\n/**\n * @categoryDescription Extension Development\n * Core utilities and functions for building MetaMask SDK extensions.\n * These APIs provide low-level access to the SDK internals and are intended\n * for advanced use cases and extension development. Most applications should\n * use the higher-level APIs exported from the main SDK package instead.\n */\n\n/** @category Extension Development */\nexport { assertMetaMaskNetworkIsGranted } from '../assertMetaMaskNetworkIsGranted';\nexport { createMetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport type { MetaMaskWalletProviderEventEmitter } from '../createMetaMaskWalletProviderEventEmitter';\nexport { disconnectMetaMaskWalletProvider } from '../disconnectMetaMaskWalletProvider';\nexport type { DisconnectMetaMaskWalletProviderParams } from '../disconnectMetaMaskWalletProvider';\n/** @category Extension Development */\nexport { getOrCreateMetaMaskClientInstanceManager } from '../metaMaskClientInstanceManager/getOrCreateMetaMaskClientInstanceManager';\nexport { clearMetaMaskStorage } from '../metaMaskStorage/clearMetaMaskStorage';\nexport { reconcileMetaMaskWalletProvider } from '../reconcileMetaMaskWalletProvider';\nexport type { ReconcileMetaMaskWalletProviderParams } from '../reconcileMetaMaskWalletProvider';\nexport { resolveActiveMetaMaskScope } from '../resolveActiveMetaMaskScope';\nexport type { ResolveActiveMetaMaskScopeResult } from '../resolveActiveMetaMaskScope';\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/exports/core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/exports/core.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AAEH,sCAAsC;AACtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,wCAAwC,EAAE,MAAM,6CAA6C,CAAC;AACvG,YAAY,EAAE,kCAAkC,EAAE,MAAM,6CAA6C,CAAC;AACtG,OAAO,EAAE,gCAAgC,EAAE,MAAM,qCAAqC,CAAC;AACvF,YAAY,EAAE,sCAAsC,EAAE,MAAM,qCAAqC,CAAC;AAClG,sCAAsC;AACtC,OAAO,EAAE,wCAAwC,EAAE,MAAM,2EAA2E,CAAC;AACrI,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,+BAA+B,EAAE,MAAM,oCAAoC,CAAC;AACrF,YAAY,EAAE,qCAAqC,EAAE,MAAM,oCAAoC,CAAC;AAChG,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,YAAY,EAAE,gCAAgC,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,YAAY,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAC1F,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,qCAAqC,EAAE,MAAM,0CAA0C,CAAC;AACjG,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op on web.
|
|
3
|
+
*
|
|
4
|
+
* Only the React Native build needs to force-load
|
|
5
|
+
* `@metamask/connect-multichain`'s lazily `import()`-ed sub-packages -- web
|
|
6
|
+
* bundlers serve them on demand from the same origin, so there's no
|
|
7
|
+
* split-bundle-loader gap to work around.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* forceImportMetaMaskSubPackages();
|
|
12
|
+
* ```
|
|
13
|
+
* @returns Nothing. Present only so callers can invoke the same import path
|
|
14
|
+
* on every platform.
|
|
15
|
+
* @see createMetaMaskClientInstanceManager
|
|
16
|
+
* @see connectWithMetaMaskUri
|
|
17
|
+
* @notInstrumented
|
|
18
|
+
*/
|
|
19
|
+
export declare const forceImportMetaMaskSubPackages: () => void;
|
|
20
|
+
//# sourceMappingURL=forceImportMetaMaskSubPackages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forceImportMetaMaskSubPackages.d.ts","sourceRoot":"","sources":["../../src/forceImportMetaMaskSubPackages/forceImportMetaMaskSubPackages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,8BAA8B,QAAO,IAEjD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forceImportMetaMaskSubPackages/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC"}
|