@turnkey/core 1.0.0-beta.2 → 1.0.0-beta.5

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 (89) hide show
  1. package/dist/__clients__/core.d.ts +92 -9
  2. package/dist/__clients__/core.d.ts.map +1 -1
  3. package/dist/__clients__/core.js +699 -535
  4. package/dist/__clients__/core.js.map +1 -1
  5. package/dist/__clients__/core.mjs +702 -538
  6. package/dist/__clients__/core.mjs.map +1 -1
  7. package/dist/__generated__/sdk-client-base.d.ts +1 -1
  8. package/dist/__generated__/sdk-client-base.d.ts.map +1 -1
  9. package/dist/__generated__/sdk-client-base.js +156 -253
  10. package/dist/__generated__/sdk-client-base.js.map +1 -1
  11. package/dist/__generated__/sdk-client-base.mjs +156 -253
  12. package/dist/__generated__/sdk-client-base.mjs.map +1 -1
  13. package/dist/__generated__/version.d.ts +1 -1
  14. package/dist/__generated__/version.js +1 -1
  15. package/dist/__generated__/version.mjs +1 -1
  16. package/dist/__inputs__/public_api.types.d.ts +377 -504
  17. package/dist/__inputs__/public_api.types.d.ts.map +1 -1
  18. package/dist/__types__/base.d.ts +193 -75
  19. package/dist/__types__/base.d.ts.map +1 -1
  20. package/dist/__types__/base.js +14 -13
  21. package/dist/__types__/base.js.map +1 -1
  22. package/dist/__types__/base.mjs +15 -14
  23. package/dist/__types__/base.mjs.map +1 -1
  24. package/dist/__wallet__/base.d.ts +11 -0
  25. package/dist/__wallet__/base.d.ts.map +1 -1
  26. package/dist/__wallet__/base.js +12 -1
  27. package/dist/__wallet__/base.js.map +1 -1
  28. package/dist/__wallet__/base.mjs +12 -1
  29. package/dist/__wallet__/base.mjs.map +1 -1
  30. package/dist/__wallet__/connector.d.ts +31 -4
  31. package/dist/__wallet__/connector.d.ts.map +1 -1
  32. package/dist/__wallet__/connector.js +35 -5
  33. package/dist/__wallet__/connector.js.map +1 -1
  34. package/dist/__wallet__/connector.mjs +35 -5
  35. package/dist/__wallet__/connector.mjs.map +1 -1
  36. package/dist/__wallet__/mobile/manager.d.ts +21 -5
  37. package/dist/__wallet__/mobile/manager.d.ts.map +1 -1
  38. package/dist/__wallet__/mobile/manager.js +28 -11
  39. package/dist/__wallet__/mobile/manager.js.map +1 -1
  40. package/dist/__wallet__/mobile/manager.mjs +28 -11
  41. package/dist/__wallet__/mobile/manager.mjs.map +1 -1
  42. package/dist/__wallet__/stamper.d.ts +73 -2
  43. package/dist/__wallet__/stamper.d.ts.map +1 -1
  44. package/dist/__wallet__/stamper.js +81 -15
  45. package/dist/__wallet__/stamper.js.map +1 -1
  46. package/dist/__wallet__/stamper.mjs +82 -16
  47. package/dist/__wallet__/stamper.mjs.map +1 -1
  48. package/dist/__wallet__/wallet-connect/base.d.ts +102 -19
  49. package/dist/__wallet__/wallet-connect/base.d.ts.map +1 -1
  50. package/dist/__wallet__/wallet-connect/base.js +198 -77
  51. package/dist/__wallet__/wallet-connect/base.js.map +1 -1
  52. package/dist/__wallet__/wallet-connect/base.mjs +198 -77
  53. package/dist/__wallet__/wallet-connect/base.mjs.map +1 -1
  54. package/dist/__wallet__/wallet-connect/client.d.ts +50 -17
  55. package/dist/__wallet__/wallet-connect/client.d.ts.map +1 -1
  56. package/dist/__wallet__/wallet-connect/client.js +76 -19
  57. package/dist/__wallet__/wallet-connect/client.js.map +1 -1
  58. package/dist/__wallet__/wallet-connect/client.mjs +76 -19
  59. package/dist/__wallet__/wallet-connect/client.mjs.map +1 -1
  60. package/dist/__wallet__/web/manager.d.ts +20 -12
  61. package/dist/__wallet__/web/manager.d.ts.map +1 -1
  62. package/dist/__wallet__/web/manager.js +29 -21
  63. package/dist/__wallet__/web/manager.js.map +1 -1
  64. package/dist/__wallet__/web/manager.mjs +29 -21
  65. package/dist/__wallet__/web/manager.mjs.map +1 -1
  66. package/dist/__wallet__/web/native/ethereum.d.ts +45 -11
  67. package/dist/__wallet__/web/native/ethereum.d.ts.map +1 -1
  68. package/dist/__wallet__/web/native/ethereum.js +58 -17
  69. package/dist/__wallet__/web/native/ethereum.js.map +1 -1
  70. package/dist/__wallet__/web/native/ethereum.mjs +58 -17
  71. package/dist/__wallet__/web/native/ethereum.mjs.map +1 -1
  72. package/dist/__wallet__/web/native/solana.d.ts +56 -3
  73. package/dist/__wallet__/web/native/solana.d.ts.map +1 -1
  74. package/dist/__wallet__/web/native/solana.js +95 -36
  75. package/dist/__wallet__/web/native/solana.js.map +1 -1
  76. package/dist/__wallet__/web/native/solana.mjs +95 -36
  77. package/dist/__wallet__/web/native/solana.mjs.map +1 -1
  78. package/dist/index.d.ts +2 -1
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +2 -10
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.mjs +2 -2
  83. package/dist/utils.d.ts +59 -13
  84. package/dist/utils.d.ts.map +1 -1
  85. package/dist/utils.js +105 -30
  86. package/dist/utils.js.map +1 -1
  87. package/dist/utils.mjs +103 -29
  88. package/dist/utils.mjs.map +1 -1
  89. package/package.json +8 -8
