@dynamic-labs-sdk/solana 1.31.0 → 1.31.2

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.
Files changed (87) hide show
  1. package/README.md +22 -0
  2. package/dist/{createWalletProviderFromSolanaStandardWallet-CpSgF7IN.esm.js → addSolanaWalletStandardExtension-CQAVpxFG.esm.js} +56 -4
  3. package/dist/addSolanaWalletStandardExtension-CQAVpxFG.esm.js.map +1 -0
  4. package/dist/{createWalletProviderFromSolanaStandardWallet-CCkxOmSK.cjs → addSolanaWalletStandardExtension-DTQS5msv.cjs} +56 -10
  5. package/dist/addSolanaWalletStandardExtension-DTQS5msv.cjs.map +1 -0
  6. package/dist/{addWaasSolanaExtension-DCOgxPMc.esm.js → addWaasSolanaExtension-CBNPkfTZ.esm.js} +2 -2
  7. package/dist/{addWaasSolanaExtension-DCOgxPMc.esm.js.map → addWaasSolanaExtension-CBNPkfTZ.esm.js.map} +1 -1
  8. package/dist/{addWaasSolanaExtension-CEDmaSAh.cjs → addWaasSolanaExtension-DwpmCWwW.cjs} +2 -2
  9. package/dist/{addWaasSolanaExtension-CEDmaSAh.cjs.map → addWaasSolanaExtension-DwpmCWwW.cjs.map} +1 -1
  10. package/dist/errors/MetaMaskDirectConnectNotSupportedError/MetaMaskDirectConnectNotSupportedError.d.ts +14 -0
  11. package/dist/errors/MetaMaskDirectConnectNotSupportedError/MetaMaskDirectConnectNotSupportedError.d.ts.map +1 -0
  12. package/dist/errors/MetaMaskDirectConnectNotSupportedError/index.d.ts +2 -0
  13. package/dist/errors/MetaMaskDirectConnectNotSupportedError/index.d.ts.map +1 -0
  14. package/dist/exports/metamask.d.ts +3 -0
  15. package/dist/exports/metamask.d.ts.map +1 -1
  16. package/dist/index.cjs +3 -4
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.esm.js +3 -4
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/metamask/addMetaMaskSolanaExtension/addMetaMaskSolanaExtension.d.ts +23 -0
  21. package/dist/metamask/addMetaMaskSolanaExtension/addMetaMaskSolanaExtension.d.ts.map +1 -0
  22. package/dist/metamask/addMetaMaskSolanaExtension/index.d.ts +2 -0
  23. package/dist/metamask/addMetaMaskSolanaExtension/index.d.ts.map +1 -0
  24. package/dist/metamask/connectWithMetaMaskUriSolana/connectWithMetaMaskUriSolana.d.ts.map +1 -1
  25. package/dist/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.d.ts +26 -6
  26. package/dist/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.d.ts.map +1 -1
  27. package/dist/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.d.ts +17 -0
  28. package/dist/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.d.ts.map +1 -0
  29. package/dist/metamask/getMetaMaskSolanaSdkWalletProviderKey/index.d.ts +2 -0
  30. package/dist/metamask/getMetaMaskSolanaSdkWalletProviderKey/index.d.ts.map +1 -0
  31. package/dist/metamask/registerMetaMaskSolanaUriConnectionStarter/index.d.ts +2 -0
  32. package/dist/metamask/registerMetaMaskSolanaUriConnectionStarter/index.d.ts.map +1 -0
  33. package/dist/metamask/registerMetaMaskSolanaUriConnectionStarter/registerMetaMaskSolanaUriConnectionStarter.d.ts +22 -0
  34. package/dist/metamask/registerMetaMaskSolanaUriConnectionStarter/registerMetaMaskSolanaUriConnectionStarter.d.ts.map +1 -0
  35. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/index.d.ts +2 -0
  36. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/index.d.ts.map +1 -0
  37. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.d.ts +18 -0
  38. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.d.ts.map +1 -0
  39. package/dist/metamask.cjs +289 -136
  40. package/dist/metamask.cjs.map +1 -1
  41. package/dist/metamask.esm.js +291 -141
  42. package/dist/metamask.esm.js.map +1 -1
  43. package/dist/{solanaTransferAmount-DFbb8Fnf.cjs → solanaTransferAmount-4hvpXzRi.cjs} +2 -2
  44. package/dist/{solanaTransferAmount-DFbb8Fnf.cjs.map → solanaTransferAmount-4hvpXzRi.cjs.map} +1 -1
  45. package/dist/{solanaTransferAmount-BmcJvD2x.esm.js → solanaTransferAmount-C-2Ct-ry.esm.js} +2 -2
  46. package/dist/{solanaTransferAmount-BmcJvD2x.esm.js.map → solanaTransferAmount-C-2Ct-ry.esm.js.map} +1 -1
  47. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  48. package/dist/waas.cjs +2 -2
  49. package/dist/waas.esm.js +2 -2
  50. package/dist/walletConnect/addWalletConnectSolanaExtension/addWalletConnectSolanaExtension.d.ts.map +1 -1
  51. package/dist/walletConnect/registerWalletConnectSolanaUriConnectionStarter/index.d.ts +2 -0
  52. package/dist/walletConnect/registerWalletConnectSolanaUriConnectionStarter/index.d.ts.map +1 -0
  53. package/dist/walletConnect/registerWalletConnectSolanaUriConnectionStarter/registerWalletConnectSolanaUriConnectionStarter.d.ts +19 -0
  54. package/dist/walletConnect/registerWalletConnectSolanaUriConnectionStarter/registerWalletConnectSolanaUriConnectionStarter.d.ts.map +1 -0
  55. package/dist/walletConnect.cjs +40 -13
  56. package/dist/walletConnect.cjs.map +1 -1
  57. package/dist/walletConnect.esm.js +41 -14
  58. package/dist/walletConnect.esm.js.map +1 -1
  59. package/dist/walletStandard.cjs +2 -3
  60. package/dist/walletStandard.cjs.map +1 -1
  61. package/dist/walletStandard.esm.js +2 -3
  62. package/dist/walletStandard.esm.js.map +1 -1
  63. package/package.json +5 -6
  64. package/dist/addSolanaWalletStandardExtension-BG3AkPK9.esm.js +0 -59
  65. package/dist/addSolanaWalletStandardExtension-BG3AkPK9.esm.js.map +0 -1
  66. package/dist/addSolanaWalletStandardExtension-C2xw3bYp.cjs +0 -65
  67. package/dist/addSolanaWalletStandardExtension-C2xw3bYp.cjs.map +0 -1
  68. package/dist/createWalletProviderFromSolanaStandardWallet-CCkxOmSK.cjs.map +0 -1
  69. package/dist/createWalletProviderFromSolanaStandardWallet-CpSgF7IN.esm.js.map +0 -1
  70. package/dist/metamask/metamask.types.d.ts +0 -14
  71. package/dist/metamask/metamask.types.d.ts.map +0 -1
  72. package/dist/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.d.ts +0 -20
  73. package/dist/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.d.ts.map +0 -1
  74. package/dist/metamask/utils/createMetaMaskSolanaController/index.d.ts +0 -2
  75. package/dist/metamask/utils/createMetaMaskSolanaController/index.d.ts.map +0 -1
  76. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.d.ts +0 -20
  77. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.d.ts.map +0 -1
  78. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/index.d.ts +0 -2
  79. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/index.d.ts.map +0 -1
  80. package/dist/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.d.ts +0 -18
  81. package/dist/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.d.ts.map +0 -1
  82. package/dist/metamask/utils/getSolanaNetworkFromCluster/index.d.ts +0 -3
  83. package/dist/metamask/utils/getSolanaNetworkFromCluster/index.d.ts.map +0 -1
  84. package/dist/metamask/utils/getSupportedNetworks/getSupportedNetworks.d.ts +0 -16
  85. package/dist/metamask/utils/getSupportedNetworks/getSupportedNetworks.d.ts.map +0 -1
  86. package/dist/metamask/utils/getSupportedNetworks/index.d.ts +0 -2
  87. package/dist/metamask/utils/getSupportedNetworks/index.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"metamask.cjs","names":["supportedNetworks: MetaMaskSupportedNetworks","latestDisplayUri: string | undefined","inFlightConnect: Promise<void> | null","getFeaturesForSolanaStandardWallet","MetaMaskWalletNotConnectedError","createWalletProviderFromSolanaStandardWallet","WalletProviderEnum","packageName","packageVersion"],"sources":["../src/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.ts","../src/metamask/utils/getSupportedNetworks/getSupportedNetworks.ts","../src/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.ts","../src/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.ts","../src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts","../src/metamask/connectWithMetaMaskUriSolana/connectWithMetaMaskUriSolana.ts","../src/metamask/connectAndVerifyWithMetaMaskUriSolana/connectAndVerifyWithMetaMaskUriSolana.ts","../src/metamask/getMetaMaskSolanaExtensionWalletProviderKey/getMetaMaskSolanaExtensionWalletProviderKey.ts","../src/exports/metamask.ts"],"sourcesContent":["import type { SolanaNetwork } from '@metamask/connect-solana';\n\n/** Parameters for {@link getSolanaNetworkFromCluster}. */\nexport type GetSolanaNetworkFromClusterParams = {\n /** The Dynamic network `cluster` (e.g. `mainnet-beta`, `devnet`, `testnet`). */\n cluster: string | undefined;\n};\n\n/**\n * Maps a Dynamic network `cluster` (e.g. `mainnet-beta`, `devnet`,\n * `testnet`) to the `mainnet | devnet | testnet` key shape expected by\n * `@metamask/connect-solana`'s `createSolanaClient`. Returns `undefined` for\n * clusters that do not correspond to one of MetaMask's supported Solana\n * networks so callers can skip them. Used by `getSupportedNetworks` to build\n * the SDK's `supportedNetworks` map.\n *\n * @notInstrumented\n */\nexport const getSolanaNetworkFromCluster = ({\n cluster,\n}: GetSolanaNetworkFromClusterParams): SolanaNetwork | undefined => {\n if (cluster === undefined) {\n return undefined;\n }\n\n if (cluster.includes('mainnet')) {\n return 'mainnet';\n }\n\n if (cluster.includes('devnet')) {\n return 'devnet';\n }\n\n if (cluster.includes('testnet')) {\n return 'testnet';\n }\n\n return undefined;\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport { assertNonEmptyArray } from '@dynamic-labs-sdk/client/core';\nimport type { SolanaNetwork } from '@metamask/connect-solana';\n\nimport { getSolanaNetworkFromCluster } from '../getSolanaNetworkFromCluster';\n\ntype MetaMaskSupportedNetworks = Partial<Record<SolanaNetwork, string>>;\n\n/**\n * Builds the `supportedNetworks` map required by\n * `@metamask/connect-solana`'s `createSolanaClient`, keyed by the SDK's\n * `mainnet | devnet | testnet` network names and valued with the first\n * configured RPC URL for each. Sources the configured SOL networks from the\n * Dynamic client's project settings. Throws when no SOL network is\n * configured, mirroring the EVM `getSupportedNetworks` contract.\n *\n * @notInstrumented\n */\nexport const getSupportedNetworks = (\n client: DynamicClient\n): MetaMaskSupportedNetworks => {\n const solanaNetworks = getNetworksData(client).filter(\n (network) => network.chain === 'SOL'\n );\n\n assertNonEmptyArray(\n solanaNetworks,\n 'No SOL networks have been configured. Make sure to add at least one Solana network to your project settings in the Dynamic Dashboard.'\n );\n\n const supportedNetworks: MetaMaskSupportedNetworks = {};\n\n for (const network of solanaNetworks) {\n const solanaNetwork = getSolanaNetworkFromCluster({\n cluster: network.cluster,\n });\n\n // Skip clusters MetaMask does not recognise, and keep the first RPC URL\n // seen for a given network so earlier-configured networks take priority.\n if (\n solanaNetwork !== undefined &&\n supportedNetworks[solanaNetwork] === undefined\n ) {\n supportedNetworks[solanaNetwork] = network.rpcUrls.http[0];\n }\n }\n\n return supportedNetworks;\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getAppMetadata,\n getCore,\n getNativeLinkScheme,\n} from '@dynamic-labs-sdk/client/core';\nimport { clearMetaMaskSessionStorage } from '@dynamic-labs-sdk/metamask';\nimport type { DisplayUriListener } from '@dynamic-labs-sdk/metamask';\nimport { createSolanaClient } from '@metamask/connect-solana';\n\nimport { getFeaturesForSolanaStandardWallet } from '../../../walletStandard/utils/getFeaturesForSolanaStandardWallet';\nimport type { MetaMaskSolanaController } from '../../metamask.types';\nimport { getSupportedNetworks } from '../getSupportedNetworks';\n\n/**\n * Builds a fully-initialised `MetaMaskSolanaController` for the given Dynamic\n * client. Drives the `@metamask/connect-solana` SDK through its Wallet\n * Standard surface so consumers render their own QR / deep-link UI, and\n * subscribes to the SDK core's `display_uri` event at construction time so\n * the first URI emission cannot be lost to a subscription race. The wallet\n * is created with `skipAutoRegister` so this URI-pairing client does not\n * register itself into the global Wallet Standard registry — an announced\n * MetaMask extension is discovered independently. Dapp metadata is sourced\n * from the client's `getAppMetadata`. Browser-only.\n * The MetaMask SDK's own verbose logging is tied to the Dynamic client's log\n * level, so turning on `debug` logging for the Dynamic SDK also surfaces\n * MetaMask's internal SDK trace output.\n *\n * @notInstrumented\n */\nexport const createMetaMaskSolanaController = async (\n client: DynamicClient\n): Promise<MetaMaskSolanaController> => {\n const supportedNetworks = getSupportedNetworks(client);\n const { appName, appLogoUrl, appUniversalLink, appNativeLink } =\n getAppMetadata(client);\n const { logger } = getCore(client);\n\n // Drop any IndexedDB session state left behind by a previous tab, page\n // reload, or abandoned pairing before the SDK initialises. The SDK's\n // auto-recovery path otherwise picks up a stale transport descriptor and\n // spends its (non-configurable) 10-second resume timeout on every\n // controller construction trying to revive a relay session that no longer\n // exists, surfacing as a long QR skeleton delay on every page reload that\n // follows an abandoned pairing.\n await clearMetaMaskSessionStorage(client);\n\n const listeners = new Set<DisplayUriListener>();\n let latestDisplayUri: string | undefined;\n\n const sdk = await createSolanaClient({\n api: { supportedNetworks },\n dapp: {\n iconUrl: appLogoUrl,\n name: appName,\n nativeScheme: getNativeLinkScheme({ nativeLink: appNativeLink }),\n url: appUniversalLink ?? '',\n },\n // Mirror the Dynamic client's own debug level, so a consumer who turns on\n // Dynamic SDK debug logging also gets MetaMask's internal SDK trace\n // output without a second, MetaMask-specific toggle to remember.\n debug: logger.isEnabled('debug'),\n skipAutoRegister: true,\n });\n\n sdk.core.on('display_uri', (uri) => {\n latestDisplayUri = uri;\n for (const listener of listeners) {\n listener(uri);\n }\n });\n\n // A terminal connection state means any cached URI is for a pairing that is\n // either complete or torn down, so it must not be replayed to late\n // subscribers.\n sdk.core.on('stateChanged', (status) => {\n if (status === 'connected' || status === 'disconnected') {\n latestDisplayUri = undefined;\n }\n });\n\n // Defensive cleanup: even though we cleared IndexedDB before constructing\n // the SDK, an in-flight `display_uri` emission could theoretically race the\n // storage delete on slow devices. Clearing the cache here guarantees late\n // subscribers cannot replay an URI that originated from any pairing attempt\n // prior to this construction.\n latestDisplayUri = undefined;\n\n const onDisplayUri = (listener: DisplayUriListener): (() => void) => {\n listeners.add(listener);\n if (latestDisplayUri !== undefined) {\n listener(latestDisplayUri);\n }\n return () => {\n listeners.delete(listener);\n };\n };\n\n // Tracks an in-flight `connect` call so that overlapping invocations (most\n // commonly React's StrictMode double-invocation of effects, or a hook that\n // re-runs while the user is still scanning) await the same underlying\n // pairing instead of racing two connect calls against each other.\n let inFlightConnect: Promise<void> | null = null;\n\n const connect = (): Promise<void> => {\n if (inFlightConnect) {\n return inFlightConnect;\n }\n\n inFlightConnect = (async () => {\n try {\n // If a previous pairing was cancelled mid-flight the SDK can be left\n // in `connecting` state with a dead transport descriptor; tear it\n // down so the next connect issues a fresh URI synchronously instead\n // of waiting for the SDK's (non-configurable) 10-second resume\n // timeout.\n if (sdk.core.status === 'connecting') {\n try {\n await sdk.disconnect();\n } catch (error) {\n getCore(client).logger.debug(\n '[metamask] pre-connect disconnect rejected (expected when aborting a pairing the wallet never accepted)',\n error\n );\n }\n }\n\n const features = getFeaturesForSolanaStandardWallet(sdk.getWallet());\n\n await features['standard:connect'].connect();\n } finally {\n inFlightConnect = null;\n }\n })();\n\n return inFlightConnect;\n };\n\n return {\n clearCachedDisplayUri: () => {\n latestDisplayUri = undefined;\n },\n connect,\n getLatestDisplayUri: () => latestDisplayUri,\n onDisplayUri,\n sdk,\n };\n};\n","import { createRuntimeServiceAccessKey } from '@dynamic-labs-sdk/client/core';\n\nimport { createMetaMaskSolanaController } from '../createMetaMaskSolanaController';\n\nconst RUNTIME_SERVICE_KEY = 'metaMaskSolanaController';\n\n/**\n * Per-`DynamicClient` accessor for the lazily-constructed MetaMask Solana\n * controller. Wraps `createMetaMaskSolanaController` with the standard\n * `runtimeServices` cache so every caller — the Wallet Standard\n * wallet-provider builder, the `display_uri` subscription helper, and the\n * `connectWithMetaMaskUriSolana` URI-returning helper — shares the same\n * controller (and therefore the same SDK instance, display-URI cache, and\n * listener registry) per Dynamic client.\n *\n * The cache is **per-Dynamic-client, not per-SDK-instance**:\n * `@metamask/connect-solana`'s `createSolanaClient` builds on the shared\n * MultichainCore singleton, so when multiple Dynamic clients coexist they\n * end up sharing the same MetaMask session regardless of this cache. The\n * wrapper exists to own the controller's `display_uri` cache and listener\n * registry per Dynamic client, which the SDK itself does not expose.\n *\n * @notInstrumented\n */\nexport const getOrCreateMetaMaskSolanaController = createRuntimeServiceAccessKey(\n RUNTIME_SERVICE_KEY,\n (client) => createMetaMaskSolanaController(client)\n);\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { MetaMaskWalletNotConnectedError } from '@dynamic-labs-sdk/metamask';\nimport { WalletProviderEnum } from '@dynamic-labs/sdk-api-core';\n\nimport type { SolanaWalletProvider } from '../../SolanaWalletProvider.types';\nimport { createWalletProviderFromSolanaStandardWallet } from '../../walletStandard/utils/createWalletProviderFromSolanaStandardWallet';\nimport { getOrCreateMetaMaskSolanaController } from '../utils/getOrCreateMetaMaskSolanaController';\n\n/**\n * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask\n * SDK URI pairing. Wraps the paired Wallet Standard wallet exposed by\n * `@metamask/connect-solana` behind the Dynamic Solana provider facade and\n * classifies it as `QrCode` so its key does not collide with an announced\n * MetaMask browser-extension provider for the same wallet name. Drops\n * `connect` so the provider is filtered out of the wallet picker by\n * `getAvailableWalletProvidersData` — mirroring how WalletConnect URI\n * sessions register a signing-only provider.\n *\n * @notInstrumented\n */\nexport const createMetaMaskSolanaWalletProvider = async (\n client: DynamicClient\n): Promise<SolanaWalletProvider> => {\n const controller = await getOrCreateMetaMaskSolanaController(client);\n\n const walletStandardWallet = controller.sdk.getWallet();\n\n // The provider is only meaningful once the URI pairing has produced a\n // connected account; guard so a premature or out-of-order call raises a\n // readable error instead of building a provider around an empty wallet.\n if (walletStandardWallet.accounts.length === 0) {\n throw new MetaMaskWalletNotConnectedError();\n }\n\n const walletProvider = createWalletProviderFromSolanaStandardWallet({\n dynamicClient: client,\n walletProviderType: WalletProviderEnum.QrCode,\n walletStandardWallet,\n });\n\n return {\n ...walletProvider,\n connect: undefined,\n };\n};\n","import { getDefaultClient } from '@dynamic-labs-sdk/client';\nimport type { WalletProviderUriConnectionResult } from '@dynamic-labs-sdk/client';\nimport { connectWithMetaMaskUri } from '@dynamic-labs-sdk/metamask';\n\nimport { registerSolanaNetworkProviderBuilder } from '../../registerSolanaNetworkProviderBuilder';\nimport { createMetaMaskSolanaWalletProvider } from '../createMetaMaskSolanaWalletProvider';\nimport { getOrCreateMetaMaskSolanaController } from '../utils/getOrCreateMetaMaskSolanaController';\n\nexport type ConnectWithMetaMaskUriSolanaParams = {\n /** Whether to add the connected wallet account to the Dynamic client. Defaults to `true`. */\n addToDynamicWalletAccounts?: boolean;\n};\n\n/**\n * Drives a MetaMask SDK URI pairing for Solana and returns `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink. The resulting\n * wallet provider registers for signing only and is never surfaced in the\n * wallet picker. When the MetaMask extension is announced via Wallet Standard,\n * prefer routing through `getMetaMaskSolanaExtensionWalletProviderKey` instead.\n *\n * @notInstrumented\n */\nexport const connectWithMetaMaskUriSolana = (\n { addToDynamicWalletAccounts = true }: ConnectWithMetaMaskUriSolanaParams = {},\n client = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n registerSolanaNetworkProviderBuilder(client);\n\n return connectWithMetaMaskUri(\n {\n addToDynamicWalletAccounts,\n chain: 'SOL',\n getController: getOrCreateMetaMaskSolanaController,\n walletProviderBuilder: createMetaMaskSolanaWalletProvider,\n },\n client\n );\n};\n","import {\n type WalletAccount,\n type WalletProviderUriConnectionResult,\n getDefaultClient,\n verifyWalletAccount,\n} from '@dynamic-labs-sdk/client';\n\nimport { connectWithMetaMaskUriSolana } from '../connectWithMetaMaskUriSolana';\n\n/**\n * Drives a MetaMask SDK URI pairing for Solana and verifies ownership of the\n * paired wallet account through message signing, returning `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink.\n *\n * Builds on `connectWithMetaMaskUriSolana` (rather than the chain-agnostic\n * connector directly) so the Solana-specific wiring stays defined in one\n * place, then wraps its `approval` to add the verification round-trip. The\n * pairing is driven with `addToDynamicWalletAccounts: false` so the account\n * lands as a verified credential instead of an unverified entry.\n *\n * The MetaMask SDK does not expose a single-round-trip authenticate\n * primitive, so this drives two sequential interactions on the wallet side:\n * the user first approves the pairing, then approves a sign-in message.\n *\n * @notInstrumented\n */\nexport const connectAndVerifyWithMetaMaskUriSolana = async (\n client = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n const { approval, uri } = await connectWithMetaMaskUriSolana(\n { addToDynamicWalletAccounts: false },\n client\n );\n\n const verifiedApproval = async (): Promise<{\n walletAccounts: WalletAccount[];\n }> => {\n const { walletAccounts } = await approval();\n\n // MetaMask SDK exposes a single active address per pairing, mirroring how\n // the underlying connect helper materializes a single account from\n // `addresses[0]`. Verify it directly.\n const [walletAccount] = walletAccounts;\n\n if (walletAccount) {\n await verifyWalletAccount({ walletAccount }, client);\n }\n\n return { walletAccounts };\n };\n\n return { approval: verifiedApproval, uri };\n};\n","import { getDefaultClient } from '@dynamic-labs-sdk/client';\nimport { getMetaMaskExtensionWalletProviderKey } from '@dynamic-labs-sdk/metamask';\n\n/**\n * Returns the wallet provider key of the MetaMask browser extension announced\n * for Solana via Wallet Standard, or `undefined` when none is announced. Pass\n * the returned key to `connectWithWalletProvider` to route through the\n * announced provider; fall back to `connectWithMetaMaskUriSolana` when\n * `undefined`.\n *\n * @notInstrumented\n */\nexport const getMetaMaskSolanaExtensionWalletProviderKey = (\n client = getDefaultClient()\n): string | undefined =>\n getMetaMaskExtensionWalletProviderKey({ chain: 'SOL' }, client);\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport {\n name as packageName,\n version as packageVersion,\n} from '../../package.json';\nassertPackageVersion(packageName, packageVersion);\n\nexport { connectAndVerifyWithMetaMaskUriSolana } from '../metamask/connectAndVerifyWithMetaMaskUriSolana';\nexport { connectWithMetaMaskUriSolana } from '../metamask/connectWithMetaMaskUriSolana';\nexport type { ConnectWithMetaMaskUriSolanaParams } from '../metamask/connectWithMetaMaskUriSolana/connectWithMetaMaskUriSolana';\nexport { getMetaMaskSolanaExtensionWalletProviderKey } from '../metamask/getMetaMaskSolanaExtensionWalletProviderKey';\nexport { MetaMaskDisplayUriMissingError } from '@dynamic-labs-sdk/metamask';\n"],"mappings":"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"}
