@dynamic-labs-sdk/solana 1.30.3 → 1.31.1

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 (76) hide show
  1. package/README.md +22 -0
  2. package/dist/{createWalletProviderFromSolanaStandardWallet-7scwFRPx.cjs → addSolanaWalletStandardExtension-BtLeB7I_.cjs} +56 -10
  3. package/dist/addSolanaWalletStandardExtension-BtLeB7I_.cjs.map +1 -0
  4. package/dist/{createWalletProviderFromSolanaStandardWallet-Ct5daB5n.esm.js → addSolanaWalletStandardExtension-Dw0WpBQT.esm.js} +56 -4
  5. package/dist/addSolanaWalletStandardExtension-Dw0WpBQT.esm.js.map +1 -0
  6. package/dist/{addWaasSolanaExtension-BOCVVYOJ.esm.js → addWaasSolanaExtension-BJFGRV-L.esm.js} +2 -2
  7. package/dist/{addWaasSolanaExtension-BOCVVYOJ.esm.js.map → addWaasSolanaExtension-BJFGRV-L.esm.js.map} +1 -1
  8. package/dist/{addWaasSolanaExtension-C578HPQN.cjs → addWaasSolanaExtension-D38jCZMI.cjs} +2 -2
  9. package/dist/{addWaasSolanaExtension-C578HPQN.cjs.map → addWaasSolanaExtension-D38jCZMI.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 +2 -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/warnMetaMaskSolanaIntegrationIncomplete/index.d.ts +2 -0
  32. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/index.d.ts.map +1 -0
  33. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.d.ts +18 -0
  34. package/dist/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.d.ts.map +1 -0
  35. package/dist/metamask.cjs +258 -136
  36. package/dist/metamask.cjs.map +1 -1
  37. package/dist/metamask.esm.js +260 -140
  38. package/dist/metamask.esm.js.map +1 -1
  39. package/dist/{solanaTransferAmount-DJWF4X6z.cjs → solanaTransferAmount-B9KcoSis.cjs} +2 -2
  40. package/dist/{solanaTransferAmount-DJWF4X6z.cjs.map → solanaTransferAmount-B9KcoSis.cjs.map} +1 -1
  41. package/dist/{solanaTransferAmount-CGMhHg9s.esm.js → solanaTransferAmount-DMJb_djy.esm.js} +2 -2
  42. package/dist/{solanaTransferAmount-CGMhHg9s.esm.js.map → solanaTransferAmount-DMJb_djy.esm.js.map} +1 -1
  43. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  44. package/dist/waas.cjs +2 -2
  45. package/dist/waas.esm.js +2 -2
  46. package/dist/walletConnect.cjs +1 -1
  47. package/dist/walletConnect.esm.js +1 -1
  48. package/dist/walletStandard.cjs +2 -3
  49. package/dist/walletStandard.cjs.map +1 -1
  50. package/dist/walletStandard.esm.js +2 -3
  51. package/dist/walletStandard.esm.js.map +1 -1
  52. package/package.json +5 -6
  53. package/dist/addSolanaWalletStandardExtension-037R5her.esm.js +0 -59
  54. package/dist/addSolanaWalletStandardExtension-037R5her.esm.js.map +0 -1
  55. package/dist/addSolanaWalletStandardExtension-GFlxcKCD.cjs +0 -65
  56. package/dist/addSolanaWalletStandardExtension-GFlxcKCD.cjs.map +0 -1
  57. package/dist/createWalletProviderFromSolanaStandardWallet-7scwFRPx.cjs.map +0 -1
  58. package/dist/createWalletProviderFromSolanaStandardWallet-Ct5daB5n.esm.js.map +0 -1
  59. package/dist/metamask/metamask.types.d.ts +0 -14
  60. package/dist/metamask/metamask.types.d.ts.map +0 -1
  61. package/dist/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.d.ts +0 -20
  62. package/dist/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.d.ts.map +0 -1
  63. package/dist/metamask/utils/createMetaMaskSolanaController/index.d.ts +0 -2
  64. package/dist/metamask/utils/createMetaMaskSolanaController/index.d.ts.map +0 -1
  65. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.d.ts +0 -20
  66. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.d.ts.map +0 -1
  67. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/index.d.ts +0 -2
  68. package/dist/metamask/utils/getOrCreateMetaMaskSolanaController/index.d.ts.map +0 -1
  69. package/dist/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.d.ts +0 -18
  70. package/dist/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.d.ts.map +0 -1
  71. package/dist/metamask/utils/getSolanaNetworkFromCluster/index.d.ts +0 -3
  72. package/dist/metamask/utils/getSolanaNetworkFromCluster/index.d.ts.map +0 -1
  73. package/dist/metamask/utils/getSupportedNetworks/getSupportedNetworks.d.ts +0 -16
  74. package/dist/metamask/utils/getSupportedNetworks/getSupportedNetworks.d.ts.map +0 -1
  75. package/dist/metamask/utils/getSupportedNetworks/index.d.ts +0 -2
  76. package/dist/metamask/utils/getSupportedNetworks/index.d.ts.map +0 -1
@@ -2,15 +2,35 @@ import type { DynamicClient } from '@dynamic-labs-sdk/client';
2
2
  import type { SolanaWalletProvider } from '../../SolanaWalletProvider.types';
3
3
  /**
4
4
  * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask
5
- * SDK URI pairing. Wraps the paired Wallet Standard wallet exposed by
6
- * `@metamask/connect-solana` behind the Dynamic Solana provider facade and
7
- * classifies it as `QrCode` so its key does not collide with an announced
8
- * MetaMask browser-extension provider for the same wallet name. Drops
9
- * `connect` so the provider is filtered out of the wallet picker by
5
+ * SDK URI pairing. Unlike the EVM facade, MetaMask does not expose a typed
6
+ * RPC surface for Solana, so this drives `invokeMethod` directly against the
7
+ * documented `signMessage` / `signTransaction` / `signAndSendTransaction`
8
+ * methods (see https://docs.metamask.io/metamask-connect/multichain/guides/sign-transactions/
9
+ * and .../send-transactions/), scoped to `solana:<genesisHash>` per CAIP-2
10
+ * MetaMask's multichain session grants every configured network as its own
11
+ * scope up front, so "the active network" is tracked in Dynamic's own
12
+ * last-known-network registry rather than asked of the SDK. Drops `connect`
13
+ * so the provider is filtered out of the wallet picker by
10
14
  * `getAvailableWalletProvidersData` — mirroring how WalletConnect URI
11
15
  * sessions register a signing-only provider.
12
16
  *
17
+ * MetaMask's multichain API does not document a batch-signing method for
18
+ * Solana, so `signAllTransactions` signs each transaction with its own
19
+ * `signTransaction` call (sequential wallet prompts) rather than one batch
20
+ * approval.
21
+ *
22
+ * `getConnectedAddresses` and `switchActiveNetwork` route through
23
+ * `resolveActiveMetaMaskScope`/`assertMetaMaskNetworkIsGranted` rather than
24
+ * the registry directly, since every configured network is requested as an
25
+ * *optional* scope -- MetaMask may grant an account for only a subset (see
26
+ * their JSDoc).
27
+ *
28
+ * `switchActiveNetwork`/`disconnectWalletAccount` are local, Dynamic-side
29
+ * actions with no live wallet event to bridge, so they emit `networkChanged`/
30
+ * `disconnected` themselves via `metaMaskEvents` -- otherwise `events` would
31
+ * never fire for MetaMask at all.
32
+ *
13
33
  * @notInstrumented
14
34
  */
15
- export declare const createMetaMaskSolanaWalletProvider: (client: DynamicClient) => Promise<SolanaWalletProvider>;
35
+ export declare const createMetaMaskSolanaWalletProvider: (client: DynamicClient) => SolanaWalletProvider;
16
36
  //# sourceMappingURL=createMetaMaskSolanaWalletProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createMetaMaskSolanaWalletProvider.d.ts","sourceRoot":"","sources":["../../../src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAI7E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kCAAkC,WACrC,aAAa,KACpB,OAAO,CAAC,oBAAoB,CAsB9B,CAAC"}
1
+ {"version":3,"file":"createMetaMaskSolanaWalletProvider.d.ts","sourceRoot":"","sources":["../../../src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAuB9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAU7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,kCAAkC,WACrC,aAAa,KACpB,oBA0QF,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Deterministic wallet provider key for the MetaMask SDK's connect-less
3
+ * Solana placeholder. Computed without building the wallet provider itself,
4
+ * so `addMetaMaskSolanaExtension` can check for a matching wallet account
5
+ * before paying the cost of `createMetaMaskSolanaWalletProvider`.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const key = getMetaMaskSolanaSdkWalletProviderKey();
10
+ * ```
11
+ * @returns The deterministic wallet provider key.
12
+ * @see createMetaMaskSolanaWalletProvider
13
+ * @see reconcileMetaMaskWalletProvider
14
+ * @notInstrumented
15
+ */
16
+ export declare const getMetaMaskSolanaSdkWalletProviderKey: () => string;
17
+ //# sourceMappingURL=getMetaMaskSolanaSdkWalletProviderKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMetaMaskSolanaSdkWalletProviderKey.d.ts","sourceRoot":"","sources":["../../../src/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qCAAqC,QAAO,MAKrD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getMetaMaskSolanaSdkWalletProviderKey } from './getMetaMaskSolanaSdkWalletProviderKey';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/metamask/getMetaMaskSolanaSdkWalletProviderKey/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { warnMetaMaskSolanaIntegrationIncomplete } from './warnMetaMaskSolanaIntegrationIncomplete';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/metamask/warnMetaMaskSolanaIntegrationIncomplete/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,2CAA2C,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { DynamicClient } from '@dynamic-labs-sdk/client';
2
+ /**
3
+ * Warns when `addMetaMaskSolanaExtension()` hasn't been added, since a
4
+ * wallet connected via `connectWithMetaMaskUriSolana` without it won't be
5
+ * restored after a page reload.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * warnMetaMaskSolanaIntegrationIncomplete(client);
10
+ * ```
11
+ * @param client - The Dynamic client instance.
12
+ * @returns void
13
+ * @see connectWithMetaMaskUriSolana
14
+ * @see addMetaMaskSolanaExtension
15
+ * @notInstrumented
16
+ */
17
+ export declare const warnMetaMaskSolanaIntegrationIncomplete: (client: DynamicClient) => void;
18
+ //# sourceMappingURL=warnMetaMaskSolanaIntegrationIncomplete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnMetaMaskSolanaIntegrationIncomplete.d.ts","sourceRoot":"","sources":["../../../src/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uCAAuC,WAC1C,aAAa,KACpB,IAeF,CAAC"}
package/dist/metamask.cjs CHANGED
@@ -1,181 +1,301 @@
1
1
  const require_chunk = require('./chunk-CbDLau6x.cjs');
2
- const require_solanaTransferAmount = require('./solanaTransferAmount-DJWF4X6z.cjs');
3
- const require_createWalletProviderFromSolanaStandardWallet = require('./createWalletProviderFromSolanaStandardWallet-7scwFRPx.cjs');
2
+ const require_solanaTransferAmount = require('./solanaTransferAmount-B9KcoSis.cjs');
4
3
  let _dynamic_labs_sdk_assert_package_version = require("@dynamic-labs-sdk/assert-package-version");
5
4
  let _dynamic_labs_sdk_client_core = require("@dynamic-labs-sdk/client/core");
6
5
  let _dynamic_labs_sdk_client = require("@dynamic-labs-sdk/client");
6
+ let _solana_web3_js = require("@solana/web3.js");
7
7
  let _dynamic_labs_sdk_api_core = require("@dynamic-labs/sdk-api-core");
8
+ let _dynamic_labs_sdk_metamask_core = require("@dynamic-labs-sdk/metamask/core");
9
+ let _dynamic_labs_sdk_wallet_connect_core = require("@dynamic-labs-sdk/wallet-connect/core");
8
10
  let _dynamic_labs_sdk_metamask = require("@dynamic-labs-sdk/metamask");
9
- let _metamask_connect_solana = require("@metamask/connect-solana");
10
11
 
11
- //#region src/metamask/utils/getSolanaNetworkFromCluster/getSolanaNetworkFromCluster.ts
12
+ //#region src/errors/MetaMaskDirectConnectNotSupportedError/MetaMaskDirectConnectNotSupportedError.ts
12
13
  /**
13
- * Maps a Dynamic network `cluster` (e.g. `mainnet-beta`, `devnet`,
14
- * `testnet`) to the `mainnet | devnet | testnet` key shape expected by
15
- * `@metamask/connect-solana`'s `createSolanaClient`. Returns `undefined` for
16
- * clusters that do not correspond to one of MetaMask's supported Solana
17
- * networks so callers can skip them. Used by `getSupportedNetworks` to build
18
- * the SDK's `supportedNetworks` map.
19
- *
20
- * @notInstrumented
14
+ * Thrown when `connect()` is called directly on the MetaMask SDK placeholder
15
+ * wallet provider (the entry `addMetaMaskSolanaExtension` registers so
16
+ * MetaMask still shows up in the wallet picker when no browser extension is
17
+ * installed). That placeholder has no generic connect flow of its own --
18
+ * connecting requires the QR / deeplink pairing flow, so callers must drive
19
+ * `connectWithMetaMaskUriSolana` (or `connectAndVerifyWithMetaMaskUriSolana`)
20
+ * instead of the picker's default connect.
21
21
  */
22
- const getSolanaNetworkFromCluster = ({ cluster }) => {
23
- if (cluster === void 0) return;
24
- if (cluster.includes("mainnet")) return "mainnet";
25
- if (cluster.includes("devnet")) return "devnet";
26
- if (cluster.includes("testnet")) return "testnet";
22
+ var MetaMaskDirectConnectNotSupportedError = class extends _dynamic_labs_sdk_client.BaseError {
23
+ constructor() {
24
+ super({
25
+ cause: null,
26
+ code: "metamask_direct_connect_not_supported",
27
+ docsUrl: null,
28
+ name: "MetaMaskDirectConnectNotSupportedError",
29
+ shortMessage: "MetaMask cannot be connected directly; call connectWithMetaMaskUriSolana (or connectAndVerifyWithMetaMaskUriSolana) to get a QR/URI pairing flow instead"
30
+ });
31
+ }
27
32
  };
28
33
 
29
34
  //#endregion
30
- //#region src/metamask/utils/getSupportedNetworks/getSupportedNetworks.ts
35
+ //#region src/metamask/getMetaMaskSolanaSdkWalletProviderKey/getMetaMaskSolanaSdkWalletProviderKey.ts
36
+ const METAMASK_SOLANA_SDK_DISPLAY_NAME = "MetaMask";
31
37
  /**
32
- * Builds the `supportedNetworks` map required by
33
- * `@metamask/connect-solana`'s `createSolanaClient`, keyed by the SDK's
34
- * `mainnet | devnet | testnet` network names and valued with the first
35
- * configured RPC URL for each. Sources the configured SOL networks from the
36
- * Dynamic client's project settings. Throws when no SOL network is
37
- * configured, mirroring the EVM `getSupportedNetworks` contract.
38
+ * Deterministic wallet provider key for the MetaMask SDK's connect-less
39
+ * Solana placeholder. Computed without building the wallet provider itself,
40
+ * so `addMetaMaskSolanaExtension` can check for a matching wallet account
41
+ * before paying the cost of `createMetaMaskSolanaWalletProvider`.
38
42
  *
43
+ * @example
44
+ * ```ts
45
+ * const key = getMetaMaskSolanaSdkWalletProviderKey();
46
+ * ```
47
+ * @returns The deterministic wallet provider key.
48
+ * @see createMetaMaskSolanaWalletProvider
49
+ * @see reconcileMetaMaskWalletProvider
39
50
  * @notInstrumented
40
51
  */
41
- const getSupportedNetworks = (client) => {
42
- const solanaNetworks = (0, _dynamic_labs_sdk_client.getNetworksData)(client).filter((network) => network.chain === "SOL");
43
- (0, _dynamic_labs_sdk_client_core.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.");
44
- const supportedNetworks = {};
45
- for (const network of solanaNetworks) {
46
- const solanaNetwork = getSolanaNetworkFromCluster({ cluster: network.cluster });
47
- if (solanaNetwork !== void 0 && supportedNetworks[solanaNetwork] === void 0) supportedNetworks[solanaNetwork] = network.rpcUrls.http[0];
48
- }
49
- return supportedNetworks;
50
- };
52
+ const getMetaMaskSolanaSdkWalletProviderKey = () => (0, _dynamic_labs_sdk_client_core.formatWalletProviderKey)({
53
+ chain: "SOL",
54
+ displayName: METAMASK_SOLANA_SDK_DISPLAY_NAME,
55
+ walletProviderType: _dynamic_labs_sdk_api_core.WalletProviderEnum.QrCode
56
+ });
51
57
 
52
58
  //#endregion
53
- //#region src/metamask/utils/createMetaMaskSolanaController/createMetaMaskSolanaController.ts
59
+ //#region src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts
60
+ const METAMASK_DISPLAY_NAME = "MetaMask";
61
+ const METAMASK_ICON = `${_dynamic_labs_sdk_client_core.DYNAMIC_ICONIC_SPRITE_URL}#metamask`;
54
62
  /**
55
- * Builds a fully-initialised `MetaMaskSolanaController` for the given Dynamic
56
- * client. Drives the `@metamask/connect-solana` SDK through its Wallet
57
- * Standard surface so consumers render their own QR / deep-link UI, and
58
- * subscribes to the SDK core's `display_uri` event at construction time so
59
- * the first URI emission cannot be lost to a subscription race. The wallet
60
- * is created with `skipAutoRegister` so this URI-pairing client does not
61
- * register itself into the global Wallet Standard registry an announced
62
- * MetaMask extension is discovered independently. Dapp metadata is sourced
63
- * from the client's `getAppMetadata`. Browser-only.
64
- * The MetaMask SDK's own verbose logging is tied to the Dynamic client's log
65
- * level, so turning on `debug` logging for the Dynamic SDK also surfaces
66
- * MetaMask's internal SDK trace output.
63
+ * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask
64
+ * SDK URI pairing. Unlike the EVM facade, MetaMask does not expose a typed
65
+ * RPC surface for Solana, so this drives `invokeMethod` directly against the
66
+ * documented `signMessage` / `signTransaction` / `signAndSendTransaction`
67
+ * methods (see https://docs.metamask.io/metamask-connect/multichain/guides/sign-transactions/
68
+ * and .../send-transactions/), scoped to `solana:<genesisHash>` per CAIP-2
69
+ * MetaMask's multichain session grants every configured network as its own
70
+ * scope up front, so "the active network" is tracked in Dynamic's own
71
+ * last-known-network registry rather than asked of the SDK. Drops `connect`
72
+ * so the provider is filtered out of the wallet picker by
73
+ * `getAvailableWalletProvidersData` mirroring how WalletConnect URI
74
+ * sessions register a signing-only provider.
75
+ *
76
+ * MetaMask's multichain API does not document a batch-signing method for
77
+ * Solana, so `signAllTransactions` signs each transaction with its own
78
+ * `signTransaction` call (sequential wallet prompts) rather than one batch
79
+ * approval.
80
+ *
81
+ * `getConnectedAddresses` and `switchActiveNetwork` route through
82
+ * `resolveActiveMetaMaskScope`/`assertMetaMaskNetworkIsGranted` rather than
83
+ * the registry directly, since every configured network is requested as an
84
+ * *optional* scope -- MetaMask may grant an account for only a subset (see
85
+ * their JSDoc).
86
+ *
87
+ * `switchActiveNetwork`/`disconnectWalletAccount` are local, Dynamic-side
88
+ * actions with no live wallet event to bridge, so they emit `networkChanged`/
89
+ * `disconnected` themselves via `metaMaskEvents` -- otherwise `events` would
90
+ * never fire for MetaMask at all.
67
91
  *
68
92
  * @notInstrumented
69
93
  */
70
- const createMetaMaskSolanaController = async (client) => {
71
- const supportedNetworks = getSupportedNetworks(client);
72
- const { appName, appLogoUrl, appUniversalLink, appNativeLink } = (0, _dynamic_labs_sdk_client_core.getAppMetadata)(client);
73
- const { logger } = (0, _dynamic_labs_sdk_client_core.getCore)(client);
74
- await (0, _dynamic_labs_sdk_metamask.clearMetaMaskSessionStorage)(client);
75
- const listeners = /* @__PURE__ */ new Set();
76
- let latestDisplayUri;
77
- const sdk = await (0, _metamask_connect_solana.createSolanaClient)({
78
- api: { supportedNetworks },
79
- dapp: {
80
- iconUrl: appLogoUrl,
81
- name: appName,
82
- nativeScheme: (0, _dynamic_labs_sdk_client_core.getNativeLinkScheme)({ nativeLink: appNativeLink }),
83
- url: appUniversalLink ?? ""
84
- },
85
- debug: logger.isEnabled("debug"),
86
- skipAutoRegister: true
87
- });
88
- sdk.core.on("display_uri", (uri) => {
89
- latestDisplayUri = uri;
90
- for (const listener of listeners) listener(uri);
91
- });
92
- sdk.core.on("stateChanged", (status) => {
93
- if (status === "connected" || status === "disconnected") latestDisplayUri = void 0;
94
+ const createMetaMaskSolanaWalletProvider = (client) => {
95
+ const metaMaskClientInstanceManager = (0, _dynamic_labs_sdk_metamask_core.getOrCreateMetaMaskClientInstanceManager)(client);
96
+ const serializeTransaction = (transaction) => (0, _dynamic_labs_sdk_client_core.getBuffer)().from(transaction.serialize({
97
+ requireAllSignatures: false,
98
+ verifySignatures: false
99
+ })).toString("base64");
100
+ const deserializeTransaction = ({ base64Transaction, original }) => {
101
+ const bytes = (0, _dynamic_labs_sdk_client_core.getBuffer)().from(base64Transaction, "base64");
102
+ return require_solanaTransferAmount.isVersionedTransaction(original) ? _solana_web3_js.VersionedTransaction.deserialize(bytes) : _solana_web3_js.Transaction.from(bytes);
103
+ };
104
+ const walletProviderKey = getMetaMaskSolanaSdkWalletProviderKey();
105
+ const metaMaskEvents = (0, _dynamic_labs_sdk_metamask_core.createMetaMaskWalletProviderEventEmitter)();
106
+ const getActiveScope = async () => {
107
+ const { networkId } = await (0, _dynamic_labs_sdk_client_core.getActiveNetworkIdFromLastKnownRegistry)({
108
+ client,
109
+ walletProviderKey
110
+ });
111
+ const network = (0, _dynamic_labs_sdk_client.getNetworksData)(client).find((candidate) => candidate.chain === "SOL" && candidate.networkId === networkId);
112
+ (0, _dynamic_labs_sdk_client_core.assertDefined)(network?.genesisHash, `No configured SOL network with a genesis hash matches active network id "${networkId}"`);
113
+ return `solana:${network.genesisHash}`;
114
+ };
115
+ const getConnectedAddresses = async () => {
116
+ const { accounts } = await (0, _dynamic_labs_sdk_metamask_core.resolveActiveMetaMaskScope)({
117
+ chain: "SOL",
118
+ metaMaskClient: await metaMaskClientInstanceManager.getMetaMaskClient(),
119
+ walletProviderKey
120
+ }, client);
121
+ return { addresses: accounts.map((account) => (0, _dynamic_labs_sdk_wallet_connect_core.splitCaip10Token)(account).address) };
122
+ };
123
+ const getActiveNetworkId = async () => (0, _dynamic_labs_sdk_client_core.getActiveNetworkIdFromLastKnownRegistry)({
124
+ client,
125
+ walletProviderKey
94
126
  });
95
- latestDisplayUri = void 0;
96
- const onDisplayUri = (listener) => {
97
- listeners.add(listener);
98
- if (latestDisplayUri !== void 0) listener(latestDisplayUri);
99
- return () => {
100
- listeners.delete(listener);
101
- };
127
+ const switchActiveNetwork = async ({ networkId }) => {
128
+ await (0, _dynamic_labs_sdk_metamask_core.assertMetaMaskNetworkIsGranted)({
129
+ chain: "SOL",
130
+ metaMaskClient: await metaMaskClientInstanceManager.getMetaMaskClient(),
131
+ networkId
132
+ }, client);
133
+ const { networkId: previousNetworkId } = await (0, _dynamic_labs_sdk_client_core.getActiveNetworkIdFromLastKnownRegistry)({
134
+ client,
135
+ walletProviderKey
136
+ });
137
+ await (0, _dynamic_labs_sdk_client_core.switchActiveNetworkInLastKnownRegistry)({
138
+ client,
139
+ networkId,
140
+ walletProviderKey
141
+ });
142
+ if (networkId !== previousNetworkId) metaMaskEvents.emitNetworkChanged({ networkId });
143
+ };
144
+ const signMessage = async ({ message, walletAccount }) => {
145
+ (0, _dynamic_labs_sdk_client_core.assertDefined)(walletAccount, "Wallet account is required");
146
+ const scope = await getActiveScope();
147
+ return { signature: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
148
+ request: {
149
+ method: "signMessage",
150
+ params: {
151
+ account: { address: walletAccount.address },
152
+ message: (0, _dynamic_labs_sdk_client_core.getBuffer)().from(message, "utf-8").toString("base64")
153
+ }
154
+ },
155
+ scope
156
+ })).signature };
157
+ };
158
+ const signTransaction = async ({ transaction, walletAccount }) => {
159
+ const scope = await getActiveScope();
160
+ return { signedTransaction: deserializeTransaction({
161
+ base64Transaction: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
162
+ request: {
163
+ method: "signTransaction",
164
+ params: {
165
+ account: { address: walletAccount.address },
166
+ scope,
167
+ transaction: serializeTransaction(transaction)
168
+ }
169
+ },
170
+ scope
171
+ })).signedTransaction,
172
+ original: transaction
173
+ }) };
174
+ };
175
+ const signAllTransactions = async ({ transactions, walletAccount }) => {
176
+ const signedTransactions = [];
177
+ for (const transaction of transactions) {
178
+ const { signedTransaction } = await signTransaction({
179
+ transaction,
180
+ walletAccount
181
+ });
182
+ signedTransactions.push(signedTransaction);
183
+ }
184
+ return { signedTransactions };
102
185
  };
103
- let inFlightConnect = null;
104
- const connect = () => {
105
- if (inFlightConnect) return inFlightConnect;
106
- inFlightConnect = (async () => {
107
- try {
108
- if (sdk.core.status === "connecting") try {
109
- await sdk.disconnect();
110
- } catch (error) {
111
- (0, _dynamic_labs_sdk_client_core.getCore)(client).logger.debug("[metamask] pre-connect disconnect rejected (expected when aborting a pairing the wallet never accepted)", error);
186
+ const signAndSendTransaction = async ({ transaction, walletAccount }) => {
187
+ const scope = await getActiveScope();
188
+ return { signature: (await (await metaMaskClientInstanceManager.getMetaMaskClient()).invokeMethod({
189
+ request: {
190
+ method: "signAndSendTransaction",
191
+ params: {
192
+ account: { address: walletAccount.address },
193
+ scope,
194
+ transaction: serializeTransaction(transaction)
112
195
  }
113
- await require_createWalletProviderFromSolanaStandardWallet.getFeaturesForSolanaStandardWallet(sdk.getWallet())["standard:connect"].connect();
114
- } finally {
115
- inFlightConnect = null;
116
- }
117
- })();
118
- return inFlightConnect;
196
+ },
197
+ scope
198
+ })).signature };
199
+ };
200
+ const disconnectWalletAccount = async () => {
201
+ await (0, _dynamic_labs_sdk_metamask_core.disconnectMetaMaskWalletProvider)({
202
+ chain: "SOL",
203
+ walletProviderKey
204
+ }, client);
205
+ metaMaskEvents.emitDisconnected();
206
+ };
207
+ const destroy = async () => {
208
+ metaMaskEvents.cleanupEventEmitter();
119
209
  };
120
210
  return {
121
- clearCachedDisplayUri: () => {
122
- latestDisplayUri = void 0;
211
+ chain: "SOL",
212
+ confirmTransaction: (args) => require_solanaTransferAmount.solanaConfirmTransaction(args, client),
213
+ connect: async () => {
214
+ throw new MetaMaskDirectConnectNotSupportedError();
215
+ },
216
+ destroy,
217
+ disconnectWalletAccount,
218
+ get events() {
219
+ return metaMaskEvents.getEventEmitter();
220
+ },
221
+ executeSwapTransaction: (args) => require_solanaTransferAmount.solanaExecuteSwapTransaction(args, client),
222
+ getActiveNetworkId,
223
+ getConnectedAddresses,
224
+ groupKey: (0, _dynamic_labs_sdk_client_core.formatWalletProviderGroupKey)(METAMASK_DISPLAY_NAME),
225
+ key: walletProviderKey,
226
+ metadata: {
227
+ displayName: METAMASK_DISPLAY_NAME,
228
+ icon: METAMASK_ICON
123
229
  },
124
- connect,
125
- getLatestDisplayUri: () => latestDisplayUri,
126
- onDisplayUri,
127
- sdk
230
+ signAllTransactions,
231
+ signAndSendTransaction,
232
+ signMessage,
233
+ signTransaction,
234
+ switchActiveNetwork,
235
+ transferAmount: (args) => require_solanaTransferAmount.solanaTransferAmount(args, client),
236
+ walletProviderType: _dynamic_labs_sdk_api_core.WalletProviderEnum.QrCode
128
237
  };
129
238
  };
130
239
 
131
240
  //#endregion
132
- //#region src/metamask/utils/getOrCreateMetaMaskSolanaController/getOrCreateMetaMaskSolanaController.ts
133
- const RUNTIME_SERVICE_KEY = "metaMaskSolanaController";
241
+ //#region src/metamask/addMetaMaskSolanaExtension/addMetaMaskSolanaExtension.ts
242
+ const METAMASK_SOLANA_EXTENSION_KEY = "metaMaskSolana";
134
243
  /**
135
- * Per-`DynamicClient` accessor for the lazily-constructed MetaMask Solana
136
- * controller. Wraps `createMetaMaskSolanaController` with the standard
137
- * `runtimeServices` cache so every caller the Wallet Standard
138
- * wallet-provider builder, the `display_uri` subscription helper, and the
139
- * `connectWithMetaMaskUriSolana` URI-returning helper — shares the same
140
- * controller (and therefore the same SDK instance, display-URI cache, and
141
- * listener registry) per Dynamic client.
244
+ * Integrates MetaMask Connect (MetaMask's multichain SDK) with the Dynamic
245
+ * client for Solana, letting users connect MetaMask on platforms where the
246
+ * browser extension isn't availablee.g. scanning a QR code, or opening
247
+ * the MetaMask mobile app from a website or React Native app. Call this
248
+ * once during setup.
142
249
  *
143
- * The cache is **per-Dynamic-client, not per-SDK-instance**:
144
- * `@metamask/connect-solana`'s `createSolanaClient` builds on the shared
145
- * MultichainCore singleton, so when multiple Dynamic clients coexist they
146
- * end up sharing the same MetaMask session regardless of this cache. The
147
- * wrapper exists to own the controller's `display_uri` cache and listener
148
- * registry per Dynamic client, which the SDK itself does not expose.
250
+ * @example
251
+ * ```ts
252
+ * const client = createDynamicClient({ environmentId: '...' });
149
253
  *
254
+ * addMetaMaskSolanaExtension(client);
255
+ * ```
256
+ * @param [client] - The Dynamic client instance. Only required when using multiple Dynamic clients.
257
+ * @returns void
258
+ * @see connectWithMetaMaskUriSolana
259
+ * @see addSolanaWalletStandardExtension
150
260
  * @notInstrumented
151
261
  */
152
- const getOrCreateMetaMaskSolanaController = (0, _dynamic_labs_sdk_client_core.createRuntimeServiceAccessKey)(RUNTIME_SERVICE_KEY, (client) => createMetaMaskSolanaController(client));
262
+ const addMetaMaskSolanaExtension = (client = (0, _dynamic_labs_sdk_client_core.getDefaultClient)()) => {
263
+ if ((0, _dynamic_labs_sdk_client_core.hasExtension)({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) return;
264
+ require_solanaTransferAmount.registerSolanaNetworkProviderBuilder(client);
265
+ (0, _dynamic_labs_sdk_client_core.registerExtension)({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client);
266
+ (0, _dynamic_labs_sdk_metamask_core.reconcileMetaMaskWalletProvider)({
267
+ walletProviderBuilder: createMetaMaskSolanaWalletProvider,
268
+ walletProviderKey: getMetaMaskSolanaSdkWalletProviderKey()
269
+ }, client);
270
+ };
153
271
 
154
272
  //#endregion
155
- //#region src/metamask/createMetaMaskSolanaWalletProvider/createMetaMaskSolanaWalletProvider.ts
273
+ //#region src/metamask/warnMetaMaskSolanaIntegrationIncomplete/warnMetaMaskSolanaIntegrationIncomplete.ts
156
274
  /**
157
- * Builds the `SolanaWalletProvider` registered AFTER a successful MetaMask
158
- * SDK URI pairing. Wraps the paired Wallet Standard wallet exposed by
159
- * `@metamask/connect-solana` behind the Dynamic Solana provider facade and
160
- * classifies it as `QrCode` so its key does not collide with an announced
161
- * MetaMask browser-extension provider for the same wallet name. Drops
162
- * `connect` so the provider is filtered out of the wallet picker by
163
- * `getAvailableWalletProvidersData` — mirroring how WalletConnect URI
164
- * sessions register a signing-only provider.
275
+ * Warns when `addMetaMaskSolanaExtension()` hasn't been added, since a
276
+ * wallet connected via `connectWithMetaMaskUriSolana` without it won't be
277
+ * restored after a page reload.
165
278
  *
279
+ * @example
280
+ * ```ts
281
+ * warnMetaMaskSolanaIntegrationIncomplete(client);
282
+ * ```
283
+ * @param client - The Dynamic client instance.
284
+ * @returns void
285
+ * @see connectWithMetaMaskUriSolana
286
+ * @see addMetaMaskSolanaExtension
166
287
  * @notInstrumented
167
288
  */
168
- const createMetaMaskSolanaWalletProvider = async (client) => {
169
- const walletStandardWallet = (await getOrCreateMetaMaskSolanaController(client)).sdk.getWallet();
170
- if (walletStandardWallet.accounts.length === 0) throw new _dynamic_labs_sdk_metamask.MetaMaskWalletNotConnectedError();
171
- return {
172
- ...require_createWalletProviderFromSolanaStandardWallet.createWalletProviderFromSolanaStandardWallet({
173
- dynamicClient: client,
174
- walletProviderType: _dynamic_labs_sdk_api_core.WalletProviderEnum.QrCode,
175
- walletStandardWallet
176
- }),
177
- connect: void 0
178
- };
289
+ const warnMetaMaskSolanaIntegrationIncomplete = (client) => {
290
+ if ((0, _dynamic_labs_sdk_client_core.hasExtension)({ extensionKey: METAMASK_SOLANA_EXTENSION_KEY }, client)) return;
291
+ (0, _dynamic_labs_sdk_client_core.getCore)(client).logger.warn(`MetaMask integration is incomplete: addMetaMaskSolanaExtension() is missing. Add it during setup:
292
+
293
+ import { addMetaMaskSolanaExtension } from '@dynamic-labs-sdk/solana/metamask';
294
+ import { createDynamicClient } from '@dynamic-labs-sdk/client';
295
+
296
+ const client = createDynamicClient({ environmentId: '...' });
297
+
298
+ addMetaMaskSolanaExtension(client);`);
179
299
  };
180
300
 
181
301
  //#endregion
@@ -190,11 +310,11 @@ const createMetaMaskSolanaWalletProvider = async (client) => {
190
310
  * @notInstrumented
191
311
  */
192
312
  const connectWithMetaMaskUriSolana = ({ addToDynamicWalletAccounts = true } = {}, client = (0, _dynamic_labs_sdk_client.getDefaultClient)()) => {
313
+ warnMetaMaskSolanaIntegrationIncomplete(client);
193
314
  require_solanaTransferAmount.registerSolanaNetworkProviderBuilder(client);
194
315
  return (0, _dynamic_labs_sdk_metamask.connectWithMetaMaskUri)({
195
316
  addToDynamicWalletAccounts,
196
317
  chain: "SOL",
197
- getController: getOrCreateMetaMaskSolanaController,
198
318
  walletProviderBuilder: createMetaMaskSolanaWalletProvider
199
319
  }, client);
200
320
  };
@@ -250,12 +370,14 @@ const getMetaMaskSolanaExtensionWalletProviderKey = (client = (0, _dynamic_labs_
250
370
  (0, _dynamic_labs_sdk_assert_package_version.assertPackageVersion)(require_solanaTransferAmount.name, require_solanaTransferAmount.version);
251
371
 
252
372
  //#endregion
373
+ exports.MetaMaskDirectConnectNotSupportedError = MetaMaskDirectConnectNotSupportedError;
253
374
  Object.defineProperty(exports, 'MetaMaskDisplayUriMissingError', {
254
375
  enumerable: true,
255
376
  get: function () {
256
377
  return _dynamic_labs_sdk_metamask.MetaMaskDisplayUriMissingError;
257
378
  }
258
379
  });
380
+ exports.addMetaMaskSolanaExtension = addMetaMaskSolanaExtension;
259
381
  exports.connectAndVerifyWithMetaMaskUriSolana = connectAndVerifyWithMetaMaskUriSolana;
260
382
  exports.connectWithMetaMaskUriSolana = connectWithMetaMaskUriSolana;
261
383
  exports.getMetaMaskSolanaExtensionWalletProviderKey = getMetaMaskSolanaExtensionWalletProviderKey;