@hashgraph/hedera-wallet-connect 1.3.6-canary.67ec2cf.0 → 1.3.7-canary.14806a9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. package/dist/{src/lib/dapp → dapp}/DAppSigner.d.ts +17 -2
  2. package/dist/{src/lib/dapp → dapp}/DAppSigner.js +108 -28
  3. package/dist/{src/lib/dapp → dapp}/index.d.ts +24 -3
  4. package/dist/{src/lib/dapp → dapp}/index.js +144 -47
  5. package/dist/shared/logger.d.ts +16 -0
  6. package/dist/shared/logger.js +32 -0
  7. package/dist/{src/lib/shared → shared}/utils.d.ts +2 -2
  8. package/dist/{src/lib/shared → shared}/utils.js +2 -2
  9. package/package.json +5 -2
  10. package/dist/src/index.d.ts +0 -1
  11. package/dist/src/index.js +0 -20
  12. package/dist/test/_helpers.d.ts +0 -38
  13. package/dist/test/_helpers.js +0 -95
  14. package/dist/test/dapp/DAppConnector.test.d.ts +0 -1
  15. package/dist/test/dapp/DAppConnector.test.js +0 -234
  16. package/dist/test/dapp/DAppSigner.test.d.ts +0 -1
  17. package/dist/test/dapp/DAppSigner.test.js +0 -155
  18. package/dist/test/utils.test.d.ts +0 -1
  19. package/dist/test/utils.test.js +0 -201
  20. package/dist/test/wallet/methods/wallet-executeTransaction.test.d.ts +0 -1
  21. package/dist/test/wallet/methods/wallet-executeTransaction.test.js +0 -43
  22. package/dist/test/wallet/methods/wallet-getNodeAddresses.test.d.ts +0 -1
  23. package/dist/test/wallet/methods/wallet-getNodeAddresses.test.js +0 -40
  24. package/dist/test/wallet/methods/wallet-signAndExecuteQuery.test.d.ts +0 -1
  25. package/dist/test/wallet/methods/wallet-signAndExecuteQuery.test.js +0 -41
  26. package/dist/test/wallet/methods/wallet-signAndExecuteTransaction.test.d.ts +0 -1
  27. package/dist/test/wallet/methods/wallet-signAndExecuteTransaction.test.js +0 -48
  28. package/dist/test/wallet/methods/wallet-signMessage.test.d.ts +0 -1
  29. package/dist/test/wallet/methods/wallet-signMessage.test.js +0 -60
  30. package/dist/test/wallet/methods/wallet-signTransaction.test.d.ts +0 -1
  31. package/dist/test/wallet/methods/wallet-signTransaction.test.js +0 -47
  32. package/dist/test/wallet/wallet-init.test.d.ts +0 -1
  33. package/dist/test/wallet/wallet-init.test.js +0 -53
  34. /package/dist/{src/lib/index.d.ts → index.d.ts} +0 -0
  35. /package/dist/{src/lib/index.js → index.js} +0 -0
  36. /package/dist/{src/lib/shared → shared}/chainIds.d.ts +0 -0
  37. /package/dist/{src/lib/shared → shared}/chainIds.js +0 -0
  38. /package/dist/{src/lib/shared → shared}/errors.d.ts +0 -0
  39. /package/dist/{src/lib/shared → shared}/errors.js +0 -0
  40. /package/dist/{src/lib/shared → shared}/events.d.ts +0 -0
  41. /package/dist/{src/lib/shared → shared}/events.js +0 -0
  42. /package/dist/{src/lib/shared → shared}/extensionController.d.ts +0 -0
  43. /package/dist/{src/lib/shared → shared}/extensionController.js +0 -0
  44. /package/dist/{src/lib/shared → shared}/index.d.ts +0 -0
  45. /package/dist/{src/lib/shared → shared}/index.js +0 -0
  46. /package/dist/{src/lib/shared → shared}/methods.d.ts +0 -0
  47. /package/dist/{src/lib/shared → shared}/methods.js +0 -0
  48. /package/dist/{src/lib/shared → shared}/payloads.d.ts +0 -0
  49. /package/dist/{src/lib/shared → shared}/payloads.js +0 -0
  50. /package/dist/{src/lib/wallet → wallet}/index.d.ts +0 -0
  51. /package/dist/{src/lib/wallet → wallet}/index.js +0 -0
  52. /package/dist/{src/lib/wallet → wallet}/provider.d.ts +0 -0
  53. /package/dist/{src/lib/wallet → wallet}/provider.js +0 -0
  54. /package/dist/{src/lib/wallet → wallet}/types.d.ts +0 -0
  55. /package/dist/{src/lib/wallet → wallet}/types.js +0 -0
@@ -1,12 +1,18 @@
1
1
  import { Signer, AccountBalance, AccountId, AccountInfo, Executable, Key, LedgerId, SignerSignature, Transaction, TransactionRecord } from '@hashgraph/sdk';