1
+ {"version":3,"file":"metamask.cjs","names":["BaseError","WalletProviderEnum","DYNAMIC_ICONIC_SPRITE_URL","isVersionedTransaction","VersionedTransaction","Transaction","getConnectedAddresses: SolanaWalletProvider['getConnectedAddresses']","getActiveNetworkId: SolanaWalletProvider['getActiveNetworkId']","switchActiveNetwork: SolanaWalletProvider['switchActiveNetwork']","signMessage: NonNullable<SolanaWalletProvider['signMessage']>","signTransaction: SolanaWalletProvider['signTransaction']","signAllTransactions: SolanaWalletProvider['signAllTransactions']","signedTransactions: T[]","signAndSendTransaction: SolanaWalletProvider['signAndSendTransaction']","disconnectWalletAccount: SolanaWalletProvider['disconnectWalletAccount']","destroy: SolanaWalletProvider['destroy']","solanaConfirmTransaction","solanaExecuteSwapTransaction","solanaTransferAmount","WalletProviderEnum","packageName","packageVersion"],"sources":["../src/errors/MetaMaskDirectConnectNotSupportedError/MetaMaskDirectConnectNotSupportedError.ts","../src/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.ts","../src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts","../src/metamask/addMetaMaskSolanaExtension/addMetaMaskSolanaExtension.ts","../src/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.ts","../src/metamask/connectWithMetaMaskUriSolana/connectWithMetaMaskUriSolana.ts","../src/metamask/connectAndVerifyWithMetaMaskUriSolana/connectAndVerifyWithMetaMaskUriSolana.ts","../src/metamask/getMetaMaskSolanaExtensionWalletProviderKey/getMetaMaskSolanaExtensionWalletProviderKey.ts","../src/metamask/registerMetaMaskSolanaUriConnectionStarter/registerMetaMaskSolanaUriConnectionStarter.ts","../src/exports/metamask.ts"],"sourcesContent":["import { BaseError } from '@dynamic-labs-sdk/client';\n\n/**\n * Thrown when `connect()` is called directly on the MetaMask SDK placeholder\n * wallet provider (the entry `addMetaMaskSolanaExtension` registers so\n * MetaMask still shows up in the wallet picker when no browser extension is\n * installed). That placeholder has no generic connect flow of its own --\n * connecting requires the QR / deeplink pairing flow, so callers must drive\n * `connectWithMetaMaskUriSolana` (or `connectAndVerifyWithMetaMaskUriSolana`)\n * instead of the picker's default connect.\n */\nexport class MetaMaskDirectConnectNotSupportedError extends BaseError {\n constructor() {\n super({\n cause: null,\n code: 'metamask_direct_connect_not_supported',\n docsUrl: null,\n name: 'MetaMaskDirectConnectNotSupportedError',\n shortMessage:\n 'MetaMask cannot be connected directly; call connectWithMetaMaskUriSolana (or connectAndVerifyWithMetaMaskUriSolana) to get a QR/URI pairing flow instead',\n });\n }\n}\n","import { formatWalletProviderKey } from '@dynamic-labs-sdk/client/core';\nimport { WalletProviderEnum } from '@dynamic-labs/sdk-api-core';\n\n// Kept in sync with `createMetaMaskSolanaWalletProvider`'s own copy of this\n// display name -- both derive the same deterministic key, and duplicating\n// the string here is simpler than threading a shared constant through an\n// aggregating export.\nconst METAMASK_SOLANA_SDK_DISPLAY_NAME = 'MetaMask';\n\n/**\n * Deterministic wallet provider key for the MetaMask SDK's connect-less\n * Solana placeholder. Computed without building the wallet provider itself,\n * so `addMetaMaskSolanaExtension` can check for a matching wallet account\n * before paying the cost of `createMetaMaskSolanaWalletProvider`.\n *\n * @example\n * ```ts\n * const key = getMetaMaskSolanaSdkWalletProviderKey();\n * ```\n * @returns The deterministic wallet provider key.\n * @see createMetaMaskSolanaWalletProvider\n * @see reconcileMetaMaskWalletProvider\n * @notInstrumented\n */\nexport const getMetaMaskSolanaSdkWalletProviderKey = (): string =>\n formatWalletProviderKey({\n chain: 'SOL',\n displayName: METAMASK_SOLANA_SDK_DISPLAY_NAME,\n walletProviderType: WalletProviderEnum.QrCode,\n });\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getNetworksData } from '@dynamic-labs-sdk/client';\nimport {\n DYNAMIC_ICONIC_SPRITE_URL,\n assertDefined,\n formatWalletProviderGroupKey,\n getActiveNetworkIdFromLastKnownRegistry,\n getBuffer,\n switchActiveNetworkInLastKnownRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport {\n assertMetaMaskNetworkIsGranted,\n createMetaMaskWalletProviderEventEmitter,\n disconnectMetaMaskWalletProvider,\n getOrCreateMetaMaskClientInstanceManager,\n resolveActiveMetaMaskScope,\n} from '@dynamic-labs-sdk/metamask/core';\nimport { splitCaip10Token } from '@dynamic-labs-sdk/wallet-connect/core';\nimport { WalletProviderEnum } from '@dynamic-labs/sdk-api-core';\nimport { Transaction, VersionedTransaction } from '@solana/web3.js';\n\nimport { MetaMaskDirectConnectNotSupportedError } from '../../errors/MetaMaskDirectConnectNotSupportedError';\nimport type { SolanaWalletAccount } from '../../SolanaWalletAccount.types';\nimport type { SolanaWalletProvider } from '../../SolanaWalletProvider.types';\nimport { isVersionedTransaction } from '../../utils/isVersionedTransaction';\nimport { solanaConfirmTransaction } from '../../utils/solanaConfirmTransaction';\nimport { solanaExecuteSwapTransaction } from '../../utils/solanaExecuteSwapTransaction';\nimport { solanaTransferAmount } from '../../utils/solanaTransferAmount';\nimport { getMetaMaskSolanaSdkWalletProviderKey } from '../getMetaMaskSolanaSdkWalletProviderKey';\n\nconst METAMASK_DISPLAY_NAME = 'MetaMask';\nconst METAMASK_ICON = `${DYNAMIC_ICONIC_SPRITE_URL}#metamask`;\n\n/**\n * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask\n * SDK URI pairing. Unlike the EVM facade, MetaMask does not expose a typed\n * RPC surface for Solana, so this drives `invokeMethod` directly against the\n * documented `signMessage` / `signTransaction` / `signAndSendTransaction`\n * methods (see https://docs.metamask.io/metamask-connect/multichain/guides/sign-transactions/\n * and .../send-transactions/), scoped to `solana:<genesisHash>` per CAIP-2 —\n * MetaMask's multichain session grants every configured network as its own\n * scope up front, so \"the active network\" is tracked in Dynamic's own\n * last-known-network registry rather than asked of the SDK. Drops `connect`\n * so the provider is filtered out of the wallet picker by\n * `getAvailableWalletProvidersData` — mirroring how WalletConnect URI\n * sessions register a signing-only provider.\n *\n * MetaMask's multichain API does not document a batch-signing method for\n * Solana, so `signAllTransactions` signs each transaction with its own\n * `signTransaction` call (sequential wallet prompts) rather than one batch\n * approval.\n *\n * `getConnectedAddresses` and `switchActiveNetwork` route through\n * `resolveActiveMetaMaskScope`/`assertMetaMaskNetworkIsGranted` rather than\n * the registry directly, since every configured network is requested as an\n * *optional* scope -- MetaMask may grant an account for only a subset (see\n * their JSDoc).\n *\n * `switchActiveNetwork`/`disconnectWalletAccount` are local, Dynamic-side\n * actions with no live wallet event to bridge, so they emit `networkChanged`/\n * `disconnected` themselves via `metaMaskEvents` -- otherwise `events` would\n * never fire for MetaMask at all.\n *\n * @notInstrumented\n */\nexport const createMetaMaskSolanaWalletProvider = (\n client: DynamicClient\n): SolanaWalletProvider => {\n const metaMaskClientInstanceManager =\n getOrCreateMetaMaskClientInstanceManager(client);\n\n // Serializes a transaction the way MetaMask's multichain `signTransaction` /\n // `signAndSendTransaction` methods expect: base64, unsigned.\n const serializeTransaction = (\n transaction: Transaction | VersionedTransaction\n ): string =>\n getBuffer()\n .from(\n transaction.serialize({\n requireAllSignatures: false,\n verifySignatures: false,\n })\n )\n .toString('base64');\n\n // Reconstructs a signed transaction from MetaMask's base64 response.\n const deserializeTransaction = <\n T extends Transaction | VersionedTransaction\n >({\n base64Transaction,\n original,\n }: {\n base64Transaction: string;\n original: T;\n }): T => {\n const bytes = getBuffer().from(base64Transaction, 'base64');\n\n return (\n isVersionedTransaction(original)\n ? VersionedTransaction.deserialize(bytes)\n : Transaction.from(bytes)\n ) as T;\n };\n\n const walletProviderKey = getMetaMaskSolanaSdkWalletProviderKey();\n\n // MetaMask's multichain session never fires a live wallet event we could\n // bridge for `switchActiveNetwork`/`disconnectWalletAccount` below (both are\n // local, Dynamic-side actions -- see their own comments), so this emitter is\n // the only way `onWalletProviderEvent` consumers ever hear about them.\n const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();\n\n const getActiveScope = async (): Promise<`solana:${string}`> => {\n const { networkId } = await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n\n const network = getNetworksData(client).find(\n (candidate) =>\n candidate.chain === 'SOL' && candidate.networkId === networkId\n );\n\n assertDefined(\n network?.genesisHash,\n `No configured SOL network with a genesis hash matches active network id \"${networkId}\"`\n );\n\n return `solana:${network.genesisHash}`;\n };\n\n const getConnectedAddresses: SolanaWalletProvider['getConnectedAddresses'] =\n async () => {\n const metaMaskClient =\n await metaMaskClientInstanceManager.getMetaMaskClient();\n\n // Every configured SOL network is requested as an *optional* MetaMask\n // scope, so MetaMask may grant an account for only a subset (e.g. only\n // mainnet, not a preconfigured devnet) -- resolveActiveMetaMaskScope\n // falls back to whichever configured network DOES have a granted\n // account, self-healing the registry's default rather than surfacing\n // a false \"no address connected\".\n const { accounts } = await resolveActiveMetaMaskScope(\n { chain: 'SOL', metaMaskClient, walletProviderKey },\n client\n );\n\n return {\n addresses: accounts.map((account) => splitCaip10Token(account).address),\n };\n };\n\n const getActiveNetworkId: SolanaWalletProvider['getActiveNetworkId'] =\n async () =>\n getActiveNetworkIdFromLastKnownRegistry({ client, walletProviderKey });\n\n // The generic switchActiveNetwork asks the wallet live, which doesn't apply\n // here: MetaMask's multichain session already grants every configured\n // chain as its own scope up front, so \"switching\" is just updating which\n // scope future requests target, tracked in Dynamic's own registry. Guarded\n // against ever pointing that registry at a network MetaMask didn't\n // actually grant -- see `assertMetaMaskNetworkIsGranted`.\n const switchActiveNetwork: SolanaWalletProvider['switchActiveNetwork'] =\n async ({ networkId }) => {\n const metaMaskClient =\n await metaMaskClientInstanceManager.getMetaMaskClient();\n\n await assertMetaMaskNetworkIsGranted(\n { chain: 'SOL', metaMaskClient, networkId },\n client\n );\n\n // Read the previous value before writing, so networkChanged only fires\n // on an actual change -- switching to the network that's already active\n // is a no-op as far as any `onWalletProviderEvent` subscriber is concerned.\n const { networkId: previousNetworkId } =\n await getActiveNetworkIdFromLastKnownRegistry({\n client,\n walletProviderKey,\n });\n\n await switchActiveNetworkInLastKnownRegistry({\n client,\n networkId,\n walletProviderKey,\n });\n\n if (networkId !== previousNetworkId) {\n metaMaskEvents.emitNetworkChanged({ networkId });\n }\n };\n\n const signMessage: NonNullable<SolanaWalletProvider['signMessage']> = async ({\n message,\n walletAccount,\n }) => {\n assertDefined(walletAccount, 'Wallet account is required');\n\n const scope = await getActiveScope();\n const metaMaskClient = await metaMaskClientInstanceManager.getMetaMaskClient();\n\n const result = (await metaMaskClient.invokeMethod({\n request: {\n method: 'signMessage',\n params: {\n account: { address: walletAccount.address },\n message: getBuffer().from(message, 'utf-8').toString('base64'),\n },\n },\n scope,\n })) as { signature: string };\n\n return { signature: result.signature };\n };\n\n const signTransaction: SolanaWalletProvider['signTransaction'] = async ({\n transaction,\n walletAccount,\n }) => {\n const scope = await getActiveScope();\n const metaMaskClient = await metaMaskClientInstanceManager.getMetaMaskClient();\n\n const result = (await metaMaskClient.invokeMethod({\n request: {\n method: 'signTransaction',\n params: {\n account: { address: walletAccount.address },\n scope,\n transaction: serializeTransaction(transaction),\n },\n },\n scope,\n })) as { signedTransaction: string };\n\n return {\n signedTransaction: deserializeTransaction({\n base64Transaction: result.signedTransaction,\n original: transaction,\n }),\n };\n };\n\n const signAllTransactions: SolanaWalletProvider['signAllTransactions'] =\n async <T extends Transaction | VersionedTransaction>({\n transactions,\n walletAccount,\n }: {\n transactions: T[];\n walletAccount: SolanaWalletAccount;\n }) => {\n const signedTransactions: T[] = [];\n\n // Sequential: MetaMask's multichain API has no documented batch-sign\n // method for Solana, unlike the Wallet Standard surface this replaces.\n for (const transaction of transactions) {\n const { signedTransaction } = await signTransaction({\n transaction,\n walletAccount,\n });\n signedTransactions.push(signedTransaction as T);\n }\n\n return { signedTransactions };\n };\n\n const signAndSendTransaction: SolanaWalletProvider['signAndSendTransaction'] =\n async ({ transaction, walletAccount }) => {\n const scope = await getActiveScope();\n const metaMaskClient =\n await metaMaskClientInstanceManager.getMetaMaskClient();\n\n const result = (await metaMaskClient.invokeMethod({\n request: {\n method: 'signAndSendTransaction',\n params: {\n account: { address: walletAccount.address },\n scope,\n transaction: serializeTransaction(transaction),\n },\n },\n scope,\n })) as { signature: string };\n\n return { signature: result.signature };\n };\n\n // A MetaMask multichain session is scope-based rather than per-provider,\n // so ending it properly means dropping this chain's scopes and cleaning\n // up the persisted session -- see `disconnectMetaMaskWalletProvider`.\n const disconnectWalletAccount: SolanaWalletProvider['disconnectWalletAccount'] =\n async () => {\n await disconnectMetaMaskWalletProvider(\n { chain: 'SOL', walletProviderKey },\n client\n );\n metaMaskEvents.emitDisconnected();\n };\n\n // Cleans up `metaMaskEvents` (the emitter behind `events` below) -- nothing\n // else in this provider owns it or ever tears it down otherwise.\n const destroy: SolanaWalletProvider['destroy'] = async () => {\n metaMaskEvents.cleanupEventEmitter();\n };\n\n return {\n chain: 'SOL',\n confirmTransaction: (args) => solanaConfirmTransaction(args, client),\n connect: async () => {\n throw new MetaMaskDirectConnectNotSupportedError();\n },\n destroy,\n disconnectWalletAccount,\n get events() {\n return metaMaskEvents.getEventEmitter();\n },\n executeSwapTransaction: (args) =>\n solanaExecuteSwapTransaction(args, client),\n getActiveNetworkId,\n getConnectedAddresses,\n groupKey: formatWalletProviderGroupKey(METAMASK_DISPLAY_NAME),\n key: walletProviderKey,\n metadata: {\n displayName: METAMASK_DISPLAY_NAME,\n icon: METAMASK_ICON,\n },\n signAllTransactions,\n signAndSendTransaction,\n signMessage,\n signTransaction,\n switchActiveNetwork,\n transferAmount: (args) => solanaTransferAmount(args, client),\n walletProviderType: WalletProviderEnum.QrCode,\n };\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getDefaultClient,\n hasExtension,\n registerExtension,\n} from '@dynamic-labs-sdk/client/core';\nimport { reconcileMetaMaskWalletProvider } from '@dynamic-labs-sdk/metamask/core';\n\nimport { registerSolanaNetworkProviderBuilder } from '../../registerSolanaNetworkProviderBuilder';\nimport { createMetaMaskSolanaWalletProvider } from '../createMetaMaskSolanaWalletProvider';\nimport { getMetaMaskSolanaSdkWalletProviderKey } from '../getMetaMaskSolanaSdkWalletProviderKey';\n\nexport const METAMASK_SOLANA_EXTENSION_KEY = 'metaMaskSolana';\n\n/**\n * Integrates MetaMask Connect (MetaMask's multichain SDK) with the Dynamic\n * client for Solana, letting users connect MetaMask on platforms where the\n * browser extension isn't available — e.g. scanning a QR code, or opening\n * the MetaMask mobile app from a website or React Native app. Call this\n * once during setup.\n *\n * @example\n * ```ts\n * const client = createDynamicClient({ environmentId: '...' });\n *\n * addMetaMaskSolanaExtension(client);\n * ```\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns void\n * @see connectWithMetaMaskUriSolana\n * @see addSolanaWalletStandardExtension\n * @notInstrumented\n */\nexport const addMetaMaskSolanaExtension = (\n client: DynamicClient = getDefaultClient()\n): void => {\n if (hasExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) {\n return;\n }\n\n registerSolanaNetworkProviderBuilder(client);\n registerExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client);\n\n reconcileMetaMaskWalletProvider(\n {\n walletProviderBuilder: createMetaMaskSolanaWalletProvider,\n walletProviderKey: getMetaMaskSolanaSdkWalletProviderKey(),\n },\n client\n );\n};\n","import type { DynamicClient } from '@dynamic-labs-sdk/client';\nimport { getCore, hasExtension } from '@dynamic-labs-sdk/client/core';\n\nimport { METAMASK_SOLANA_EXTENSION_KEY } from '../addMetaMaskSolanaExtension/addMetaMaskSolanaExtension';\n\n/**\n * Warns when `addMetaMaskSolanaExtension()` hasn't been added, since a\n * wallet connected via `connectWithMetaMaskUriSolana` without it won't be\n * restored after a page reload.\n *\n * @example\n * ```ts\n * warnMetaMaskSolanaIntegrationIncomplete(client);\n * ```\n * @param client - The Dynamic client instance.\n * @returns void\n * @see connectWithMetaMaskUriSolana\n * @see addMetaMaskSolanaExtension\n * @notInstrumented\n */\nexport const warnMetaMaskSolanaIntegrationIncomplete = (\n client: DynamicClient\n): void => {\n if (hasExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) {\n return;\n }\n\n getCore(client).logger.warn(\n `MetaMask integration is incomplete: addMetaMaskSolanaExtension() is missing. Add it during setup:\n\nimport { addMetaMaskSolanaExtension } from '@dynamic-labs-sdk/solana/metamask';\nimport { createDynamicClient } from '@dynamic-labs-sdk/client';\n\nconst client = createDynamicClient({ environmentId: '...' });\n\naddMetaMaskSolanaExtension(client);`\n );\n};\n","import { getDefaultClient } from '@dynamic-labs-sdk/client';\nimport type { WalletProviderUriConnectionResult } from '@dynamic-labs-sdk/client';\nimport { connectWithMetaMaskUri } from '@dynamic-labs-sdk/metamask';\n\nimport { registerSolanaNetworkProviderBuilder } from '../../registerSolanaNetworkProviderBuilder';\nimport { createMetaMaskSolanaWalletProvider } from '../createMetaMaskSolanaWalletProvider';\nimport { warnMetaMaskSolanaIntegrationIncomplete } from '../warnMetaMaskSolanaIntegrationIncomplete';\n\nexport type ConnectWithMetaMaskUriSolanaParams = {\n /** Whether to add the connected wallet account to the Dynamic client. Defaults to `true`. */\n addToDynamicWalletAccounts?: boolean;\n};\n\n/**\n * Drives a MetaMask SDK URI pairing for Solana and returns `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink. The resulting\n * wallet provider registers for signing only and is never surfaced in the\n * wallet picker. When the MetaMask extension is announced via Wallet Standard,\n * prefer routing through `getMetaMaskSolanaExtensionWalletProviderKey` instead.\n *\n * @notInstrumented\n */\nexport const connectWithMetaMaskUriSolana = (\n { addToDynamicWalletAccounts = true }: ConnectWithMetaMaskUriSolanaParams = {},\n client = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n warnMetaMaskSolanaIntegrationIncomplete(client);\n\n registerSolanaNetworkProviderBuilder(client);\n\n return connectWithMetaMaskUri(\n {\n addToDynamicWalletAccounts,\n chain: 'SOL',\n walletProviderBuilder: createMetaMaskSolanaWalletProvider,\n },\n client\n );\n};\n","import {\n type WalletAccount,\n type WalletProviderUriConnectionResult,\n getDefaultClient,\n verifyWalletAccount,\n} from '@dynamic-labs-sdk/client';\n\nimport { connectWithMetaMaskUriSolana } from '../connectWithMetaMaskUriSolana';\n\n/**\n * Drives a MetaMask SDK URI pairing for Solana and verifies ownership of the\n * paired wallet account through message signing, returning `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink.\n *\n * Builds on `connectWithMetaMaskUriSolana` (rather than the chain-agnostic\n * connector directly) so the Solana-specific wiring stays defined in one\n * place, then wraps its `approval` to add the verification round-trip. The\n * pairing is driven with `addToDynamicWalletAccounts: false` so the account\n * lands as a verified credential instead of an unverified entry.\n *\n * The MetaMask SDK does not expose a single-round-trip authenticate\n * primitive, so this drives two sequential interactions on the wallet side:\n * the user first approves the pairing, then approves a sign-in message.\n *\n * @notInstrumented\n */\nexport const connectAndVerifyWithMetaMaskUriSolana = async (\n client = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n const { approval, uri } = await connectWithMetaMaskUriSolana(\n { addToDynamicWalletAccounts: false },\n client\n );\n\n const verifiedApproval = async (): Promise<{\n walletAccounts: WalletAccount[];\n }> => {\n const { walletAccounts } = await approval();\n\n // MetaMask SDK exposes a single active address per pairing, mirroring how\n // the underlying connect helper materializes a single account from\n // `addresses[0]`. Verify it directly.\n const [walletAccount] = walletAccounts;\n\n if (walletAccount) {\n await verifyWalletAccount({ walletAccount }, client);\n }\n\n return { walletAccounts };\n };\n\n return { approval: verifiedApproval, uri };\n};\n","import { getDefaultClient } from '@dynamic-labs-sdk/client';\nimport { getMetaMaskExtensionWalletProviderKey } from '@dynamic-labs-sdk/metamask';\n\n/**\n * Returns the wallet provider key of the MetaMask browser extension announced\n * for Solana via Wallet Standard, or `undefined` when none is announced. Pass\n * the returned key to `connectWithWalletProvider` to route through the\n * announced provider; fall back to `connectWithMetaMaskUriSolana` when\n * `undefined`.\n *\n * @notInstrumented\n */\nexport const getMetaMaskSolanaExtensionWalletProviderKey = (\n client = getDefaultClient()\n): string | undefined =>\n getMetaMaskExtensionWalletProviderKey({ chain: 'SOL' }, client);\n","import { getDefaultClient } from '@dynamic-labs-sdk/client';\nimport { getUriConnectionStarterRegistry } from '@dynamic-labs-sdk/client/core';\n\nimport { connectWithMetaMaskUriSolana } from '../connectWithMetaMaskUriSolana';\n\n/**\n * Registers the MetaMask SDK URI pairing for Solana with the client, so higher\n * level connection APIs can mint a MetaMask URI for Solana without depending on\n * this package.\n *\n * Call it during app setup to opt into the MetaMask URI path — it is kept out\n * of the Solana extension so apps that never pair with MetaMask over a URI\n * don't bundle the MetaMask SDK.\n *\n * @example\n * ```ts\n * registerMetaMaskSolanaUriConnectionStarter();\n * ```\n *\n * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.\n * @returns Nothing.\n * @see connectWithMetaMaskUriSolana\n * @see getUriConnectionStarterRegistry\n * @notInstrumented\n */\nexport const registerMetaMaskSolanaUriConnectionStarter = (\n client = getDefaultClient()\n): void => {\n getUriConnectionStarterRegistry(client).register({\n chain: 'SOL',\n start: ({ addToDynamicWalletAccounts }) =>\n connectWithMetaMaskUriSolana({ addToDynamicWalletAccounts }, client),\n type: 'metamaskSdkUri',\n });\n};\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport {\n name as packageName,\n version as packageVersion,\n} from '../../package.json';\nassertPackageVersion(packageName, packageVersion);\n\nexport { addMetaMaskSolanaExtension } from '../metamask/addMetaMaskSolanaExtension';\nexport { connectAndVerifyWithMetaMaskUriSolana } from '../metamask/connectAndVerifyWithMetaMaskUriSolana';\nexport { connectWithMetaMaskUriSolana } from '../metamask/connectWithMetaMaskUriSolana';\nexport type { ConnectWithMetaMaskUriSolanaParams } from '../metamask/connectWithMetaMaskUriSolana/connectWithMetaMaskUriSolana';\nexport { MetaMaskDirectConnectNotSupportedError } from '../errors/MetaMaskDirectConnectNotSupportedError';\nexport { getMetaMaskSolanaExtensionWalletProviderKey } from '../metamask/getMetaMaskSolanaExtensionWalletProviderKey';\nexport { registerMetaMaskSolanaUriConnectionStarter } from '../metamask/registerMetaMaskSolanaUriConnectionStarter';\nexport { MetaMaskDisplayUriMissingError } from '@dynamic-labs-sdk/metamask';\n"],"mappings":"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"}
@@ -1,180 +1,300 @@
1
- import { d as registerSolanaNetworkProviderBuilder, f as name, p as version } from "./solanaTransferAmount-BmcJvD2x.esm.js";
2
- import { n as getFeaturesForSolanaStandardWallet, t as createWalletProviderFromSolanaStandardWallet } from "./createWalletProviderFromSolanaStandardWallet-CpSgF7IN.esm.js";
1
+ import { d as registerSolanaNetworkProviderBuilder, f as name, l as isVersionedTransaction, n as solanaExecuteSwapTransaction, p as version, s as solanaConfirmTransaction, t as solanaTransferAmount } from "./solanaTransferAmount-C-2Ct-ry.esm.js";
3
2
  import { assertPackageVersion } from "@dynamic-labs-sdk/assert-package-version";
