@meshconnect/uwc-wallet-connect-connector 0.2.0

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 (56) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +2 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/services/connection-service.d.ts +60 -0
  6. package/dist/services/connection-service.d.ts.map +1 -0
  7. package/dist/services/connection-service.js +235 -0
  8. package/dist/services/connection-service.js.map +1 -0
  9. package/dist/services/network-switch-service.d.ts +16 -0
  10. package/dist/services/network-switch-service.d.ts.map +1 -0
  11. package/dist/services/network-switch-service.js +71 -0
  12. package/dist/services/network-switch-service.js.map +1 -0
  13. package/dist/services/signature-service.d.ts +15 -0
  14. package/dist/services/signature-service.d.ts.map +1 -0
  15. package/dist/services/signature-service.js +102 -0
  16. package/dist/services/signature-service.js.map +1 -0
  17. package/dist/services/transaction-service.d.ts +33 -0
  18. package/dist/services/transaction-service.d.ts.map +1 -0
  19. package/dist/services/transaction-service.js +287 -0
  20. package/dist/services/transaction-service.js.map +1 -0
  21. package/dist/services/walletconnect-client.d.ts +28 -0
  22. package/dist/services/walletconnect-client.d.ts.map +1 -0
  23. package/dist/services/walletconnect-client.js +92 -0
  24. package/dist/services/walletconnect-client.js.map +1 -0
  25. package/dist/utils/account-utils.d.ts +41 -0
  26. package/dist/utils/account-utils.d.ts.map +1 -0
  27. package/dist/utils/account-utils.js +81 -0
  28. package/dist/utils/account-utils.js.map +1 -0
  29. package/dist/utils/encoding-utils.d.ts +6 -0
  30. package/dist/utils/encoding-utils.d.ts.map +1 -0
  31. package/dist/utils/encoding-utils.js +27 -0
  32. package/dist/utils/encoding-utils.js.map +1 -0
  33. package/dist/utils/error-utils.d.ts +6 -0
  34. package/dist/utils/error-utils.d.ts.map +1 -0
  35. package/dist/utils/error-utils.js +55 -0
  36. package/dist/utils/error-utils.js.map +1 -0
  37. package/dist/utils/solana-transactions.d.ts +4 -0
  38. package/dist/utils/solana-transactions.d.ts.map +1 -0
  39. package/dist/utils/solana-transactions.js +15 -0
  40. package/dist/utils/solana-transactions.js.map +1 -0
  41. package/dist/wallet-connect-connector.d.ts +17 -0
  42. package/dist/wallet-connect-connector.d.ts.map +1 -0
  43. package/dist/wallet-connect-connector.js +47 -0
  44. package/dist/wallet-connect-connector.js.map +1 -0
  45. package/package.json +41 -0
  46. package/src/index.ts +1 -0
  47. package/src/services/connection-service.ts +304 -0
  48. package/src/services/network-switch-service.ts +83 -0
  49. package/src/services/signature-service.ts +128 -0
  50. package/src/services/transaction-service.ts +397 -0
  51. package/src/services/walletconnect-client.ts +103 -0
  52. package/src/utils/account-utils.ts +116 -0
  53. package/src/utils/encoding-utils.ts +32 -0
  54. package/src/utils/error-utils.ts +62 -0
  55. package/src/utils/solana-transactions.ts +24 -0
  56. package/src/wallet-connect-connector.ts +83 -0