2
- import type { ISignClient } from '@walletconnect/types';
2
+ import type { CoreTypes, ISignClient } from '@walletconnect/types';
3
3
  export declare class DAppSigner implements Signer {
4
4
  private readonly accountId;
5
5
  private readonly signClient;
6
6
  readonly topic: string;
7
7
  private readonly ledgerId;
8
8
  readonly extensionId?: string | undefined;
9
- constructor(accountId: AccountId, signClient: ISignClient, topic: string, ledgerId?: LedgerId, extensionId?: string | undefined);
9
+ private logger;
10
+ constructor(accountId: AccountId, signClient: ISignClient, topic: string, ledgerId?: LedgerId, extensionId?: string | undefined, logLevel?: 'error' | 'warn' | 'info' | 'debug');
11
+ /**
12
+ * Sets the logging level for the DAppSigner
13
+ * @param level - The logging level to set
14
+ */
15
+ setLogLevel(level: 'error' | 'warn' | 'info' | 'debug'): void;
10
16
  private _getHederaClient;
11
17
  private get _signerAccountId();
12
18
  private _getRandomNodes;
@@ -24,6 +30,7 @@ export declare class DAppSigner implements Signer {
24
30
  getAccountBalance(): Promise<AccountBalance>;
25
31
  getAccountInfo(): Promise<AccountInfo>;
26
32
  getAccountRecords(): Promise<TransactionRecord[]>;
33
+ getMetadata(): CoreTypes.Metadata;
27
34
  sign(data: Uint8Array[], signOptions?: Record<string, any>): Promise<SignerSignature[]>;
28
35
  checkTransaction<T extends Transaction>(transaction: T): Promise<T>;
29
36
  populateTransaction<T extends Transaction>(transaction: T): Promise<T>;
@@ -38,6 +45,14 @@ export declare class DAppSigner implements Signer {
38
45
  signTransaction<T extends Transaction>(transaction: T): Promise<T>;
39
46
  private _tryExecuteTransactionRequest;
40
47
  private _parseQueryResponse;
48
+ /**
49
+ * Executes a free receipt query without signing a transaction.
50
+ * Enables the DApp to fetch the receipt of a transaction without making a new request
51
+ * to the wallet.
52
+ * @param request - The query to execute
53
+ * @returns The result of the query
54
+ */
55
+ private executeReceiptQueryFromRequest;
41
56
  private _tryExecuteQueryRequest;
42
57
  call<RequestT, ResponseT, OutputT>(request: Executable<RequestT, ResponseT, OutputT>): Promise<OutputT>;
43
58
  }
@@ -20,14 +20,25 @@
20
20
  import { AccountBalance, AccountId, AccountInfo, LedgerId, SignerSignature, Transaction, TransactionRecord, Client, PublicKey, TransactionId, TransactionResponse, Query, AccountRecordsQuery, AccountInfoQuery, AccountBalanceQuery, TransactionReceiptQuery, TransactionReceipt, TransactionRecordQuery, } from '@hashgraph/sdk';
21
21
  import { proto } from '@hashgraph/proto';
22
22
  import { HederaJsonRpcMethod, Uint8ArrayToBase64String, base64StringToSignatureMap, base64StringToUint8Array, ledgerIdToCAIPChainId, queryToBase64String, transactionBodyToBase64String, transactionToBase64String, transactionToTransactionBody, extensionOpen, } from '../shared';
23
+ import { DefaultLogger } from '../shared/logger';
23
24
  const clients = {};
24
25
  export class DAppSigner {
25
- constructor(accountId, signClient, topic, ledgerId = LedgerId.MAINNET, extensionId) {
26
+ constructor(accountId, signClient, topic, ledgerId = LedgerId.MAINNET, extensionId, logLevel = 'debug') {
26
27
  this.accountId = accountId;
27
28
  this.signClient = signClient;
28
29
  this.topic = topic;
29
30
  this.ledgerId = ledgerId;
30
31
  this.extensionId = extensionId;
32
+ this.logger = new DefaultLogger(logLevel);
33
+ }
34
+ /**
35
+ * Sets the logging level for the DAppSigner
36
+ * @param level - The logging level to set
37
+ */
38
+ setLogLevel(level) {
39
+ if (this.logger instanceof DefaultLogger) {
40
+ this.logger.setLogLevel(level);
41
+ }
31
42
  }
32
43
  _getHederaClient() {
33
44
  const ledgerIdString = this.ledgerId.toString();
@@ -81,22 +92,33 @@ export class DAppSigner {
81
92
  getAccountRecords() {
82
93
  return this.call(new AccountRecordsQuery().setAccountId(this.accountId));
83
94
  }
95
+ getMetadata() {
96
+ return this.signClient.metadata;
97
+ }
84
98
  async sign(data, signOptions) {
85
- const { signatureMap } = await this.request({
86
- method: HederaJsonRpcMethod.SignMessage,
87
- params: {
88
- signerAccountId: this._signerAccountId,
89
- message: Uint8ArrayToBase64String(data[0]),
90
- },
91
- });
92
- const sigmap = base64StringToSignatureMap(signatureMap);
93
- const signerSignature = new SignerSignature({
94
- accountId: this.getAccountId(),
95
- publicKey: PublicKey.fromBytes(sigmap.sigPair[0].pubKeyPrefix),
96
- signature: sigmap.sigPair[0].ed25519 ||
97
- sigmap.sigPair[0].ECDSASecp256k1,
98
- });
99
- return [signerSignature];
99
+ this.logger.debug('Signing data');
100
+ try {
101
+ const { signatureMap } = await this.request({
102
+ method: HederaJsonRpcMethod.SignMessage,
103
+ params: {
104
+ signerAccountId: this._signerAccountId,
105
+ message: Uint8ArrayToBase64String(data[0]),
106
+ },
107
+ });
108
+ const sigmap = base64StringToSignatureMap(signatureMap);
109
+ const signerSignature = new SignerSignature({
110
+ accountId: this.getAccountId(),
111
+ publicKey: PublicKey.fromBytes(sigmap.sigPair[0].pubKeyPrefix),
112
+ signature: sigmap.sigPair[0].ed25519 ||
113
+ sigmap.sigPair[0].ECDSASecp256k1,
114
+ });
115
+ this.logger.debug('Data signed successfully');
116
+ return [signerSignature];
117
+ }
118
+ catch (error) {
119
+ this.logger.error('Error signing data:', error);
120
+ throw error;
121
+ }
100
122
  }
101
123
  async checkTransaction(transaction) {
102
124
  throw new Error('Method not implemented.');
@@ -138,7 +160,10 @@ export class DAppSigner {
138
160
  }
139
161
  async _tryExecuteTransactionRequest(request) {
140
162
  try {
141
- const transaction = Transaction.fromBytes(request.toBytes());
163
+ const requestToBytes = request.toBytes();
164
+ this.logger.debug('Creating transaction from bytes', requestToBytes, request);
165
+ const transaction = Transaction.fromBytes(requestToBytes);
166
+ this.logger.debug('Executing transaction request', transaction);
142
167
  const result = await this.request({
143
168
  method: HederaJsonRpcMethod.SignAndExecuteTransaction,
144
169
  params: {
@@ -146,9 +171,11 @@ export class DAppSigner {
146
171
  transactionList: transactionToBase64String(transaction),
147
172
  },
148
173
  });
174
+ this.logger.debug('Transaction request completed successfully');
149
175
  return { result: TransactionResponse.fromJSON(result) };
150
176
  }
151
177
  catch (error) {
178
+ this.logger.error('Error executing transaction request:', error);
152
179
  return { error };
153
180
  }
154
181
  }
@@ -175,9 +202,46 @@ export class DAppSigner {
175
202
  throw new Error('Unsupported query type');
176
203
  }
177
204
  }
205
+ /**
206
+ * Executes a free receipt query without signing a transaction.
207
+ * Enables the DApp to fetch the receipt of a transaction without making a new request
208
+ * to the wallet.
209
+ * @param request - The query to execute
210
+ * @returns The result of the query
211
+ */
212
+ async executeReceiptQueryFromRequest(request) {
213
+ try {
214
+ const isMainnet = this.ledgerId === LedgerId.MAINNET;
215
+ const client = isMainnet ? Client.forMainnet() : Client.forTestnet();
216
+ const receipt = TransactionReceiptQuery.fromBytes(request.toBytes());
217
+ const result = await receipt.execute(client);
218
+ return { result };
219
+ }
220
+ catch (error) {
221
+ return { error };
222
+ }
223
+ }
178
224
  async _tryExecuteQueryRequest(request) {
179
225
  try {
180
- const query = Query.fromBytes(request.toBytes());
226
+ const isReceiptQuery = request instanceof TransactionReceiptQuery;
227
+ if (isReceiptQuery) {
228
+ this.logger.debug('Attempting to execute free receipt query', request);
229
+ const result = await this.executeReceiptQueryFromRequest(request);
230
+ if (!(result === null || result === void 0 ? void 0 : result.error)) {
231
+ return { result: result.result };
232
+ }
233
+ else {
234
+ this.logger.error('Error executing free receipt query. Sending to wallet.', result.error);
235
+ }
236
+ }
237
+ /**
238
+ * Note, should we be converting these to specific query types?
239
+ * Left alone to avoid changing the API for other requests.
240
+ */
241
+ const query = isReceiptQuery
242
+ ? TransactionReceiptQuery.fromBytes(request.toBytes())
243
+ : Query.fromBytes(request.toBytes());
244
+ this.logger.debug('Executing query request', query, queryToBase64String(query), isReceiptQuery);
181
245
  const result = await this.request({
182
246
  method: HederaJsonRpcMethod.SignAndExecuteQuery,
183
247
  params: {
@@ -185,6 +249,7 @@ export class DAppSigner {
185
249
  query: queryToBase64String(query),
186
250
  },
187
251
  });
252
+ this.logger.debug('Query request completed successfully', result);
188
253
  return { result: this._parseQueryResponse(query, result.response) };
189
254
  }
190
255
  catch (error) {
@@ -192,27 +257,42 @@ export class DAppSigner {
192
257
  }
193
258
  }
194
259
  async call(request) {
195
- var _a, _b, _c, _d, _e, _f;
196
- const txResult = await this._tryExecuteTransactionRequest(request);
197
- if (txResult.result) {
198
- return txResult.result;
260
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
261
+ const isReceiptQuery = request instanceof TransactionReceiptQuery;
262
+ let txResult = undefined;
263
+ // a receipt query is a free query and we should not execute a transaction.
264
+ if (!isReceiptQuery) {
265
+ txResult = await this._tryExecuteTransactionRequest(request);
266
+ if (txResult.result) {
267
+ return txResult.result;
268
+ }
199
269
  }
200
270
  const queryResult = await this._tryExecuteQueryRequest(request);
201
271
  if (queryResult.result) {
202
272
  return queryResult.result;
203
273
  }
204
274
  // TODO: make this error more usable
275
+ if (isReceiptQuery) {
276
+ throw new Error('Error executing receipt query: \n' +
277
+ JSON.stringify({
278
+ queryError: {
279
+ name: (_a = queryResult.error) === null || _a === void 0 ? void 0 : _a.name,
280
+ message: (_b = queryResult.error) === null || _b === void 0 ? void 0 : _b.message,
281
+ stack: (_c = queryResult.error) === null || _c === void 0 ? void 0 : _c.stack,
282
+ },
283
+ }));
284
+ }
205
285
  throw new Error('Error executing transaction or query: \n' +
206
286
  JSON.stringify({
207
287
  txError: {
208
- name: (_a = txResult.error) === null || _a === void 0 ? void 0 : _a.name,
209
- message: (_b = txResult.error) === null || _b === void 0 ? void 0 : _b.message,
210
- stack: (_c = txResult.error) === null || _c === void 0 ? void 0 : _c.stack,
288
+ name: (_d = txResult === null || txResult === void 0 ? void 0 : txResult.error) === null || _d === void 0 ? void 0 : _d.name,
289
+ message: (_e = txResult === null || txResult === void 0 ? void 0 : txResult.error) === null || _e === void 0 ? void 0 : _e.message,
290
+ stack: (_f = txResult === null || txResult === void 0 ? void 0 : txResult.error) === null || _f === void 0 ? void 0 : _f.stack,
211
291
  },
212
292
  queryError: {
213
- name: (_d = queryResult.error) === null || _d === void 0 ? void 0 : _d.name,
214
- message: (_e = queryResult.error) === null || _e === void 0 ? void 0 : _e.message,
215
- stack: (_f = queryResult.error) === null || _f === void 0 ? void 0 : _f.stack,
293
+ name: (_g = queryResult.error) === null || _g === void 0 ? void 0 : _g.name,
294
+ message: (_h = queryResult.error) === null || _h === void 0 ? void 0 : _h.message,
295
+ stack: (_j = queryResult.error) === null || _j === void 0 ? void 0 : _j.stack,
216
296
  },
217
297
  }, null, 2));
218
298
  }
@@ -7,6 +7,7 @@ import { DAppSigner } from './DAppSigner';
7
7
  export * from './DAppSigner';
8
8
  type BaseLogger = 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'fatal';
9
9
  export declare class DAppConnector {
10
+ private logger;
10
11
  dAppMetadata: SignClientTypes.Metadata;
11
12
  network: LedgerId;
12
13
  projectId: string;
@@ -27,8 +28,14 @@ export declare class DAppConnector {
27
28
  * @param methods - Array of supported methods for the DApp (optional).
28
29
  * @param events - Array of supported events for the DApp (optional).
29
30
  * @param chains - Array of supported chains for the DApp (optional).
31
+ * @param logLevel - Logging level for the DAppConnector (optional).
30
32
  */
31
- constructor(metadata: SignClientTypes.Metadata, network: LedgerId, projectId: string, methods?: string[], events?: string[], chains?: string[]);
33
+ constructor(metadata: SignClientTypes.Metadata, network: LedgerId, projectId: string, methods?: string[], events?: string[], chains?: string[], logLevel?: 'error' | 'warn' | 'info' | 'debug');
34
+ /**
35
+ * Sets the logging level for the DAppConnector
36
+ * @param level - The logging level to set
37
+ */
38
+ setLogLevel(level: 'error' | 'warn' | 'info' | 'debug'): void;
32
39
  /**
33
40
  * Initializes the DAppConnector instance.
34
41
  * @param logger - `BaseLogger` for logging purposes (optional).
@@ -71,6 +78,16 @@ export declare class DAppConnector {
71
78
  * @returns A Promise that resolves when the connection process is complete.
72
79
  */
73
80
  connectExtension(extensionId: string, pairingTopic?: string): Promise<SessionTypes.Struct>;
81
+ /**
82
+ * Validates the session by checking if the session exists.
83
+ * @param topic - The topic of the session to validate.
84
+ * @returns {boolean} - True if the session exists, false otherwise.
85
+ */
86
+ private validateSession;
87
+ /**
88
+ * Validates the session and refreshes the signers by removing the invalid ones.
89
+ */
90
+ private validateAndRefreshSigners;
74
91
  /**
75
92
  * Initiates the WallecConnect connection if the wallet in iframe mode is detected.
76
93
  */
@@ -81,7 +98,7 @@ export declare class DAppConnector {
81
98
  * @param topic - The topic of the session to disconnect.
82
99
  * @returns A Promise that resolves when the session is disconnected.
83
100
  */
84
- disconnect(topic: string): Promise<void>;
101
+ disconnect(topic: string): Promise<boolean>;
85
102
  /**
86
103
  * Disconnects all active sessions and pairings.
87
104
  *
@@ -127,7 +144,7 @@ export declare class DAppConnector {
127
144
  * @example
128
145
  * ```ts
129
146
  * const params = {
130
- * signerAccountId: '0.0.12345',
147
+ * signerAccountId: 'hedera:testnet:0.0.12345',
131
148
  * message: 'Hello World!'
132
149
  * }
133
150
  *
@@ -194,5 +211,9 @@ export declare class DAppConnector {
194
211
  * ```
195
212
  */
196
213
  signTransaction(params: SignTransactionParams): Promise<SignTransactionResult>;
214
+ private handleSessionEvent;
215
+ private handleSessionUpdate;
216
+ private handleSessionDelete;
217
+ private handlePairingDelete;
197
218
  }
198
219
  export default DAppConnector;
@@ -22,6 +22,7 @@ import QRCodeModal from '@walletconnect/qrcode-modal';
22
22
  import { WalletConnectModal } from '@walletconnect/modal';
23
23
  import SignClient from '@walletconnect/sign-client';
24
24
  import { getSdkError } from '@walletconnect/utils';
25
+ import { DefaultLogger } from '../shared/logger';
25
26
  import { HederaJsonRpcMethod, accountAndLedgerFromSession, networkNamespaces, extensionConnect, findExtensions, } from '../shared';
26
27
  import { DAppSigner } from './DAppSigner';
27
28
  export * from './DAppSigner';
@@ -34,8 +35,9 @@ export class DAppConnector {
34
35
  * @param methods - Array of supported methods for the DApp (optional).
35
36
  * @param events - Array of supported events for the DApp (optional).
36
37
  * @param chains - Array of supported chains for the DApp (optional).
38
+ * @param logLevel - Logging level for the DAppConnector (optional).
37
39
  */
38
- constructor(metadata, network, projectId, methods, events, chains) {
40
+ constructor(metadata, network, projectId, methods, events, chains, logLevel = 'debug') {
39
41
  this.network = LedgerId.TESTNET;
40
42
  this.supportedMethods = [];
41
43
  this.supportedEvents = [];
@@ -62,6 +64,7 @@ export class DAppConnector {
62
64
  }
63
65
  });
64
66
  };
67
+ this.logger = new DefaultLogger(logLevel);
65
68
  this.dAppMetadata = metadata;
66
69
  this.network = network;
67
70
  this.projectId = projectId;
@@ -77,6 +80,15 @@ export class DAppConnector {
77
80
  this.extensions.push(Object.assign(Object.assign({}, metadata), { available: true, availableInIframe: isIframe }));
78
81
  });
79
82
  }
83
+ /**
84
+ * Sets the logging level for the DAppConnector
85
+ * @param level - The logging level to set
86
+ */
87
+ setLogLevel(level) {
88
+ if (this.logger instanceof DefaultLogger) {
89
+ this.logger.setLogLevel(level);
90
+ }
91
+ }
80
92
  /**
81
93
  * Initializes the DAppConnector instance.
82
94
  * @param logger - `BaseLogger` for logging purposes (optional).
@@ -98,43 +110,13 @@ export class DAppConnector {
98
110
  this.signers = existingSessions.flatMap((session) => this.createSigners(session));
99
111
  else
100
112
  this.checkIframeConnect();
101
- this.walletConnectClient.on('session_event', (event) => {
102
- // Handle session events, such as "chainChanged", "accountsChanged", etc.
103
- console.log(event);
104
- });
105
- this.walletConnectClient.on('session_update', ({ topic, params }) => {
106
- // Handle session update
107
- const { namespaces } = params;
108
- const _session = this.walletConnectClient.session.get(topic);
109
- // Overwrite the `namespaces` of the existing session with the incoming one.
110
- const updatedSession = Object.assign(Object.assign({}, _session), { namespaces });
111
- // Integrate the updated session state into your dapp state.
112
- console.log(updatedSession);
113
- });
114
- this.walletConnectClient.on('session_delete', (pairing) => {
115
- console.log(pairing);
116
- this.signers = this.signers.filter((signer) => signer.topic !== pairing.topic);
117
- // Session was deleted -> reset the dapp state, clean up from user session, etc.
118
- try {
119
- this.disconnect(pairing.topic);
120
- }
121
- catch (e) {
122
- console.error(e);
123
- }
124
- console.log('Dapp: Session deleted by wallet!');
125
- });
126
- this.walletConnectClient.core.pairing.events.on('pairing_delete', (pairing) => {
127
- console.log(pairing);
128
- this.signers = this.signers.filter((signer) => signer.topic !== pairing.topic);
129
- try {
130
- this.disconnect(pairing.topic);
131
- }
132
- catch (e) {
133
- console.error(e);
134
- }
135
- console.log(`Dapp: Pairing deleted by wallet!`);
136
- // clean up after the pairing for `topic` was deleted.
137
- });
113
+ this.walletConnectClient.on('session_event', this.handleSessionEvent.bind(this));
114
+ this.walletConnectClient.on('session_update', this.handleSessionUpdate.bind(this));
115
+ this.walletConnectClient.on('session_delete', this.handleSessionDelete.bind(this));
116
+ this.walletConnectClient.core.pairing.events.on('pairing_delete', this.handlePairingDelete.bind(this));
117
+ }
118
+ catch (e) {
119
+ this.logger.error('Error initializing DAppConnector:', e);
138
120
  }
139
121
  finally {
140
122
  this.isInitializing = false;
@@ -148,6 +130,9 @@ export class DAppConnector {
148
130
  * @throws {Error} - If no signer is found for the provided account ID.
149
131
  */
150
132
  getSigner(accountId) {
133
+ if (this.isInitializing) {
134
+ throw new Error('DAppConnector is not initialized yet. Try again later.');
135
+ }
151
136
  const signer = this.signers.find((signer) => signer.getAccountId().equals(accountId));
152
137
  if (!signer)
153
138
  throw new Error('Signer is not found for this accountId');
@@ -231,6 +216,32 @@ export class DAppConnector {
231
216
  extensionConnect(extension.id, extension.availableInIframe, uri);
232
217
  }, pairingTopic, extension.availableInIframe ? undefined : extensionId);
233
218
  }
219
+ /**
220
+ * Validates the session by checking if the session exists.
221
+ * @param topic - The topic of the session to validate.
222
+ * @returns {boolean} - True if the session exists, false otherwise.
223
+ */
224
+ validateSession(topic) {
225
+ try {
226
+ if (!this.walletConnectClient) {
227
+ return false;
228
+ }
229
+ const session = this.walletConnectClient.session.get(topic);
230
+ if (!session) {
231
+ return false;
232
+ }
233
+ return true;
234
+ }
235
+ catch (_a) {
236
+ return false;
237
+ }
238
+ }
239
+ /**
240
+ * Validates the session and refreshes the signers by removing the invalid ones.
241
+ */
242
+ validateAndRefreshSigners() {
243
+ this.signers = this.signers.filter((signer) => this.validateSession(signer.topic));
244
+ }
234
245
  /**
235
246
  * Initiates the WallecConnect connection if the wallet in iframe mode is detected.
236
247
  */
@@ -248,10 +259,20 @@ export class DAppConnector {
248
259
  * @returns A Promise that resolves when the session is disconnected.
249
260
  */
250
261
  async disconnect(topic) {
251
- await this.walletConnectClient.disconnect({
252
- topic: topic,
253
- reason: getSdkError('USER_DISCONNECTED'),
254
- });
262
+ try {
263
+ if (!this.walletConnectClient) {
264
+ throw new Error('WalletConnect is not initialized');
265
+ }
266
+ await this.walletConnectClient.disconnect({
267
+ topic: topic,
268
+ reason: getSdkError('USER_DISCONNECTED'),
269
+ });
270
+ return true;
271
+ }
272
+ catch (e) {
273
+ this.logger.error('Either the session was already disconnected or the topic is invalid', e);
274
+ return false;
275
+ }
255
276
  }
256
277
  /**
257
278
  * Disconnects all active sessions and pairings.
@@ -271,7 +292,7 @@ export class DAppConnector {
271
292
  const disconnectionPromises = [];
272
293
  // disconnect sessions
273
294
  for (const session of this.walletConnectClient.session.getAll()) {
274
- console.log(`Disconnecting from session: ${session}`);
295
+ this.logger.info(`Disconnecting from session: ${session}`);
275
296
  const promise = this.disconnect(session.topic);
276
297
  disconnectionPromises.push(promise);
277
298
  }
@@ -288,11 +309,38 @@ export class DAppConnector {
288
309
  const allNamespaceAccounts = accountAndLedgerFromSession(session);
289
310
  return allNamespaceAccounts.map(({ account, network }) => {
290
311
  var _a;
291
- return new DAppSigner(account, this.walletConnectClient, session.topic, network, (_a = session.sessionProperties) === null || _a === void 0 ? void 0 : _a.extensionId);
312
+ return new DAppSigner(account, this.walletConnectClient, session.topic, network, (_a = session.sessionProperties) === null || _a === void 0 ? void 0 : _a.extensionId, this.logger instanceof DefaultLogger ? this.logger.getLogLevel() : 'debug');
292
313
  });
293
314
  }
294
315
  async onSessionConnected(session) {
295
- this.signers.push(...this.createSigners(session));
316
+ const newSigners = this.createSigners(session);
317
+ // Filter out any existing signers with duplicate AccountIds
318
+ for (const newSigner of newSigners) {
319
+ // We check if any signers have the same account, extension + metadata name.
320
+ const existingSigners = this.signers.filter((currentSigner) => {
321
+ var _a, _b;
322
+ const matchingAccountId = ((_a = currentSigner === null || currentSigner === void 0 ? void 0 : currentSigner.getAccountId()) === null || _a === void 0 ? void 0 : _a.toString()) === ((_b = newSigner === null || newSigner === void 0 ? void 0 : newSigner.getAccountId()) === null || _b === void 0 ? void 0 : _b.toString());
323
+ const matchingExtensionId = newSigner.extensionId === currentSigner.extensionId;
324
+ const newSignerMetadata = newSigner.getMetadata();
325
+ const existingSignerMetadata = currentSigner.getMetadata();
326
+ const metadataNameMatch = (newSignerMetadata === null || newSignerMetadata === void 0 ? void 0 : newSignerMetadata.name) === (existingSignerMetadata === null || existingSignerMetadata === void 0 ? void 0 : existingSignerMetadata.name);
327
+ if (currentSigner.topic === newSigner.topic) {
328
+ this.logger.error('The topic was already connected. This is a weird error. Please report it.', newSigner.getAccountId().toString());
329
+ }
330
+ return matchingAccountId && matchingExtensionId && metadataNameMatch;
331
+ });
332
+ // Any dupes get disconnected + removed from the signers array.
333
+ for (const existingSigner of existingSigners) {
334
+ this.logger.debug(`Disconnecting duplicate signer for account ${existingSigner.getAccountId().toString()}`);
335
+ await this.disconnect(existingSigner.topic);
336
+ this.signers = this.signers.filter((s) => s.topic !== existingSigner.topic);
337
+ }
338
+ }
339
+ // Add new signers after all duplicates have been cleaned up
340
+ this.signers.push(...newSigners);
341
+ this.logger.debug(`Current signers after connection: ${this.signers
342
+ .map((s) => `${s.getAccountId().toString()}:${s.topic}`)
343
+ .join(', ')}`);
296
344
  }
297
345
  async connectURI(pairingTopic) {
298
346
  if (!this.walletConnectClient) {
@@ -304,10 +352,25 @@ export class DAppConnector {
304
352
  });
305
353
  }
306
354
  async request({ method, params, }) {
307
- const signer = this.signers[this.signers.length - 1];
355
+ var _a, _b, _c;
356
+ let signer;
357
+ this.logger.debug(`Requesting method: ${method} with params: ${JSON.stringify(params)}`);
358
+ if (params === null || params === void 0 ? void 0 : params.signerAccountId) {
359
+ // Extract the actual account ID from the hedera:<network>:<address> format
360
+ const actualAccountId = (_b = (_a = params === null || params === void 0 ? void 0 : params.signerAccountId) === null || _a === void 0 ? void 0 : _a.split(':')) === null || _b === void 0 ? void 0 : _b.pop();
361
+ signer = this.signers.find((s) => { var _a; return ((_a = s === null || s === void 0 ? void 0 : s.getAccountId()) === null || _a === void 0 ? void 0 : _a.toString()) === actualAccountId; });
362
+ this.logger.debug(`Found signer: ${(_c = signer === null || signer === void 0 ? void 0 : signer.getAccountId()) === null || _c === void 0 ? void 0 : _c.toString()}`);
363
+ if (!signer) {
364
+ throw new Error(`Signer not found for account ID: ${params === null || params === void 0 ? void 0 : params.signerAccountId}. Did you use the correct format? e.g hedera:<network>:<address> `);
365
+ }
366
+ }
367
+ else {
368
+ signer = this.signers[this.signers.length - 1];
369
+ }
308
370
  if (!signer) {
309
371
  throw new Error('There is no active session. Connect to the wallet at first.');
310
372
  }
373
+ this.logger.debug(`Using signer: ${signer.getAccountId().toString()}: ${signer.topic} - about to request.`);
311
374
  return await signer.request({
312
375
  method: method,
313
376
  params: params,
@@ -357,7 +420,7 @@ export class DAppConnector {
357
420
  * @example
358
421
  * ```ts
359
422
  * const params = {
360
- * signerAccountId: '0.0.12345',
423
+ * signerAccountId: 'hedera:testnet:0.0.12345',
361
424
  * message: 'Hello World!'
362
425
  * }
363
426
  *
@@ -444,5 +507,39 @@ export class DAppConnector {
444
507
  params,
445
508
  });
446
509
  }
510
+ handleSessionEvent(args) {
511
+ this.logger.debug('Session event received:', args);
512
+ this.validateAndRefreshSigners();
513
+ }
514
+ handleSessionUpdate({ topic, params, }) {
515
+ const { namespaces } = params;
516
+ const _session = this.walletConnectClient.session.get(topic);
517
+ const updatedSession = Object.assign(Object.assign({}, _session), { namespaces });
518
+ this.logger.info('Session updated:', updatedSession);
519
+ this.signers = this.signers.filter((signer) => signer.topic !== topic);
520
+ this.signers.push(...this.createSigners(updatedSession));
521
+ }
522
+ handleSessionDelete(event) {
523
+ this.logger.info('Session deleted:', event);
524
+ this.signers = this.signers.filter((signer) => signer.topic !== event.topic);
525
+ try {
526
+ this.disconnect(event.topic);
527
+ }
528
+ catch (e) {
529
+ this.logger.error('Error disconnecting session:', e);
530
+ }
531
+ this.logger.info('Session deleted by wallet');
532
+ }
533
+ handlePairingDelete(event) {
534
+ this.logger.info('Pairing deleted:', event);
535
+ this.signers = this.signers.filter((signer) => signer.topic !== event.topic);
536
+ try {
537
+ this.disconnect(event.topic);
538
+ }
539
+ catch (e) {
540
+ this.logger.error('Error disconnecting pairing:', e);
541
+ }
542
+ this.logger.info('Pairing deleted by wallet');
543
+ }
447
544
  }
448
545
  export default DAppConnector;
@@ -0,0 +1,16 @@
1
+ export interface ILogger {
2
+ error(message: string, ...args: any[]): void;
3
+ warn(message: string, ...args: any[]): void;
4
+ info(message: string, ...args: any[]): void;
5
+ debug(message: string, ...args: any[]): void;
6
+ }
7
+ export declare class DefaultLogger implements ILogger {
8
+ private logLevel;
9
+ constructor(logLevel?: 'error' | 'warn' | 'info' | 'debug');
10
+ setLogLevel(level: 'error' | 'warn' | 'info' | 'debug'): void;
11
+ getLogLevel(): 'error' | 'warn' | 'info' | 'debug';
12
+ error(message: string, ...args: any[]): void;
13
+ warn(message: string, ...args: any[]): void;
14
+ info(message: string, ...args: any[]): void;
15
+ debug(message: string, ...args: any[]): void;
16
+ }
@@ -0,0 +1,32 @@
1
+ export class DefaultLogger {
2
+ constructor(logLevel = 'info') {
3
+ this.logLevel = 'info';
4
+ this.logLevel = logLevel;
5
+ }
6
+ setLogLevel(level) {
7
+ this.logLevel = level;
8
+ }
9
+ getLogLevel() {
10
+ return this.logLevel;
11
+ }
12
+ error(message, ...args) {
13
+ if (['error', 'warn', 'info', 'debug'].includes(this.logLevel)) {
14
+ console.error(`[ERROR] ${message}`, ...args);
15
+ }
16
+ }
17
+ warn(message, ...args) {
18
+ if (['warn', 'info', 'debug'].includes(this.logLevel)) {
19
+ console.warn(`[WARN] ${message}`, ...args);
20
+ }
21
+ }
22
+ info(message, ...args) {
23
+ if (['info', 'debug'].includes(this.logLevel)) {
24
+ console.info(`[INFO] ${message}`, ...args);
25
+ }
26
+ }
27
+ debug(message, ...args) {
28
+ if (this.logLevel === 'debug') {
29
+ console.debug(`[DEBUG] ${message}`, ...args);
30
+ }
31
+ }
32
+ }
@@ -49,8 +49,8 @@ export declare function base64StringToTransaction<T extends Transaction>(transac
49
49
  * @param transaction - a base64 encoded string of proto.TransactionBody.encode().finish()
50
50
  * @returns `string`
51
51
  * */
52
- export declare function transactionToTransactionBody<T extends Transaction>(transaction: T, nodeAccountId: AccountId): Uint8Array | null | undefined;
53
- export declare function transactionBodyToBase64String(transactionBody: Uint8Array): string;
52
+ export declare function transactionToTransactionBody<T extends Transaction>(transaction: T, nodeAccountId: AccountId): any;
53
+ export declare function transactionBodyToBase64String(transactionBody: proto.ITransactionBody): string;
54
54
  /**
55
55
  * @param transactionList - a proto.TransactionList object
56
56
  * @returns `string`