4
- import { assertNonEmptyArray, createRuntimeServiceAccessKey, getAppMetadata, getCore, getNativeLinkScheme } from "@dynamic-labs-sdk/client/core";
5
- import { getDefaultClient as getDefaultClient$1, getNetworksData, verifyWalletAccount } from "@dynamic-labs-sdk/client";
3
+ import { DYNAMIC_ICONIC_SPRITE_URL, assertDefined, formatWalletProviderGroupKey, formatWalletProviderKey, getActiveNetworkIdFromLastKnownRegistry, getBuffer, getCore, getDefaultClient, getUriConnectionStarterRegistry, hasExtension, registerExtension, switchActiveNetworkInLastKnownRegistry } from "@dynamic-labs-sdk/client/core";
4
+ import { BaseError, getDefaultClient as getDefaultClient$1, getNetworksData, verifyWalletAccount } from "@dynamic-labs-sdk/client";
5
+ import { Transaction, VersionedTransaction } from "@solana/web3.js";
6
6
  import { WalletProviderEnum } from "@dynamic-labs/sdk-api-core";
7
- import { MetaMaskDisplayUriMissingError, MetaMaskWalletNotConnectedError, clearMetaMaskSessionStorage, connectWithMetaMaskUri, getMetaMaskExtensionWalletProviderKey } from "@dynamic-labs-sdk/metamask";
8
- import { createSolanaClient } from "@metamask/connect-solana";
7
+ import { assertMetaMaskNetworkIsGranted, createMetaMaskWalletProviderEventEmitter, disconnectMetaMaskWalletProvider, getOrCreateMetaMaskClientInstanceManager, reconcileMetaMaskWalletProvider, resolveActiveMetaMaskScope } from "@dynamic-labs-sdk/metamask/core";
8
+ import { splitCaip10Token } from "@dynamic-labs-sdk/wallet-connect/core";
9
+ import { MetaMaskDisplayUriMissingError, connectWithMetaMaskUri, getMetaMaskExtensionWalletProviderKey } from "@dynamic-labs-sdk/metamask";
9
10
 