@@ -8,14 +8,28 @@ export declare class WalletConnectWallet implements WalletConnectInterface {
8
8
  private ethChain;
9
9
  private solChain;
10
10
  private uri?;
11
+ private changeListeners;
12
+ private addChangeListener;
13
+ private notifyChange;
14
+ /**
15
+ * Constructs a WalletConnectWallet bound to a WalletConnect client.
16
+ *
17
+ * - Subscribes to session deletions and automatically re-initiates pairing,
18
+ * updating `this.uri` so the UI can present a fresh QR/deeplink.
19
+ *
20
+ * @param client - The low-level WalletConnect client used for session/RPC.
21
+ */
11
22
  constructor(client: WalletConnectClient);
12
23
  /**
13
- * Initializes WalletConnect pairing flow with the specified chains.
14
- * If an active session already exists, pairing is skipped.
24
+ * Initializes WalletConnect pairing flow with the specified namespaces.
25
+ *
26
+ * - Saves the requested chain namespaces (e.g., `["eip155:1", "eip155:137", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"]`).
27
+ * - If an active session already has connected accounts, pairing is skipped.
28
+ * - Otherwise initiates a pairing and stores the resulting URI.
15
29
  *
16
- * @param opts.ethereum - Whether to enable Ethereum pairing
17
- * @param opts.solana - Whether to enable Solana pairing
18
- * @throws {Error} If no chains are enabled
30
+ * @param opts.ethereumNamespaces - List of EVM CAIP IDs (e.g., "eip155:1").
31
+ * @param opts.solanaNamespaces - List of Solana CAIP IDs (e.g., "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp").
32
+ * @throws {Error} If no namespaces are provided for either chain.
19
33
  */
20
34
  init(opts: {
21
35
  ethereumNamespaces: string[];
@@ -23,61 +37,130 @@ export declare class WalletConnectWallet implements WalletConnectInterface {
23
37
  }): Promise<void>;
24
38
  /**
25
39
  * Returns WalletConnect providers with associated chain/account metadata.
40
+ *
41
+ * - Builds an EVM provider (if Ethereum namespaces are enabled).
42
+ * - Builds a Solana provider (if Solana namespaces are enabled).
43
+ *
44
+ * @returns A promise resolving to an array of WalletProvider objects.
26
45
  */
27
46
  getProviders(): Promise<WalletProvider[]>;
28
47
  /**
29
48
  * Approves the session if needed and ensures at least one account is available.
49
+ *
50
+ * - Calls `approve()` on the underlying client when pairing is pending.
51
+ * - Throws if the approved session contains no connected accounts.
52
+ *
53
+ * @param _provider - Unused (present for interface compatibility).
54
+ * @throws {Error} If the session contains no accounts.
30
55
  */
31
56
  connectWalletAccount(_provider: WalletProvider): Promise<void>;
32
57
  /**
33
- * Switch the user’s WalletConnect session to a new EVM chain.
58
+ * Switches the user’s WalletConnect session to a new EVM chain.
34
59
  *
35
- * @param provider – the WalletProvider returned by getProviders()
36
- * @param chainOrId – either:
37
- * a CAIP string ("eip155:1", "eip155:137", …)
38
- * a SwitchableChain object carrying full metadata
60
+ * - Ethereum-only: only supported for providers on the Ethereum namespace.
61
+ * - No add-then-switch: WalletConnect cannot add chains mid-session. The target chain
62
+ * must be present in `ethereumNamespaces` negotiated at pairing time. To support a new chain,
63
+ * you must include it in the walletConfig.
64
+ * - Accepts a hex chain ID (e.g., "0x1"). If a `SwitchableChain` is passed, only its `id`
65
+ * (hex chain ID) is used; metadata is ignored for WalletConnect.
66
+ *
67
+ * @param provider - The WalletProvider returned by `getProviders()`.
68
+ * @param chainOrId - Hex chain ID (e.g., "0x1") or a `SwitchableChain` (its `id` is used).
69
+ * @returns A promise that resolves when the switch completes.
70
+ * @throws {Error} If no active session, provider is non-EVM, the chain is not in `ethereumNamespaces`,
71
+ * or the switch RPC fails.
39
72
  */
40
73
  switchChain(provider: WalletProvider, chainOrId: string | SwitchableChain): Promise<void>;
41
74
  /**
42
- * Signs a message or transaction using the specified provider and intent.
75
+ * Signs a message or transaction using the specified wallet provider and intent.
76
+ *
77
+ * - Ensures an active WalletConnect session:
78
+ * - If a pairing is in progress (URI shown but not yet approved), this call will
79
+ * wait for the user to approve the session and may appear stuck until they do.
80
+ * - If no pairing is in progress, this will throw (e.g., "call pair() before approve()").
81
+ * - Ethereum:
82
+ * - `SignMessage` → `personal_sign` (returns hex signature).
83
+ * - `SignAndSendTransaction` → `eth_sendTransaction` (returns tx hash).
84
+ * - Solana:
85
+ * - `SignMessage` → `solana_signMessage` (returns hex signature).
86
+ * - `SignTransaction` → `solana_signTransaction` (returns hex signature).
87
+ * - `SignAndSendTransaction` → `solana_sendTransaction` (returns hex signature of the submitted tx).
43
88
  *
44
- * @param message - The message or serialized transaction to sign.
89
+ * @param payload - Payload or serialized transaction to sign.
45
90
  * @param provider - The WalletProvider to use.
46
- * @param intent - The type of signing intent (message, tx, send).
91
+ * @param intent - The signing intent.
92
+ * @returns A hex string (signature or transaction hash, depending on intent).
93
+ * @throws {Error} If no account is available, no pairing is in progress, or the intent is unsupported.
47
94
  */
48
- sign(message: string, provider: WalletProvider, intent: SignIntent): Promise<string>;
95
+ sign(payload: string, provider: WalletProvider, intent: SignIntent): Promise<string>;
49
96
  /**
50
97
  * Retrieves the public key of the connected wallet.
51
98
  *
99
+ * - Ethereum: signs a fixed challenge and recovers the compressed secp256k1 public key.
100
+ * - Solana: decodes the base58-encoded address to raw bytes.
101
+ *
52
102
  * @param provider - The WalletProvider to fetch the key from.
53
- * @returns Compressed public key as a hex string.
103
+ * @returns A compressed public key as a hex string.
104
+ * @throws {Error} If no account is available or the namespace is unsupported.
54
105
  */
55
106
  getPublicKey(provider: WalletProvider): Promise<string>;
56
107
  /**
57
108
  * Disconnects the current session and re-initiates a fresh pairing URI.
109
+ *
110
+ * - Calls `disconnect()` on the client, then `pair()` with current namespaces.
111
+ * - Updates `this.uri` so the UI can present a new QR/deeplink.
58
112
  */
59
113
  disconnectWalletAccount(_provider: WalletProvider): Promise<void>;
60
114
  /**
61
115
  * Builds a lightweight provider interface for the given chain.
62
116
  *
63
- * @param chainId - The namespace chain ID (e.g., eip155:1)
64
- * @returns A WalletConnect-compatible provider implementation
117
+ * @param chainId - Namespace chain ID (e.g., "eip155:1" or "solana:101").
118
+ * @returns A WalletConnect-compatible provider that proxies JSON-RPC via WC.
65
119
  */
66
120
  private makeProvider;
67
121
  /**
68
122
  * Ensures there is an active WalletConnect session, initiating approval if necessary.
69
123
  *
70
- * @returns The current WalletConnect session
71
- * @throws {Error} If approval fails or session is not established
124
+ * - If a session exists, returns it immediately.
125
+ * - If no session exists but a pairing is in progress, awaits `approve()` —
126
+ * this will block until the user approves (or rejects) in their wallet.
127
+ * - If no session exists and no pairing is in progress, throws; the caller
128
+ * must have initiated pairing via `pair()` elsewhere.
129
+ *
130
+ * @returns The active WalletConnect session.
131
+ * @throws {Error} If approval is rejected, completes without establishing a session,
132
+ * or no pairing is in progress.
72
133
  */
73
134
  private ensureSession;
74
135
  /**
75
136
  * Builds a WalletProvider descriptor for an EVM chain.
137
+ *
138
+ * - Extracts the connected address (if any) and current chain ID.
139
+ * - Includes the pairing `uri` if available.
140
+ *
141
+ * @param session - Current WalletConnect session (or null).
142
+ * @param info - Provider branding info (name, icon).
143
+ * @returns A WalletProvider object for Ethereum.
76
144
  */
77
145
  private buildEthProvider;
78
146
  /**
79
147
  * Builds a WalletProvider descriptor for Solana.
148
+ *
149
+ * - Extracts the connected address (if any).
150
+ * - Includes the fresh pairing `uri` if available.
151
+ *
152
+ * @param session - Current WalletConnect session (or null).
153
+ * @param info - Provider branding info (name, icon).
154
+ * @returns A WalletProvider object for Solana.
80
155
  */
81
156
  private buildSolProvider;
157
+ /**
158
+ * Builds the requested WalletConnect namespaces from the current config.
159
+ *
160
+ * - Includes methods and events for Ethereum and/or Solana based on enabled namespaces.
161
+ *
162
+ * @returns A namespaces object suitable for `WalletConnectClient.pair()`.
163
+ */
164
+ private buildNamespaces;
82
165
  }
83
166
  //# sourceMappingURL=base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/__wallet__/wallet-connect/base.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,mBAAmB,EACnB,cAAc,EAEd,UAAU,EAEV,sBAAsB,EACtB,eAAe,EAChB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAIpD,qBAAa,mBAAoB,YAAW,sBAAsB;IAWpD,OAAO,CAAC,MAAM;IAV1B,QAAQ,CAAC,aAAa,qCAAqC;IAE3D,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IAExC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,QAAQ,CAAU;IAE1B,OAAO,CAAC,GAAG,CAAC,CAAS;gBAED,MAAM,EAAE,mBAAmB;IAI/C;;;;;;;OAOG;IACG,IAAI,CAAC,IAAI,EAAE;QACf,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDjB;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAqB/C;;OAEG;IACG,oBAAoB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE;;;;;;;OAOG;IACG,WAAW,CACf,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,GAAG,eAAe,GAClC,OAAO,CAAC,IAAI,CAAC;IAmChB;;;;;;OAMG;IACG,IAAI,CACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,MAAM,CAAC;IAuGlB;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAyC7D;;OAEG;IACG,uBAAuB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCvE;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;;OAKG;YACW,aAAa;IAU3B;;OAEG;YACW,gBAAgB;IAwB9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAgBzB"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/__wallet__/wallet-connect/base.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,mBAAmB,EACnB,cAAc,EAEd,UAAU,EAEV,sBAAsB,EACtB,eAAe,EAChB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AASpD,qBAAa,mBAAoB,YAAW,sBAAsB;IAkCpD,OAAO,CAAC,MAAM;IAjC1B,QAAQ,CAAC,aAAa,qCAAqC;IAE3D,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IAExC,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,QAAQ,CAAU;IAE1B,OAAO,CAAC,GAAG,CAAC,CAAS;IAErB,OAAO,CAAC,eAAe,CAEnB;IAEJ,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,YAAY;IAIpB;;;;;;;OAOG;gBACiB,MAAM,EAAE,mBAAmB;IAuB/C;;;;;;;;;;OAUG;IACG,IAAI,CAAC,IAAI,EAAE;QACf,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCjB;;;;;;;OAOG;IACG,YAAY,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAqB/C;;;;;;;;OAQG;IACG,oBAAoB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE;;;;;;;;;;;;;;;OAeG;IACG,WAAW,CACf,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,GAAG,eAAe,GAClC,OAAO,CAAC,IAAI,CAAC;IAmChB;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,IAAI,CACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,MAAM,CAAC;IAuGlB;;;;;;;;;OASG;IACG,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAyC7D;;;;;OAKG;IACG,uBAAuB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvE;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAepB;;;;;;;;;;;;OAYG;YACW,aAAa;IAU3B;;;;;;;;;OASG;YACW,gBAAgB;IAwB9B;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;CA+BxB"}
@@ -8,20 +8,55 @@ var base = require('../../__types__/base.js');
8
8
  var ethers = require('ethers');
9
9
 
10
10
  class WalletConnectWallet {
11
+ addChangeListener(listener) {
12
+ this.changeListeners.add(listener);
13
+ return () => this.changeListeners.delete(listener);
14
+ }
15
+ notifyChange(event) {
16
+ this.changeListeners.forEach((listener) => listener(event));
17
+ }
18
+ /**
19
+ * Constructs a WalletConnectWallet bound to a WalletConnect client.
20
+ *
21
+ * - Subscribes to session deletions and automatically re-initiates pairing,
22
+ * updating `this.uri` so the UI can present a fresh QR/deeplink.
23
+ *
24
+ * @param client - The low-level WalletConnect client used for session/RPC.
25
+ */
11
26
  constructor(client) {
12
27
  this.client = client;
13
28
  this.interfaceType = base.WalletInterfaceType.WalletConnect;
14
29
  this.ethereumNamespaces = [];
15
30
  this.solanaNamespaces = [];
16
- this.client.onSessionDelete(() => { });
31
+ this.changeListeners = new Set();
32
+ // session disconnected
33
+ this.client.onSessionDelete(() => {
34
+ this.notifyChange({ type: "disconnect" });
35
+ });
36
+ // session updated (actual update to the session for example adding a chain to namespaces)
37
+ this.client.onSessionUpdate(() => {
38
+ this.notifyChange({ type: "update" });
39
+ });
40
+ // chain switched
41
+ this.client.onSessionEvent(({ event }) => {
42
+ if (event?.name === "chainChanged" || event?.name === "accountsChanged") {
43
+ const chainId = typeof event.data?.chainId === "string"
44
+ ? event.data.chainId
45
+ : undefined;
46
+ this.notifyChange({ type: "chainChanged", chainId });
47
+ }
48
+ });
17
49
  }
18
50
  /**
19
- * Initializes WalletConnect pairing flow with the specified chains.
20
- * If an active session already exists, pairing is skipped.
51
+ * Initializes WalletConnect pairing flow with the specified namespaces.
21
52
  *
22
- * @param opts.ethereum - Whether to enable Ethereum pairing
23
- * @param opts.solana - Whether to enable Solana pairing
24
- * @throws {Error} If no chains are enabled
53
+ * - Saves the requested chain namespaces (e.g., `["eip155:1", "eip155:137", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"]`).
54
+ * - If an active session already has connected accounts, pairing is skipped.
55
+ * - Otherwise initiates a pairing and stores the resulting URI.
56
+ *
57
+ * @param opts.ethereumNamespaces - List of EVM CAIP IDs (e.g., "eip155:1").
58
+ * @param opts.solanaNamespaces - List of Solana CAIP IDs (e.g., "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp").
59
+ * @throws {Error} If no namespaces are provided for either chain.
25
60
  */
26
61
  async init(opts) {
27
62
  this.ethereumNamespaces = opts.ethereumNamespaces;
@@ -36,39 +71,23 @@ class WalletConnectWallet {
36
71
  this.solanaNamespaces.length === 0) {
37
72
  throw new Error("At least one namespace must be enabled for WalletConnect");
38
73
  }
74
+ // we don't want to create more than one active session
75
+ // so we don't make a pair request if one is already active
76
+ // since pairing would mean initializing a new session
39
77
  const session = this.client.getSession();
40
78
  if (hasConnectedAccounts(session)) {
41
79
  return;
42
80
  }
43
- const namespaces = {};
44
- if (this.ethereumNamespaces.length > 0) {
45
- namespaces.eip155 = {
46
- methods: [
47
- "personal_sign",
48
- "eth_sendTransaction",
49
- "eth_chainId",
50
- "wallet_switchEthereumChain",
51
- "wallet_addEthereumChain",
52
- ],
53
- chains: this.ethereumNamespaces,
54
- events: ["accountsChanged", "chainChanged"],
55
- };
56
- }
57
- if (this.solanaNamespaces.length > 0) {
58
- namespaces.solana = {
59
- methods: [
60
- "solana_signMessage",
61
- "solana_signTransaction",
62
- "solana_sendTransaction",
63
- ],
64
- chains: this.solanaNamespaces,
65
- events: ["accountsChanged", "chainChanged"],
66
- };
67
- }
81
+ const namespaces = this.buildNamespaces();
68
82
  this.uri = await this.client.pair(namespaces);
69
83
  }
70
84
  /**
71
85
  * Returns WalletConnect providers with associated chain/account metadata.
86
+ *
87
+ * - Builds an EVM provider (if Ethereum namespaces are enabled).
88
+ * - Builds a Solana provider (if Solana namespaces are enabled).
89
+ *
90
+ * @returns A promise resolving to an array of WalletProvider objects.
72
91
  */
73
92
  async getProviders() {
74
93
  const session = this.client.getSession();
@@ -87,6 +106,12 @@ class WalletConnectWallet {
87
106
  }
88
107
  /**
89
108
  * Approves the session if needed and ensures at least one account is available.
109
+ *
110
+ * - Calls `approve()` on the underlying client when pairing is pending.
111
+ * - Throws if the approved session contains no connected accounts.
112
+ *
113
+ * @param _provider - Unused (present for interface compatibility).
114
+ * @throws {Error} If the session contains no accounts.
90
115
  */
91
116
  async connectWalletAccount(_provider) {
92
117
  const session = await this.client.approve();
@@ -94,12 +119,20 @@ class WalletConnectWallet {
94
119
  throw new Error("No account found in session");
95
120
  }
96
121
  /**
97
- * Switch the user’s WalletConnect session to a new EVM chain.
122
+ * Switches the user’s WalletConnect session to a new EVM chain.
123
+ *
124
+ * - Ethereum-only: only supported for providers on the Ethereum namespace.
125
+ * - No add-then-switch: WalletConnect cannot add chains mid-session. The target chain
126
+ * must be present in `ethereumNamespaces` negotiated at pairing time. To support a new chain,
127
+ * you must include it in the walletConfig.
128
+ * - Accepts a hex chain ID (e.g., "0x1"). If a `SwitchableChain` is passed, only its `id`
129
+ * (hex chain ID) is used; metadata is ignored for WalletConnect.
98
130
  *
99
- * @param provider the WalletProvider returned by getProviders()
100
- * @param chainOrId either:
101
- * a CAIP string ("eip155:1", "eip155:137", …)
102
- * a SwitchableChain object carrying full metadata
131
+ * @param provider - The WalletProvider returned by `getProviders()`.
132
+ * @param chainOrId - Hex chain ID (e.g., "0x1") or a `SwitchableChain` (its `id` is used).
133
+ * @returns A promise that resolves when the switch completes.
134
+ * @throws {Error} If no active session, provider is non-EVM, the chain is not in `ethereumNamespaces`,
135
+ * or the switch RPC fails.
103
136
  */
104
137
  async switchChain(provider, chainOrId) {
105
138
  if (provider.chainInfo.namespace !== base.Chain.Ethereum) {
@@ -126,13 +159,27 @@ class WalletConnectWallet {
126
159
  }
127
160
  }
128
161
  /**
129
- * Signs a message or transaction using the specified provider and intent.
162
+ * Signs a message or transaction using the specified wallet provider and intent.
130
163
  *
131
- * @param message - The message or serialized transaction to sign.
164
+ * - Ensures an active WalletConnect session:
165
+ * - If a pairing is in progress (URI shown but not yet approved), this call will
166
+ * wait for the user to approve the session and may appear stuck until they do.
167
+ * - If no pairing is in progress, this will throw (e.g., "call pair() before approve()").
168
+ * - Ethereum:
169
+ * - `SignMessage` → `personal_sign` (returns hex signature).
170
+ * - `SignAndSendTransaction` → `eth_sendTransaction` (returns tx hash).
171
+ * - Solana:
172
+ * - `SignMessage` → `solana_signMessage` (returns hex signature).
173
+ * - `SignTransaction` → `solana_signTransaction` (returns hex signature).
174
+ * - `SignAndSendTransaction` → `solana_sendTransaction` (returns hex signature of the submitted tx).
175
+ *
176
+ * @param payload - Payload or serialized transaction to sign.
132
177
  * @param provider - The WalletProvider to use.
133
- * @param intent - The type of signing intent (message, tx, send).
178
+ * @param intent - The signing intent.
179
+ * @returns A hex string (signature or transaction hash, depending on intent).
180
+ * @throws {Error} If no account is available, no pairing is in progress, or the intent is unsupported.
134
181
  */
135
- async sign(message, provider, intent) {
182
+ async sign(payload, provider, intent) {
136
183
  const session = await this.ensureSession();
137
184
  if (!hasConnectedAccounts(session)) {
138
185
  await this.connectWalletAccount(provider);
@@ -145,12 +192,12 @@ class WalletConnectWallet {
145
192
  switch (intent) {
146
193
  case base.SignIntent.SignMessage:
147
194
  return (await this.client.request(this.ethChain, "personal_sign", [
148
- message,
195
+ payload,
149
196
  address,
150
197
  ]));
151
198
  case base.SignIntent.SignAndSendTransaction:
152
199
  const account = provider.connectedAddresses[0];
153
- const tx = ethers.Transaction.from(message);
200
+ const tx = ethers.Transaction.from(payload);
154
201
  const txParams = {
155
202
  from: account,
156
203
  to: tx.to?.toString(),
@@ -174,7 +221,7 @@ class WalletConnectWallet {
174
221
  }
175
222
  switch (intent) {
176
223
  case base.SignIntent.SignMessage: {
177
- const msgBytes = new TextEncoder().encode(message);
224
+ const msgBytes = new TextEncoder().encode(payload);
178
225
  const msgB58 = bs58.encode(msgBytes);
179
226
  const { signature: sigB58 } = await this.client.request(this.solChain, "solana_signMessage", {
180
227
  pubkey: address,
@@ -183,7 +230,7 @@ class WalletConnectWallet {
183
230
  return encoding.uint8ArrayToHexString(bs58.decode(sigB58));
184
231
  }
185
232
  case base.SignIntent.SignTransaction: {
186
- const txBytes = encoding.uint8ArrayFromHexString(message);
233
+ const txBytes = encoding.uint8ArrayFromHexString(payload);
187
234
  const txBase64 = encoding.stringToBase64urlString(String.fromCharCode(...txBytes));
188
235
  const { signature: sigB58 } = await this.client.request(this.solChain, "solana_signTransaction", {
189
236
  feePayer: address,
@@ -192,7 +239,7 @@ class WalletConnectWallet {
192
239
  return encoding.uint8ArrayToHexString(bs58.decode(sigB58));
193
240
  }
194
241
  case base.SignIntent.SignAndSendTransaction: {
195
- const txBytes = encoding.uint8ArrayFromHexString(message);
242
+ const txBytes = encoding.uint8ArrayFromHexString(payload);
196
243
  const txBase64 = encoding.stringToBase64urlString(String.fromCharCode(...txBytes));
197
244
  const sigB58 = await this.client.request(this.solChain, "solana_sendTransaction", {
198
245
  feePayer: address,
@@ -210,8 +257,12 @@ class WalletConnectWallet {
210
257
  /**
211
258
  * Retrieves the public key of the connected wallet.
212
259
  *
260
+ * - Ethereum: signs a fixed challenge and recovers the compressed secp256k1 public key.
261
+ * - Solana: decodes the base58-encoded address to raw bytes.
262
+ *
213
263
  * @param provider - The WalletProvider to fetch the key from.
214
- * @returns Compressed public key as a hex string.
264
+ * @returns A compressed public key as a hex string.
265
+ * @throws {Error} If no account is available or the namespace is unsupported.
215
266
  */
216
267
  async getPublicKey(provider) {
217
268
  const session = this.client.getSession();
@@ -247,34 +298,13 @@ class WalletConnectWallet {
247
298
  }
248
299
  /**
249
300
  * Disconnects the current session and re-initiates a fresh pairing URI.
301
+ *
302
+ * - Calls `disconnect()` on the client, then `pair()` with current namespaces.
303
+ * - Updates `this.uri` so the UI can present a new QR/deeplink.
250
304
  */
251
305
  async disconnectWalletAccount(_provider) {
252
306
  await this.client.disconnect();
253
- const namespaces = {};
254
- if (this.ethereumNamespaces.length > 0) {
255
- namespaces.eip155 = {
256
- methods: [
257
- "personal_sign",
258
- "eth_sendTransaction",
259
- "eth_chainId",
260
- "wallet_switchEthereumChain",
261
- "wallet_addEthereumChain",
262
- ],
263
- chains: this.ethereumNamespaces,
264
- events: ["accountsChanged", "chainChanged"],
265
- };
266
- }
267
- if (this.solanaNamespaces.length > 0) {
268
- namespaces.solana = {
269
- methods: [
270
- "solana_signMessage",
271
- "solana_signTransaction",
272
- "solana_sendTransaction",
273
- ],
274
- chains: this.solanaNamespaces,
275
- events: ["accountsChanged", "chainChanged"],
276
- };
277
- }
307
+ const namespaces = this.buildNamespaces();
278
308
  await this.client.pair(namespaces).then((newUri) => {
279
309
  this.uri = newUri;
280
310
  });
@@ -282,21 +312,35 @@ class WalletConnectWallet {
282
312
  /**
283
313
  * Builds a lightweight provider interface for the given chain.
284
314
  *
285
- * @param chainId - The namespace chain ID (e.g., eip155:1)
286
- * @returns A WalletConnect-compatible provider implementation
315
+ * @param chainId - Namespace chain ID (e.g., "eip155:1" or "solana:101").
316
+ * @returns A WalletConnect-compatible provider that proxies JSON-RPC via WC.
287
317
  */
288
318
  makeProvider(chainId) {
289
319
  return {
290
- request: ({ method, params }) => {
291
- return this.client.request(chainId, method, params);
320
+ request: ({ method, params }) => this.client.request(chainId, method, params),
321
+ features: {
322
+ "standard:events": {
323
+ on: (event, callback) => {
324
+ if (event !== "change")
325
+ return () => { };
326
+ return this.addChangeListener(callback);
327
+ },
328
+ },
292
329
  },
293
330
  };
294
331
  }
295
332
  /**
296
333
  * Ensures there is an active WalletConnect session, initiating approval if necessary.
297
334
  *
298
- * @returns The current WalletConnect session
299
- * @throws {Error} If approval fails or session is not established
335
+ * - If a session exists, returns it immediately.
336
+ * - If no session exists but a pairing is in progress, awaits `approve()` —
337
+ * this will block until the user approves (or rejects) in their wallet.
338
+ * - If no session exists and no pairing is in progress, throws; the caller
339
+ * must have initiated pairing via `pair()` elsewhere.
340
+ *
341
+ * @returns The active WalletConnect session.
342
+ * @throws {Error} If approval is rejected, completes without establishing a session,
343
+ * or no pairing is in progress.
300
344
  */
301
345
  async ensureSession() {
302
346
  let session = this.client.getSession();
@@ -310,6 +354,13 @@ class WalletConnectWallet {
310
354
  }
311
355
  /**
312
356
  * Builds a WalletProvider descriptor for an EVM chain.
357
+ *
358
+ * - Extracts the connected address (if any) and current chain ID.
359
+ * - Includes the pairing `uri` if available.
360
+ *
361
+ * @param session - Current WalletConnect session (or null).
362
+ * @param info - Provider branding info (name, icon).
363
+ * @returns A WalletProvider object for Ethereum.
313
364
  */
314
365
  async buildEthProvider(session, info) {
315
366
  const raw = session?.namespaces.eip155?.accounts?.[0] ?? "";
@@ -331,6 +382,13 @@ class WalletConnectWallet {
331
382
  }
332
383
  /**
333
384
  * Builds a WalletProvider descriptor for Solana.
385
+ *
386
+ * - Extracts the connected address (if any).
387
+ * - Includes the fresh pairing `uri` if available.
388
+ *
389
+ * @param session - Current WalletConnect session (or null).
390
+ * @param info - Provider branding info (name, icon).
391
+ * @returns A WalletProvider object for Solana.
334
392
  */
335
393
  buildSolProvider(session, info) {
336
394
  const raw = session?.namespaces.solana?.accounts?.[0] ?? "";
@@ -344,15 +402,78 @@ class WalletConnectWallet {
344
402
  ...(this.uri && { uri: this.uri }),
345
403
  };
346
404
  }
405
+ /**
406
+ * Builds the requested WalletConnect namespaces from the current config.
407
+ *
408
+ * - Includes methods and events for Ethereum and/or Solana based on enabled namespaces.
409
+ *
410
+ * @returns A namespaces object suitable for `WalletConnectClient.pair()`.
411
+ */
412
+ buildNamespaces() {
413
+ const namespaces = {};
414
+ if (this.ethereumNamespaces.length > 0) {
415
+ namespaces.eip155 = {
416
+ methods: [
417
+ "personal_sign",
418
+ "eth_sendTransaction",
419
+ "eth_chainId",
420
+ "wallet_switchEthereumChain",
421
+ "wallet_addEthereumChain",
422
+ ],
423
+ chains: this.ethereumNamespaces,
424
+ events: ["accountsChanged", "chainChanged"],
425
+ };
426
+ }
427
+ if (this.solanaNamespaces.length > 0) {
428
+ namespaces.solana = {
429
+ methods: [
430
+ "solana_signMessage",
431
+ "solana_signTransaction",
432
+ "solana_sendTransaction",
433
+ ],
434
+ chains: this.solanaNamespaces,
435
+ events: ["accountsChanged", "chainChanged"],
436
+ };
437
+ }
438
+ return namespaces;
439
+ }
347
440
  }
441
+ /**
442
+ * Determines whether the session has at least one connected account
443
+ * across any namespace.
444
+ *
445
+ * - Safe to call with `null` (returns `false`).
446
+ * - Checks all namespaces for a non-empty `accounts` array.
447
+ *
448
+ * @param session - The current WalletConnect session, or `null`.
449
+ * @returns `true` if any namespace has ≥1 account; otherwise `false`.
450
+ */
348
451
  function hasConnectedAccounts(session) {
349
452
  return (!!session &&
350
453
  Object.values(session.namespaces).some((ns) => ns.accounts?.length > 0));
351
454
  }
455
+ /**
456
+ * Retrieves the first connected Ethereum account.
457
+ *
458
+ * - Safe to call with `null` (returns `undefined`).
459
+ * - Returns only the address portion (e.g., `0xabc...`), not the full CAIP string.
460
+ *
461
+ * @param session - The current WalletConnect session, or `null`.
462
+ * @returns The connected EVM address, or `undefined` if none.
463
+ */
352
464
  function getConnectedEthereum(session) {
353
465
  const acc = session?.namespaces.eip155?.accounts?.[0];
354
466
  return acc ? acc.split(":")[2] : undefined;
355
467
  }
468
+ /**
469
+ * Retrieves the first connected Solana account.
470
+ *
471
+ * - Safe to call with `null` (returns `undefined`).
472
+ * - Returns only the base58 address portion, not the full CAIP string.
473
+ *
474
+ * @param session - The current WalletConnect session, or `null`.
475
+ * @returns The connected Solana address (base58), or `undefined` if none.
476
+ */
356
477
  function getConnectedSolana(session) {
357
478
  const acc = session?.namespaces.solana?.accounts?.[0];
358
479
  return acc ? acc.split(":")[2] : undefined;