@@ -0,0 +1,55 @@
1
+ import { WalletConnectorError } from '@meshconnect/uwc-types';
2
+ /**
3
+ * Parse an error and throw a WalletConnectorError
4
+ * Detects if the error is a user rejection or an unknown error
5
+ */
6
+ export function parseError(error) {
7
+ let message;
8
+ let isRejected = false;
9
+ // Handle different error formats
10
+ if (error && typeof error === 'object') {
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const errorObj = error;
13
+ // Check for EIP-1193 error code
14
+ if (errorObj.code === 4001 || errorObj.code === 'ACTION_REJECTED') {
15
+ isRejected = true;
16
+ }
17
+ // Extract message
18
+ if (errorObj.message) {
19
+ message = errorObj.message;
20
+ }
21
+ else if (errorObj.error?.message) {
22
+ message = errorObj.error.message;
23
+ }
24
+ else {
25
+ message = String(error);
26
+ }
27
+ }
28
+ else {
29
+ message = String(error);
30
+ }
31
+ // If not already marked as rejected, check message patterns
32
+ if (!isRejected) {
33
+ const rejectionPatterns = [
34
+ 'user rejected',
35
+ 'user denied',
36
+ 'user cancelled',
37
+ 'user canceled',
38
+ 'rejected by user',
39
+ 'denied by user',
40
+ 'cancelled by user',
41
+ 'canceled by user',
42
+ 'user disapproved',
43
+ 'user declined',
44
+ 'action_rejected'
45
+ ];
46
+ const lowerMessage = message.toLowerCase();
47
+ isRejected = rejectionPatterns.some(pattern => lowerMessage.includes(pattern.toLowerCase()));
48
+ }
49
+ const walletError = {
50
+ type: isRejected ? 'rejected' : 'unknown',
51
+ message
52
+ };
53
+ throw new WalletConnectorError(walletError);
54
+ }
55
+ //# sourceMappingURL=error-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-utils.js","sourceRoot":"","sources":["../../src/utils/error-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,OAAe,CAAA;IACnB,IAAI,UAAU,GAAG,KAAK,CAAA;IAEtB,iCAAiC;IACjC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,8DAA8D;QAC9D,MAAM,QAAQ,GAAG,KAAY,CAAA;QAE7B,gCAAgC;QAChC,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAClE,UAAU,GAAG,IAAI,CAAA;QACnB,CAAC;QAED,kBAAkB;QAClB,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrB,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAA;QAC5B,CAAC;aAAM,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;YACnC,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAA;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,iBAAiB,GAAG;YACxB,eAAe;YACf,aAAa;YACb,gBAAgB;YAChB,eAAe;YACf,kBAAkB;YAClB,gBAAgB;YAChB,mBAAmB;YACnB,kBAAkB;YAClB,kBAAkB;YAClB,eAAe;YACf,iBAAiB;SAClB,CAAA;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;QAC1C,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAC5C,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAC7C,CAAA;IACH,CAAC;IAED,MAAM,WAAW,GAAgB;QAC/B,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;QACzC,OAAO;KACR,CAAA;IAED,MAAM,IAAI,oBAAoB,CAAC,WAAW,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SolanaNativeTransferRequest } from '@meshconnect/uwc-types';
2
+ import { Transaction } from '@solana/web3.js';
3
+ export declare function getSolanaTransaction(params: SolanaNativeTransferRequest): Transaction;
4
+ //# sourceMappingURL=solana-transactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana-transactions.d.ts","sourceRoot":"","sources":["../../src/utils/solana-transactions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAGL,WAAW,EAEZ,MAAM,iBAAiB,CAAA;AAExB,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,2BAA2B,eAevE"}
@@ -0,0 +1,15 @@
1
+ import { PublicKey, SystemProgram, Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ export function getSolanaTransaction(params) {
3
+ if (!params.blockhash) {
4
+ throw new Error('Blockhash is required for Solana transactions');
5
+ }
6
+ const transaction = new Transaction().add(SystemProgram.transfer({
7
+ fromPubkey: new PublicKey(params.from),
8
+ toPubkey: new PublicKey(params.to),
9
+ lamports: Number(params.amount)
10
+ }));
11
+ transaction.recentBlockhash = params.blockhash;
12
+ transaction.feePayer = new PublicKey(params.from);
13
+ return transaction;
14
+ }
15
+ //# sourceMappingURL=solana-transactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana-transactions.js","sourceRoot":"","sources":["../../src/utils/solana-transactions.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,aAAa,EACb,WAAW,EACX,oBAAoB,EACrB,MAAM,iBAAiB,CAAA;AAExB,MAAM,UAAU,oBAAoB,CAAC,MAAmC;IACtE,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,MAAM,WAAW,GAAuC,IAAI,WAAW,EAAE,CAAC,GAAG,CAC3E,aAAa,CAAC,QAAQ,CAAC;QACrB,UAAU,EAAE,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QACtC,QAAQ,EAAE,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;KAChC,CAAC,CACH,CAAA;IACD,WAAW,CAAC,eAAe,GAAG,MAAM,CAAC,SAAS,CAAA;IAC9C,WAAW,CAAC,QAAQ,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACjD,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Network, Connector, ConnectorResult, SwitchNetworkResult, WalletConnectConfig, WalletConnectProvider, TransactionRequest, TransactionResult, NetworkRpcMap } from '@meshconnect/uwc-types';
2
+ export declare class WalletConnectConnector implements Connector {
3
+ private walletConnectClient;
4
+ private connectionService;
5
+ private networkSwitchService;
6
+ private signatureService;
7
+ private transactionService;
8
+ private networkRpcMap;
9
+ constructor(config: WalletConnectConfig, networkRpcMap?: NetworkRpcMap);
10
+ connect(network: Network, provider?: WalletConnectProvider): Promise<ConnectorResult>;
11
+ getConnectionURI(): string;
12
+ disconnect(): Promise<void>;
13
+ switchNetwork(network: Network): Promise<SwitchNetworkResult>;
14
+ signMessage(message: string): Promise<string>;
15
+ sendTransaction(request: TransactionRequest): Promise<TransactionResult>;
16
+ }
17
+ //# sourceMappingURL=wallet-connect-connector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-connect-connector.d.ts","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAO/B,qBAAa,sBAAuB,YAAW,SAAS;IACtD,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,mBAAmB,EAAE,aAAa,GAAE,aAAkB;IAmBpE,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,eAAe,CAAC;IAU3B,gBAAgB,IAAI,MAAM;IAQpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;CAG9B"}
@@ -0,0 +1,47 @@
1
+ import { WalletConnectClient } from './services/walletconnect-client';
2
+ import { ConnectionService } from './services/connection-service';
3
+ import { NetworkSwitchService } from './services/network-switch-service';
4
+ import { SignatureService } from './services/signature-service';
5
+ import { TransactionService } from './services/transaction-service';
6
+ export class WalletConnectConnector {
7
+ walletConnectClient;
8
+ connectionService;
9
+ networkSwitchService;
10
+ signatureService;
11
+ transactionService;
12
+ networkRpcMap;
13
+ constructor(config, networkRpcMap = {}) {
14
+ this.walletConnectClient = new WalletConnectClient(config);
15
+ this.networkRpcMap = networkRpcMap;
16
+ this.connectionService = new ConnectionService(this.walletConnectClient);
17
+ this.networkSwitchService = new NetworkSwitchService(this.walletConnectClient, this.connectionService);
18
+ this.signatureService = new SignatureService(this.walletConnectClient, this.connectionService);
19
+ this.transactionService = new TransactionService(this.walletConnectClient, this.connectionService, this.networkRpcMap);
20
+ }
21
+ async connect(network, provider) {
22
+ if (!provider) {
23
+ throw new Error('WalletConnectProvider is required for WalletConnect connection');
24
+ }
25
+ return this.connectionService.connect(network, provider);
26
+ }
27
+ getConnectionURI() {
28
+ const uri = this.connectionService.getConnectionURI();
29
+ if (!uri) {
30
+ throw new Error('No connection URI available. Call connect() first.');
31
+ }
32
+ return uri;
33
+ }
34
+ async disconnect() {
35
+ return this.connectionService.disconnect();
36
+ }
37
+ async switchNetwork(network) {
38
+ return this.networkSwitchService.switchNetwork(network);
39
+ }
40
+ async signMessage(message) {
41
+ return this.signatureService.signMessage(message);
42
+ }
43
+ async sendTransaction(request) {
44
+ return this.transactionService.sendTransaction(request);
45
+ }
46
+ }
47
+ //# sourceMappingURL=wallet-connect-connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-connect-connector.js","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEnE,MAAM,OAAO,sBAAsB;IACzB,mBAAmB,CAAqB;IACxC,iBAAiB,CAAmB;IACpC,oBAAoB,CAAsB;IAC1C,gBAAgB,CAAkB;IAClC,kBAAkB,CAAoB;IACtC,aAAa,CAAe;IAEpC,YAAY,MAA2B,EAAE,gBAA+B,EAAE;QACxE,IAAI,CAAC,mBAAmB,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC1D,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACxE,IAAI,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAClD,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAC1C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,kBAAkB,GAAG,IAAI,kBAAkB,CAC9C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,EACtB,IAAI,CAAC,aAAa,CACnB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,QAAgC;QAEhC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC;IAED,gBAAgB;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QACrD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAgB;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAA2B;QAE3B,OAAO,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@meshconnect/uwc-wallet-connect-connector",
3
+ "version": "0.2.0",
4
+ "description": "WalletConnect connector for Universal Wallet Connector",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "dependencies": {
19
+ "@solana/web3.js": "^1.98.4",
20
+ "@walletconnect/sign-client": "^2.21.8",
21
+ "@walletconnect/types": "^2.21.8",
22
+ "@walletconnect/utils": "^2.21.8",
23
+ "bs58": "^6.0.0",
24
+ "buffer": "^6.0.3",
25
+ "ethers": "^6.15.0",
26
+ "@meshconnect/uwc-types": "0.2.0"
27
+ },
28
+ "devDependencies": {
29
+ "typescript": "^5.9.2"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "dev": "tsc --watch",
37
+ "lint": "eslint src --ext .ts,.tsx",
38
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
39
+ "type-check": "tsc --noEmit"
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './wallet-connect-connector'
@@ -0,0 +1,304 @@
1
+ import type { SessionTypes } from '@walletconnect/types'
2
+ import type {
3
+ Network,
4
+ AvailableAddress,
5
+ ConnectorResult,
6
+ WalletConnectProvider,
7
+ Namespace
8
+ } from '@meshconnect/uwc-types'
9
+ import { WalletConnectClient } from './walletconnect-client'
10
+ import { parseAccount, getNamespaceFromNetworkId } from '../utils/account-utils'
11
+ import { parseError } from '../utils/error-utils'
12
+
13
+ /**
14
+ * Service for handling WalletConnect connections
15
+ */
16
+ export class ConnectionService {
17
+ private currentSession: SessionTypes.Struct | null = null
18
+ private connectionUri: string | null = null
19
+ private activeNetwork: Network | null = null
20
+ private activeAddress: string | null = null
21
+
22
+ constructor(private walletConnectClient: WalletConnectClient) {}
23
+
24
+ /**
25
+ * Connect to a wallet via WalletConnect
26
+ * This will store the URI and wait for approval
27
+ */
28
+ async connect(
29
+ network: Network,
30
+ provider: WalletConnectProvider
31
+ ): Promise<ConnectorResult> {
32
+ try {
33
+ const client = await this.walletConnectClient.getClient()
34
+
35
+ // Disconnect any existing sessions first
36
+ await this.walletConnectClient.disconnectAll()
37
+
38
+ // Build namespaces from the provider's supported network IDs
39
+ const optionalNamespaces = this.buildNamespacesFromProvider(provider)
40
+
41
+ // Initiate connection - this starts the connection process
42
+ const connectResult = await client.connect({
43
+ optionalNamespaces
44
+ })
45
+
46
+ if (!connectResult.uri) {
47
+ throw new Error('No connection URI generated')
48
+ }
49
+
50
+ // Store the URI immediately so it can be retrieved via getConnectionURI
51
+ this.connectionUri = connectResult.uri
52
+
53
+ // Start the approval process in the background
54
+ // The main thread will poll for the URI while this waits for approval
55
+ const approvalPromise = connectResult.approval()
56
+
57
+ try {
58
+ // Wait for approval (this resolves when user approves in wallet)
59
+ const session = await approvalPromise
60
+ this.currentSession = session
61
+ this.connectionUri = null // Clear URI after connection
62
+
63
+ // Extract addresses from session
64
+ const { address, availableAddresses } = this.extractAddresses(
65
+ session,
66
+ network,
67
+ provider
68
+ )
69
+
70
+ // Store the active network and address
71
+ this.activeNetwork = network
72
+ this.activeAddress = address
73
+
74
+ return {
75
+ networkId: network.id,
76
+ address,
77
+ availableAddresses
78
+ }
79
+ } catch (approvalError) {
80
+ this.connectionUri = null // Clear URI on error
81
+ throw approvalError
82
+ }
83
+ } catch (error) {
84
+ this.connectionUri = null // Clear URI on error
85
+ throw parseError(error)
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Get the current connection URI
91
+ */
92
+ getConnectionURI(): string | null {
93
+ return this.connectionUri
94
+ }
95
+
96
+ /**
97
+ * Build WalletConnect namespaces from provider's supported network IDs
98
+ */
99
+ private buildNamespacesFromProvider(provider: WalletConnectProvider): Record<
100
+ string,
101
+ {
102
+ chains: string[]
103
+ methods: string[]
104
+ events: string[]
105
+ }
106
+ > {
107
+ const namespaces: Record<
108
+ string,
109
+ {
110
+ chains: string[]
111
+ methods: string[]
112
+ events: string[]
113
+ }
114
+ > = {}
115
+
116
+ // Group networks by namespace
117
+ const namespaceGroups: Record<Namespace, string[]> = {} as Record<
118
+ Namespace,
119
+ string[]
120
+ >
121
+
122
+ provider.supportedNetworkIds.forEach(networkId => {
123
+ const namespace = getNamespaceFromNetworkId(networkId)
124
+ if (!namespaceGroups[namespace]) {
125
+ namespaceGroups[namespace] = []
126
+ }
127
+ namespaceGroups[namespace]!.push(networkId)
128
+ })
129
+
130
+ // Build namespaces for each group
131
+ Object.entries(namespaceGroups).forEach(([namespace, chains]) => {
132
+ switch (namespace) {
133
+ case 'eip155':
134
+ namespaces['eip155'] = {
135
+ chains,
136
+ methods: [
137
+ 'personal_sign',
138
+ 'eth_sign',
139
+ 'eth_signTypedData',
140
+ 'eth_signTypedData_v4',
141
+ 'eth_sendTransaction',
142
+ 'eth_sendRawTransaction',
143
+ 'eth_accounts',
144
+ 'eth_requestAccounts',
145
+ 'wallet_switchEthereumChain',
146
+ 'wallet_addEthereumChain'
147
+ ],
148
+ events: ['chainChanged', 'accountsChanged']
149
+ }
150
+ break
151
+
152
+ case 'solana':
153
+ namespaces['solana'] = {
154
+ chains,
155
+ methods: [
156
+ 'solana_signMessage',
157
+ 'solana_signTransaction',
158
+ 'solana_signAndSendTransaction',
159
+ 'solana_getAccounts',
160
+ 'solana_requestAccounts'
161
+ ],
162
+ events: []
163
+ }
164
+ break
165
+
166
+ case 'bip122':
167
+ namespaces['bip122'] = {
168
+ chains,
169
+ methods: [
170
+ 'sendTransfer',
171
+ 'getAccountAddresses',
172
+ 'signPsbt',
173
+ 'signMessage'
174
+ ],
175
+ events: ['bip122_addressesChanged']
176
+ }
177
+ break
178
+
179
+ case 'tron':
180
+ namespaces['tron'] = {
181
+ chains,
182
+ methods: ['tron_signTransaction', 'tron_signMessage'],
183
+ events: []
184
+ }
185
+ break
186
+
187
+ default:
188
+ // For unknown namespaces, include basic methods
189
+ namespaces[namespace] = {
190
+ chains,
191
+ methods: [],
192
+ events: []
193
+ }
194
+ }
195
+ })
196
+
197
+ return namespaces
198
+ }
199
+
200
+ /**
201
+ * Extract addresses from a WalletConnect session
202
+ */
203
+ private extractAddresses(
204
+ session: SessionTypes.Struct,
205
+ network: Network,
206
+ provider: WalletConnectProvider
207
+ ): {
208
+ address: string
209
+ availableAddresses: AvailableAddress[]
210
+ } {
211
+ const availableAddresses: AvailableAddress[] = []
212
+ let primaryAddress = ''
213
+
214
+ // Extract addresses from all namespaces
215
+ Object.entries(session.namespaces).forEach(([, data]) => {
216
+ data.accounts.forEach((account: string) => {
217
+ try {
218
+ const { networkId, address } = parseAccount(account)
219
+
220
+ // Only include addresses for networks that are supported by the provider
221
+ if (provider.supportedNetworkIds.includes(networkId)) {
222
+ availableAddresses.push({
223
+ address,
224
+ networkId
225
+ })
226
+
227
+ // Set the primary address based on the requested network
228
+ if (networkId === network.id && !primaryAddress) {
229
+ primaryAddress = address
230
+ }
231
+ }
232
+ } catch {
233
+ // Skip invalid account formats
234
+ }
235
+ })
236
+ })
237
+
238
+ // If no address for the specific network, use the first available
239
+ if (!primaryAddress && availableAddresses.length > 0) {
240
+ primaryAddress = availableAddresses[0]?.address || ''
241
+ }
242
+
243
+ if (!primaryAddress) {
244
+ throw new Error('No addresses found in session')
245
+ }
246
+
247
+ return { address: primaryAddress, availableAddresses }
248
+ }
249
+
250
+ /**
251
+ * Get current session
252
+ */
253
+ getSession(): SessionTypes.Struct | null {
254
+ return this.currentSession
255
+ }
256
+
257
+ /**
258
+ * Set session (for restoration)
259
+ */
260
+ setSession(session: SessionTypes.Struct): void {
261
+ this.currentSession = session
262
+ }
263
+
264
+ /**
265
+ * Get active network
266
+ */
267
+ getActiveNetwork(): Network | null {
268
+ return this.activeNetwork
269
+ }
270
+
271
+ /**
272
+ * Set active network (for network switching)
273
+ */
274
+ setActiveNetwork(network: Network): void {
275
+ this.activeNetwork = network
276
+ }
277
+
278
+ /**
279
+ * Get active address
280
+ */
281
+ getActiveAddress(): string | null {
282
+ return this.activeAddress
283
+ }
284
+
285
+ /**
286
+ * Set active address (for network/address switching)
287
+ */
288
+ setActiveAddress(address: string): void {
289
+ this.activeAddress = address
290
+ }
291
+
292
+ /**
293
+ * Disconnect current session
294
+ */
295
+ async disconnect(): Promise<void> {
296
+ if (this.currentSession) {
297
+ await this.walletConnectClient.disconnect(this.currentSession.topic)
298
+ this.currentSession = null
299
+ }
300
+ this.connectionUri = null
301
+ this.activeNetwork = null
302
+ this.activeAddress = null
303
+ }
304
+ }
@@ -0,0 +1,83 @@
1
+ import type { Network, SwitchNetworkResult } from '@meshconnect/uwc-types'
2
+ import { WalletConnectClient } from './walletconnect-client'
3
+ import { ConnectionService } from './connection-service'
4
+ import { parseAccount } from '../utils/account-utils'
5
+ import { parseError } from '../utils/error-utils'
6
+
7
+ /**
8
+ * Service for handling network switching in WalletConnect
9
+ */
10
+ export class NetworkSwitchService {
11
+ constructor(
12
+ private walletConnectClient: WalletConnectClient,
13
+ private connectionService: ConnectionService
14
+ ) {}
15
+
16
+ /**
17
+ * Switch to a different network
18
+ */
19
+ async switchNetwork(network: Network): Promise<SwitchNetworkResult> {
20
+ try {
21
+ const session = this.connectionService.getSession()
22
+ if (!session) {
23
+ throw new Error('No active session. Please connect first.')
24
+ }
25
+
26
+ const client = await this.walletConnectClient.getClient()
27
+
28
+ // Check if the requested network is available in the session
29
+ const networkChain = network.id
30
+ const namespace = network.namespace
31
+
32
+ if (!session.namespaces[namespace]?.chains?.includes(networkChain)) {
33
+ throw new Error(
34
+ `Network ${networkChain} is not available in the current session`
35
+ )
36
+ }
37
+
38
+ // For WalletConnect, we can't directly switch networks
39
+ // The wallet controls the active network
40
+ // We can only request methods on specific chains
41
+ // Return the current address for the requested network
42
+
43
+ const accounts = session.namespaces[namespace]?.accounts || []
44
+ const matchingAccount = accounts.find(account =>
45
+ account.startsWith(networkChain)
46
+ )
47
+
48
+ if (!matchingAccount) {
49
+ throw new Error(`No account found for network ${networkChain}`)
50
+ }
51
+
52
+ // Extract address from account string
53
+ const { address } = parseAccount(matchingAccount)
54
+
55
+ // Update the active network and address in the connection service
56
+ this.connectionService.setActiveNetwork(network)
57
+ this.connectionService.setActiveAddress(address)
58
+
59
+ // Emit a chainChanged event if switching within the same namespace
60
+ if (namespace === 'eip155') {
61
+ try {
62
+ await client.emit({
63
+ topic: session.topic,
64
+ event: {
65
+ name: 'chainChanged',
66
+ data: networkChain
67
+ },
68
+ chainId: networkChain
69
+ })
70
+ } catch {
71
+ // Some wallets may not support this event
72
+ }
73
+ }
74
+
75
+ return {
76
+ networkId: network.id,
77
+ address
78
+ }
79
+ } catch (error) {
80
+ throw parseError(error)
81
+ }
82
+ }
83
+ }