10
- //#region src/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.ts
11
+ //#region src/errors/MetaMaskDirectConnectNotSupportedError/MetaMaskDirectConnectNotSupportedError.ts
11
12
  /**
12
- * Maps a Dynamic network `cluster` (e.g. `mainnet-beta`, `devnet`,
13
- * `testnet`) to the `mainnet | devnet | testnet` key shape expected by
14
- * `@metamask/connect-solana`'s `createSolanaClient`. Returns `undefined` for
15
- * clusters that do not correspond to one of MetaMask's supported Solana
16
- * networks so callers can skip them. Used by `getSupportedNetworks` to build
17
- * the SDK's `supportedNetworks` map.
18
- *
19
- * @notInstrumented
13
+ * Thrown when `connect()` is called directly on the MetaMask SDK placeholder
14
+ * wallet provider (the entry `addMetaMaskSolanaExtension` registers so
15
+ * MetaMask still shows up in the wallet picker when no browser extension is
16
+ * installed). That placeholder has no generic connect flow of its own --
17
+ * connecting requires the QR / deeplink pairing flow, so callers must drive
18
+ * `connectWithMetaMaskUriSolana` (or `connectAndVerifyWithMetaMaskUriSolana`)
19
+ * instead of the picker's default connect.
20
20
  */
21
- const getSolanaNetworkFromCluster = ({ cluster }) => {
22
- if (cluster === void 0) return;
23
- if (cluster.includes("mainnet")) return "mainnet";
24
- if (cluster.includes("devnet")) return "devnet";
25
- if (cluster.includes("testnet")) return "testnet";
21
+ var MetaMaskDirectConnectNotSupportedError = class extends BaseError {
22
+ constructor() {
23
+ super({
24
+ cause: null,
25
+ code: "metamask_direct_connect_not_supported",
26
+ docsUrl: null,
27
+ name: "MetaMaskDirectConnectNotSupportedError",
28
+ shortMessage: "MetaMask cannot be connected directly; call connectWithMetaMaskUriSolana (or connectAndVerifyWithMetaMaskUriSolana) to get a QR/URI pairing flow instead"
29
+ });
30
+ }
26
31
  };
27
32
 
28
33
  //#endregion
29
- //#region src/metamask/utils/getSupportedNetworks/getSupportedNetworks.ts
34
+ //#region src/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.ts
35
+ const METAMASK_SOLANA_SDK_DISPLAY_NAME = "MetaMask";
30
36
  /**
31
- * Builds the `supportedNetworks` map required by
32
- * `@metamask/connect-solana`'s `createSolanaClient`, keyed by the SDK's
33
- * `mainnet | devnet | testnet` network names and valued with the first
34
- * configured RPC URL for each. Sources the configured SOL networks from the
35
- * Dynamic client's project settings. Throws when no SOL network is
36
- * configured, mirroring the EVM `getSupportedNetworks` contract.
37
+ * Deterministic wallet provider key for the MetaMask SDK's connect-less
38
+ * Solana placeholder. Computed without building the wallet provider itself,
39
+ * so `addMetaMaskSolanaExtension` can check for a matching wallet account
40
+ * before paying the cost of `createMetaMaskSolanaWalletProvider`.
37
41
  *
42
+ * @example
43
+ * ```ts
44
+ * const key = getMetaMaskSolanaSdkWalletProviderKey();
45
+ * ```
46
+ * @returns The deterministic wallet provider key.
47
+ * @see createMetaMaskSolanaWalletProvider
48
+ * @see reconcileMetaMaskWalletProvider
38
49
  * @notInstrumented
39
50
  */
40
- const getSupportedNetworks = (client) => {
41
- const solanaNetworks = getNetworksData(client).filter((network) => network.chain === "SOL");
42
- assertNonEmptyArray(solanaNetworks, "No SOL networks have been configured. Make sure to add at least one Solana network to your project settings in the Dynamic Dashboard.");
43
- const supportedNetworks = {};
44
- for (const network of solanaNetworks) {
45
- const solanaNetwork = getSolanaNetworkFromCluster({ cluster: network.cluster });
46
- if (solanaNetwork !== void 0 && supportedNetworks[solanaNetwork] === void 0) supportedNetworks[solanaNetwork] = network.rpcUrls.http[0];
47
- }
48
- return supportedNetworks;
49
- };
51
+ const getMetaMaskSolanaSdkWalletProviderKey = () => formatWalletProviderKey({
52
+ chain: "SOL",
53
+ displayName: METAMASK_SOLANA_SDK_DISPLAY_NAME,
54
+ walletProviderType: WalletProviderEnum.QrCode
55
+ });
50
56
 
51
57
  //#endregion
52
- //#region src/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.ts
58
+ //#region src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts
59
+ const METAMASK_DISPLAY_NAME = "MetaMask";
60
+ const METAMASK_ICON = `${DYNAMIC_ICONIC_SPRITE_URL}#metamask`;
53
61
  /**
54
- * Builds a fully-initialised `MetaMaskSolanaController` for the given Dynamic
55
- * client. Drives the `@metamask/connect-solana` SDK through its Wallet
56
- * Standard surface so consumers render their own QR / deep-link UI, and
57
- * subscribes to the SDK core's `display_uri` event at construction time so
58
- * the first URI emission cannot be lost to a subscription race. The wallet
59
- * is created with `skipAutoRegister` so this URI-pairing client does not
60
- * register itself into the global Wallet Standard registry an announced
61
- * MetaMask extension is discovered independently. Dapp metadata is sourced
62
- * from the client's `getAppMetadata`. Browser-only.
63
- * The MetaMask SDK's own verbose logging is tied to the Dynamic client's log
64
- * level, so turning on `debug` logging for the Dynamic SDK also surfaces
65
- * MetaMask's internal SDK trace output.
62
+ * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask
63
+ * SDK URI pairing. Unlike the EVM facade, MetaMask does not expose a typed
64
+ * RPC surface for Solana, so this drives `invokeMethod` directly against the
65
+ * documented `signMessage` / `signTransaction` / `signAndSendTransaction`
66
+ * methods (see https://docs.metamask.io/metamask-connect/multichain/guides/sign-transactions/
67
+ * and .../send-transactions/), scoped to `solana:<genesisHash>` per CAIP-2
68
+ * MetaMask's multichain session grants every configured network as its own
69
+ * scope up front, so "the active network" is tracked in Dynamic's own
70
+ * last-known-network registry rather than asked of the SDK. Drops `connect`
71
+ * so the provider is filtered out of the wallet picker by
72
+ * `getAvailableWalletProvidersData` mirroring how WalletConnect URI
73
+ * sessions register a signing-only provider.
74
+ *
75
+ * MetaMask's multichain API does not document a batch-signing method for
76
+ * Solana, so `signAllTransactions` signs each transaction with its own
77
+ * `signTransaction` call (sequential wallet prompts) rather than one batch
78
+ * approval.
79
+ *
80
+ * `getConnectedAddresses` and `switchActiveNetwork` route through
81
+ * `resolveActiveMetaMaskScope`/`assertMetaMaskNetworkIsGranted` rather than
82
+ * the registry directly, since every configured network is requested as an
83
+ * *optional* scope -- MetaMask may grant an account for only a subset (see
84
+ * their JSDoc).
85
+ *
86
+ * `switchActiveNetwork`/`disconnectWalletAccount` are local, Dynamic-side
87
+ * actions with no live wallet event to bridge, so they emit `networkChanged`/
88
+ * `disconnected` themselves via `metaMaskEvents` -- otherwise `events` would
89
+ * never fire for MetaMask at all.
66
90
  *
67
91
  * @notInstrumented
68
92
  */
69
- const createMetaMaskSolanaController = async (client) => {
70
- const supportedNetworks = getSupportedNetworks(client);
71
- const { appName, appLogoUrl, appUniversalLink, appNativeLink } = getAppMetadata(client);
72
- const { logger } = getCore(client);
73
- await clearMetaMaskSessionStorage(client);
74
- const listeners = /* @__PURE__ */ new Set();
75
- let latestDisplayUri;
76
- const sdk = await createSolanaClient({
77
- api: { supportedNetworks },
78
- dapp: {
79
- iconUrl: appLogoUrl,
80
- name: appName,
81
- nativeScheme: getNativeLinkScheme({ nativeLink: appNativeLink }),
82
- url: appUniversalLink ?? ""
83
- },
84
- debug: logger.isEnabled("debug"),
85
- skipAutoRegister: true
86
- });
87
- sdk.core.on("display_uri", (uri) => {
88
- latestDisplayUri = uri;
89
- for (const listener of listeners) listener(uri);
90
- });
91
- sdk.core.on("stateChanged", (status) => {
92
- if (status === "connected" || status === "disconnected") latestDisplayUri = void 0;
93
+ const createMetaMaskSolanaWalletProvider = (client) => {
94
+ const metaMaskClientInstanceManager = getOrCreateMetaMaskClientInstanceManager(client);
95
+ const serializeTransaction = (transaction) => getBuffer().from(transaction.serialize({
96
+ requireAllSignatures: false,
97
+ verifySignatures: false
98
+ })).toString("base64");
99
+ const deserializeTransaction = ({ base64Transaction, original }) => {
100
+ const bytes = getBuffer().from(base64Transaction, "base64");
101
+ return isVersionedTransaction(original) ? VersionedTransaction.deserialize(bytes) : Transaction.from(bytes);
102
+ };
103
+ const walletProviderKey = getMetaMaskSolanaSdkWalletProviderKey();
104
+ const metaMaskEvents = createMetaMaskWalletProviderEventEmitter();
105
+ const getActiveScope = async () => {
106
+ const { networkId } = await getActiveNetworkIdFromLastKnownRegistry({
107
+ client,
108
+ walletProviderKey
109
+ });
110
+ const network = getNetworksData(client).find((candidate) => candidate.chain === "SOL" && candidate.networkId === networkId);
111
+ assertDefined(network?.genesisHash, `No configured SOL network with a genesis hash matches active network id "${networkId}"`);
112
+ return `solana:${network.genesisHash}`;
113
+ };
114
+ const getConnectedAddresses = async () => {
115
+ const { accounts } = await resolveActiveMetaMaskScope({
116
+ chain: "SOL",
117
+ metaMaskClient: await metaMaskClientInstanceManager.getMetaMaskClient(),
118
+ walletProviderKey
119
+ }, client);
120
+ return { addresses: accounts.map((account) => splitCaip10Token(account).address) };
121
+ };
122
+ const getActiveNetworkId = async () => getActiveNetworkIdFromLastKnownRegistry({
123
+ client,
124
+ walletProviderKey
93
125
  });
94
- latestDisplayUri = void 0;
95
- const onDisplayUri = (listener) => {
96
- listeners.add(listener);
97
- if (latestDisplayUri !== void 0) listener(latestDisplayUri);
98
- return () => {
99
- listeners.delete(listener);
100
- };
126
+ const switchActiveNetwork = async ({ networkId }) => {
127
+ await assertMetaMaskNetworkIsGranted({
128
+ chain: "SOL",
129
+ metaMaskClient: await metaMaskClientInstanceManager.getMetaMaskClient(),
130
+ networkId
131
+ }, client);
132
+ const { networkId: previousNetworkId } = await getActiveNetworkIdFromLastKnownRegistry({
133
+ client,
134
+ walletProviderKey
135
+ });
136
+ await switchActiveNetworkInLastKnownRegistry({
137
+ client,
138
+ networkId,
139
+ walletProviderKey
140
+ });
141
+ if (networkId !== previousNetworkId) metaMaskEvents.emitNetworkChanged({ networkId });
101
142
  };
102
- let inFlightConnect = null;
103
- const connect = () => {
104
- if (inFlightConnect) return inFlightConnect;
105
- inFlightConnect = (async () => {
106
- try {
107
- if (sdk.core.status === "connecting") try {
108
- await sdk.disconnect();
109
- } catch (error) {
110
- getCore(client).logger.debug("[metamask] pre-connect disconnect rejected (expected when aborting a pairing the wallet never accepted)", error);
143
+ const signMessage = async ({ message, walletAccount }) => {
144
+ assertDefined(walletAccount, "Wallet account is required");
145
+ const scope = await getActiveScope();
146
+ return { signature: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
147
+ request: {
148
+ method: "signMessage",
149
+ params: {
150
+ account: { address: walletAccount.address },
151
+ message: getBuffer().from(message, "utf-8").toString("base64")
111
152
  }
112
- await getFeaturesForSolanaStandardWallet(sdk.getWallet())["standard:connect"].connect();
113
- } finally {
114
- inFlightConnect = null;
115
- }
116
- })();
117
- return inFlightConnect;
153
+ },
154
+ scope
155
+ })).signature };
156
+ };
157
+ const signTransaction = async ({ transaction, walletAccount }) => {
158
+ const scope = await getActiveScope();
159
+ return { signedTransaction: deserializeTransaction({
160
+ base64Transaction: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
161
+ request: {
162
+ method: "signTransaction",
163
+ params: {
164
+ account: { address: walletAccount.address },
165
+ scope,
166
+ transaction: serializeTransaction(transaction)
167
+ }
168
+ },
169
+ scope
170
+ })).signedTransaction,
171
+ original: transaction
172
+ }) };
173
+ };
174
+ const signAllTransactions = async ({ transactions, walletAccount }) => {
175
+ const signedTransactions = [];
176
+ for (const transaction of transactions) {
177
+ const { signedTransaction } = await signTransaction({
178
+ transaction,
179
+ walletAccount
180
+ });
181
+ signedTransactions.push(signedTransaction);
182
+ }
183
+ return { signedTransactions };
184
+ };
185
+ const signAndSendTransaction = async ({ transaction, walletAccount }) => {
186
+ const scope = await getActiveScope();
187
+ return { signature: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
188
+ request: {
189
+ method: "signAndSendTransaction",
190
+ params: {
191
+ account: { address: walletAccount.address },
192
+ scope,
193
+ transaction: serializeTransaction(transaction)
194
+ }
195
+ },
196
+ scope
197
+ })).signature };
198
+ };
199
+ const disconnectWalletAccount = async () => {
200
+ await disconnectMetaMaskWalletProvider({
201
+ chain: "SOL",
202
+ walletProviderKey
203
+ }, client);
204
+ metaMaskEvents.emitDisconnected();
205
+ };
206
+ const destroy = async () => {
207
+ metaMaskEvents.cleanupEventEmitter();
118
208
  };
119
209
  return {
120
- clearCachedDisplayUri: () => {
121
- latestDisplayUri = void 0;
210
+ chain: "SOL",
211
+ confirmTransaction: (args) => solanaConfirmTransaction(args, client),
212
+ connect: async () => {
213
+ throw new MetaMaskDirectConnectNotSupportedError();
214
+ },
215
+ destroy,
216
+ disconnectWalletAccount,
217
+ get events() {
218
+ return metaMaskEvents.getEventEmitter();
122
219
  },
123
- connect,
124
- getLatestDisplayUri: () => latestDisplayUri,
125
- onDisplayUri,
126
- sdk
220
+ executeSwapTransaction: (args) => solanaExecuteSwapTransaction(args, client),
221
+ getActiveNetworkId,
222
+ getConnectedAddresses,
223
+ groupKey: formatWalletProviderGroupKey(METAMASK_DISPLAY_NAME),
224
+ key: walletProviderKey,
225
+ metadata: {
226
+ displayName: METAMASK_DISPLAY_NAME,
227
+ icon: METAMASK_ICON
228
+ },
229
+ signAllTransactions,
230
+ signAndSendTransaction,
231
+ signMessage,
232
+ signTransaction,
233
+ switchActiveNetwork,
234
+ transferAmount: (args) => solanaTransferAmount(args, client),
235
+ walletProviderType: WalletProviderEnum.QrCode
127
236
  };
128
237
  };
129
238
 
130
239
  //#endregion
131
- //#region src/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.ts
132
- const RUNTIME_SERVICE_KEY = "metaMaskSolanaController";
240
+ //#region src/metamask/addMetaMaskSolanaExtension/addMetaMaskSolanaExtension.ts
241
+ const METAMASK_SOLANA_EXTENSION_KEY = "metaMaskSolana";
133
242
  /**
134
- * Per-`DynamicClient` accessor for the lazily-constructed MetaMask Solana
135
- * controller. Wraps `createMetaMaskSolanaController` with the standard
136
- * `runtimeServices` cache so every caller the Wallet Standard
137
- * wallet-provider builder, the `display_uri` subscription helper, and the
138
- * `connectWithMetaMaskUriSolana` URI-returning helper — shares the same
139
- * controller (and therefore the same SDK instance, display-URI cache, and
140
- * listener registry) per Dynamic client.
141
- *
142
- * The cache is **per-Dynamic-client, not per-SDK-instance**:
143
- * `@metamask/connect-solana`'s `createSolanaClient` builds on the shared
144
- * MultichainCore singleton, so when multiple Dynamic clients coexist they
145
- * end up sharing the same MetaMask session regardless of this cache. The
146
- * wrapper exists to own the controller's `display_uri` cache and listener
147
- * registry per Dynamic client, which the SDK itself does not expose.
243
+ * Integrates MetaMask Connect (MetaMask's multichain SDK) with the Dynamic
244
+ * client for Solana, letting users connect MetaMask on platforms where the
245
+ * browser extension isn't availablee.g. scanning a QR code, or opening
246
+ * the MetaMask mobile app from a website or React Native app. Call this
247
+ * once during setup.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * const client = createDynamicClient({ environmentId: '...' });
148
252
  *
253
+ * addMetaMaskSolanaExtension(client);
254
+ * ```
255
+ * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.
256
+ * @returns void
257
+ * @see connectWithMetaMaskUriSolana
258
+ * @see addSolanaWalletStandardExtension
149
259
  * @notInstrumented
150
260
  */
151
- const getOrCreateMetaMaskSolanaController = createRuntimeServiceAccessKey(RUNTIME_SERVICE_KEY, (client) => createMetaMaskSolanaController(client));
261
+ const addMetaMaskSolanaExtension = (client = getDefaultClient()) => {
262
+ if (hasExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) return;
263
+ registerSolanaNetworkProviderBuilder(client);
264
+ registerExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client);
265
+ reconcileMetaMaskWalletProvider({
266
+ walletProviderBuilder: createMetaMaskSolanaWalletProvider,
267
+ walletProviderKey: getMetaMaskSolanaSdkWalletProviderKey()
268
+ }, client);
269
+ };
152
270
 
153
271
  //#endregion
154
- //#region src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts
272
+ //#region src/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.ts
155
273
  /**
156
- * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask
157
- * SDK URI pairing. Wraps the paired Wallet Standard wallet exposed by
158
- * `@metamask/connect-solana` behind the Dynamic Solana provider facade and
159
- * classifies it as `QrCode` so its key does not collide with an announced
160
- * MetaMask browser-extension provider for the same wallet name. Drops
161
- * `connect` so the provider is filtered out of the wallet picker by
162
- * `getAvailableWalletProvidersData` — mirroring how WalletConnect URI
163
- * sessions register a signing-only provider.
274
+ * Warns when `addMetaMaskSolanaExtension()` hasn't been added, since a
275
+ * wallet connected via `connectWithMetaMaskUriSolana` without it won't be
276
+ * restored after a page reload.
164
277
  *
278
+ * @example
279
+ * ```ts
280
+ * warnMetaMaskSolanaIntegrationIncomplete(client);
281
+ * ```
282
+ * @param client - The Dynamic client instance.
283
+ * @returns void
284
+ * @see connectWithMetaMaskUriSolana
285
+ * @see addMetaMaskSolanaExtension
165
286
  * @notInstrumented
166
287
  */
167
- const createMetaMaskSolanaWalletProvider = async (client) => {
168
- const walletStandardWallet = (await getOrCreateMetaMaskSolanaController(client)).sdk.getWallet();
169
- if (walletStandardWallet.accounts.length === 0) throw new MetaMaskWalletNotConnectedError();
170
- return {
171
- ...createWalletProviderFromSolanaStandardWallet({
172
- dynamicClient: client,
173
- walletProviderType: WalletProviderEnum.QrCode,
174
- walletStandardWallet
175
- }),
176
- connect: void 0
177
- };
288
+ const warnMetaMaskSolanaIntegrationIncomplete = (client) => {
289
+ if (hasExtension({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) return;
290
+ getCore(client).logger.warn(`MetaMask integration is incomplete: addMetaMaskSolanaExtension() is missing. Add it during setup:
291
+
292
+ import { addMetaMaskSolanaExtension } from '@dynamic-labs-sdk/solana/metamask';
293
+ import { createDynamicClient } from '@dynamic-labs-sdk/client';
294
+
295
+ const client = createDynamicClient({ environmentId: '...' });
296
+
297
+ addMetaMaskSolanaExtension(client);`);
178
298
  };
179
299
 
180
300
  //#endregion
@@ -189,11 +309,11 @@ const createMetaMaskSolanaWalletProvider = async (client) => {
189
309
  * @notInstrumented
190
310
  */
191
311
  const connectWithMetaMaskUriSolana = ({ addToDynamicWalletAccounts = true } = {}, client = getDefaultClient$1()) => {
312
+ warnMetaMaskSolanaIntegrationIncomplete(client);
192
313
  registerSolanaNetworkProviderBuilder(client);
193
314
  return connectWithMetaMaskUri({
194
315
  addToDynamicWalletAccounts,
195
316
  chain: "SOL",
196
- getController: getOrCreateMetaMaskSolanaController,
197
317
  walletProviderBuilder: createMetaMaskSolanaWalletProvider
198
318
  }, client);
199
319
  };
@@ -244,10 +364,40 @@ const connectAndVerifyWithMetaMaskUriSolana = async (client = getDefaultClient$1
244
364
  */
245
365
  const getMetaMaskSolanaExtensionWalletProviderKey = (client = getDefaultClient$1()) => getMetaMaskExtensionWalletProviderKey({ chain: "SOL" }, client);
246
366
 
367
+ //#endregion
368
+ //#region src/metamask/registerMetaMaskSolanaUriConnectionStarter/registerMetaMaskSolanaUriConnectionStarter.ts
369
+ /**
370
+ * Registers the MetaMask SDK URI pairing for Solana with the client, so higher
371
+ * level connection APIs can mint a MetaMask URI for Solana without depending on
372
+ * this package.
373
+ *
374
+ * Call it during app setup to opt into the MetaMask URI path — it is kept out
375
+ * of the Solana extension so apps that never pair with MetaMask over a URI
376
+ * don't bundle the MetaMask SDK.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * registerMetaMaskSolanaUriConnectionStarter();
381
+ * ```
382
+ *
383
+ * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.
384
+ * @returns Nothing.
385
+ * @see connectWithMetaMaskUriSolana
386
+ * @see getUriConnectionStarterRegistry
387
+ * @notInstrumented
388
+ */
389
+ const registerMetaMaskSolanaUriConnectionStarter = (client = getDefaultClient$1()) => {
390
+ getUriConnectionStarterRegistry(client).register({
391
+ chain: "SOL",
392
+ start: ({ addToDynamicWalletAccounts }) => connectWithMetaMaskUriSolana({ addToDynamicWalletAccounts }, client),
393
+ type: "metamaskSdkUri"
394
+ });
395
+ };
396
+
247
397
  //#endregion
248
398
  //#region src/exports/metamask.ts
249
399
  assertPackageVersion(name, version);
250
400
 
251
401
  //#endregion
252
- export { MetaMaskDisplayUriMissingError, connectAndVerifyWithMetaMaskUriSolana, connectWithMetaMaskUriSolana, getMetaMaskSolanaExtensionWalletProviderKey };
402
+ export { MetaMaskDirectConnectNotSupportedError, MetaMaskDisplayUriMissingError, addMetaMaskSolanaExtension, connectAndVerifyWithMetaMaskUriSolana, connectWithMetaMaskUriSolana, getMetaMaskSolanaExtensionWalletProviderKey, registerMetaMaskSolanaUriConnectionStarter };
253
403
  //# sourceMappingURL=metamask.esm.js.map