@dynamic-labs/multi-wallet 0.16.5 → 0.16.7

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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
1
 
2
+ ### [0.16.7](https://github.com/dynamic-labs/DynamicAuth/compare/v0.16.6...v0.16.7) (2023-04-24)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * **Cypress:** add polyfills ([#1945](https://github.com/dynamic-labs/DynamicAuth/issues/1945)) ([093c9f9](https://github.com/dynamic-labs/DynamicAuth/commit/093c9f98725f90f3dea49328e76c5f126fa6478d))
8
+ * **DYN-2261:** hide authorization flow after network switch ([#1942](https://github.com/dynamic-labs/DynamicAuth/issues/1942)) ([0b44470](https://github.com/dynamic-labs/DynamicAuth/commit/0b444708183ffcbfd5302f3e48f69c0d0de6a0b4))
9
+ * remove listeners properly ([#1940](https://github.com/dynamic-labs/DynamicAuth/issues/1940)) ([aaca308](https://github.com/dynamic-labs/DynamicAuth/commit/aaca308e834149d50322768887c308171f9f767f))
10
+
11
+ ### [0.16.6](https://github.com/dynamic-labs/DynamicAuth/compare/v0.16.5...v0.16.6) (2023-04-23)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * wait for safe transaction validation before verify call v16 ([#1930](https://github.com/dynamic-labs/DynamicAuth/issues/1930)) ([6064455](https://github.com/dynamic-labs/DynamicAuth/commit/60644554916100bffc4c5e1090475b3f7b9b79c3))
17
+
2
18
  ### [0.16.5](https://github.com/dynamic-labs/DynamicAuth/compare/v0.16.4...v0.16.5) (2023-04-22)
3
19
 
4
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/multi-wallet",
3
- "version": "0.16.5",
3
+ "version": "0.16.7",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -28,8 +28,8 @@
28
28
  "magic-sdk": "^16.0.1",
29
29
  "@keplr-wallet/provider": "0.11.56",
30
30
  "@keplr-wallet/types": "^0.11.51",
31
- "@dynamic-labs/logger": "0.16.5",
32
- "@dynamic-labs/wallet-connector-core": "0.16.5"
31
+ "@dynamic-labs/logger": "0.16.7",
32
+ "@dynamic-labs/wallet-connector-core": "0.16.7"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@walletconnect/types": "^2.2.1"
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
6
  var Client = require('@walletconnect/client');
7
+ var ethers = require('ethers');
7
8
  var isMobile = require('../../../utils/isMobile.cjs');
8
9
  var isSameAddress = require('../../../utils/isSameAddress/isSameAddress.cjs');
9
10
  var logger = require('../../../utils/logger.cjs');
@@ -156,7 +157,7 @@ const fetchWalletConnectEVMPublicAddress = (metadata, wcClient, opts) => tslib._
156
157
  const [accountPublicAddress] = payload.params[0].accounts;
157
158
  return accountPublicAddress;
158
159
  });
159
- const signWalletConnectPersonalMessage = (messageToSign, metadata, client) => tslib.__awaiter(void 0, void 0, void 0, function* () {
160
+ const signWalletConnectPersonalMessage = (messageToSign, metadata, client, rpcProvider) => tslib.__awaiter(void 0, void 0, void 0, function* () {
160
161
  var _c, _d;
161
162
  const isCryptoWallet = ((_c = client === null || client === void 0 ? void 0 : client.peerMeta) === null || _c === void 0 ? void 0 : _c.name) === 'Crypto.com | DeFi Wallet' ||
162
163
  ((_d = client === null || client === void 0 ? void 0 : client.peerMeta) === null || _d === void 0 ? void 0 : _d.name) === 'DeFi Wallet';
@@ -184,12 +185,63 @@ const signWalletConnectPersonalMessage = (messageToSign, metadata, client) => ts
184
185
  // and not allowing the user to sign the message
185
186
  yield sleep(1000);
186
187
  }
187
- return client.signPersonalMessage([messageToSign, accountPublicAddress]);
188
+ const signature = yield client.signPersonalMessage([
189
+ messageToSign,
190
+ accountPublicAddress,
191
+ ]);
192
+ yield waitForSafeTransactionOrTimeout(accountPublicAddress, signature, messageToSign, client, rpcProvider);
193
+ return signature;
188
194
  }
189
195
  catch (e) {
190
196
  logger.logger.debug(e);
191
197
  throw e;
192
198
  }
199
+ });
200
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
201
+ // Successful value as defined by the EIP
202
+ // https://eips.ethereum.org/EIPS/eip-1271#specification
203
+ const MAGIC_VALUE = '0x1626ba7e';
204
+ const IS_VALID_SIGNATURE_ABI = [
205
+ 'function isValidSignature(bytes32 _message, bytes _signature) public view returns (bytes4)',
206
+ ];
207
+ const waitForSafeTransactionOrTimeout = (accountPublicAddress, signature, messageToSign, client, rpcProvider) => tslib.__awaiter(void 0, void 0, void 0, function* () {
208
+ var _e;
209
+ if (signature === '0x' &&
210
+ // this is what wallet connect client returns there's no `safe` or `Safe`
211
+ // exact string anywhere, so this seems like the best proxy
212
+ ((_e = client.peerMeta) === null || _e === void 0 ? void 0 : _e.name) === 'WalletConnect Safe App') {
213
+ if (!rpcProvider) {
214
+ return;
215
+ }
216
+ const contract = new ethers.Contract(accountPublicAddress, IS_VALID_SIGNATURE_ABI, yield rpcProvider());
217
+ const safeTransactionPromise = waitForSafeTransaction(signature, messageToSign, contract);
218
+ const timeoutPromise = new Promise((resolve) => {
219
+ setTimeout(resolve, 120000);
220
+ });
221
+ yield Promise.race([safeTransactionPromise, timeoutPromise]);
222
+ }
223
+ });
224
+ // this is a hack for safe
225
+ // before sending the signature downstream, we need to make sure
226
+ // the transaction is recorded first on the blockchain
227
+ // redcoast verify WILL fail if it attempts to verify the signature
228
+ // that has not yet been properly processed!
229
+ const waitForSafeTransaction = (signature, messageToSign, contract) => tslib.__awaiter(void 0, void 0, void 0, function* () {
230
+ // wait for safe wallet to finish txn on the blockchain contract
231
+ for (let i = 0; i < 120; i++) {
232
+ try {
233
+ // this will result in an exception if the transaction is still not ready
234
+ // we need to catch it below
235
+ const result = yield contract.isValidSignature(ethers.ethers.utils.hashMessage(messageToSign), signature);
236
+ if (result === MAGIC_VALUE)
237
+ return;
238
+ }
239
+ catch (err) {
240
+ logger.logger.info('Safe transaction cannot be validated yet. Retrying.');
241
+ }
242
+ // try again after 2 seconds
243
+ yield sleep(2000);
244
+ }
193
245
  });
194
246
 
195
247
  exports.createSession = createSession;
@@ -1,4 +1,5 @@
1
1
  import Client from '@walletconnect/client';
2
+ import { ethers } from 'ethers';
2
3
  import { FetchPublicAddressOpts, PayloadParams, WalletEventListeners } from '@dynamic-labs/wallet-connector-core';
3
4
  import { WalletSchema } from '@dynamic-labs/wallet-book';
4
5
  import { KeplrWalletConnectV1 } from '../../cosmos/wcClient';
@@ -19,4 +20,4 @@ export declare const createSession: (client: Client) => Promise<PayloadParams>;
19
20
  export declare const useDeepLink: (metadata: WalletSchema, wcClient: Client, opts?: FetchPublicAddressOpts) => void;
20
21
  export declare const fetchWalletConnectCosmosPublicAddress: (metadata: WalletSchema, wcClient: Client, provider: KeplrWalletConnectV1, opts: FetchPublicAddressOpts & Required<Pick<FetchPublicAddressOpts, 'chainId'>>) => Promise<string>;
21
22
  export declare const fetchWalletConnectEVMPublicAddress: (metadata: WalletSchema, wcClient: Client, opts?: FetchPublicAddressOpts) => Promise<string | undefined>;
22
- export declare const signWalletConnectPersonalMessage: (messageToSign: string, metadata: WalletSchema, client: Client) => Promise<string | undefined>;
23
+ export declare const signWalletConnectPersonalMessage: (messageToSign: string, metadata: WalletSchema, client: Client, rpcProvider?: () => Promise<ethers.providers.JsonRpcProvider | undefined>) => Promise<string | undefined>;
@@ -1,5 +1,6 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import Client from '@walletconnect/client';
3
+ import { Contract, ethers } from 'ethers';
3
4
  import { isMobile, isIOS } from '../../../utils/isMobile.js';
4
5
  import { isSameAddress } from '../../../utils/isSameAddress/isSameAddress.js';
5
6
  import { logger } from '../../../utils/logger.js';
@@ -148,7 +149,7 @@ const fetchWalletConnectEVMPublicAddress = (metadata, wcClient, opts) => __await
148
149
  const [accountPublicAddress] = payload.params[0].accounts;
149
150
  return accountPublicAddress;
150
151
  });
151
- const signWalletConnectPersonalMessage = (messageToSign, metadata, client) => __awaiter(void 0, void 0, void 0, function* () {
152
+ const signWalletConnectPersonalMessage = (messageToSign, metadata, client, rpcProvider) => __awaiter(void 0, void 0, void 0, function* () {
152
153
  var _c, _d;
153
154
  const isCryptoWallet = ((_c = client === null || client === void 0 ? void 0 : client.peerMeta) === null || _c === void 0 ? void 0 : _c.name) === 'Crypto.com | DeFi Wallet' ||
154
155
  ((_d = client === null || client === void 0 ? void 0 : client.peerMeta) === null || _d === void 0 ? void 0 : _d.name) === 'DeFi Wallet';
@@ -176,12 +177,63 @@ const signWalletConnectPersonalMessage = (messageToSign, metadata, client) => __
176
177
  // and not allowing the user to sign the message
177
178
  yield sleep(1000);
178
179
  }
179
- return client.signPersonalMessage([messageToSign, accountPublicAddress]);
180
+ const signature = yield client.signPersonalMessage([
181
+ messageToSign,
182
+ accountPublicAddress,
183
+ ]);
184
+ yield waitForSafeTransactionOrTimeout(accountPublicAddress, signature, messageToSign, client, rpcProvider);
185
+ return signature;
180
186
  }
181
187
  catch (e) {
182
188
  logger.debug(e);
183
189
  throw e;
184
190
  }
191
+ });
192
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
193
+ // Successful value as defined by the EIP
194
+ // https://eips.ethereum.org/EIPS/eip-1271#specification
195
+ const MAGIC_VALUE = '0x1626ba7e';
196
+ const IS_VALID_SIGNATURE_ABI = [
197
+ 'function isValidSignature(bytes32 _message, bytes _signature) public view returns (bytes4)',
198
+ ];
199
+ const waitForSafeTransactionOrTimeout = (accountPublicAddress, signature, messageToSign, client, rpcProvider) => __awaiter(void 0, void 0, void 0, function* () {
200
+ var _e;
201
+ if (signature === '0x' &&
202
+ // this is what wallet connect client returns there's no `safe` or `Safe`
203
+ // exact string anywhere, so this seems like the best proxy
204
+ ((_e = client.peerMeta) === null || _e === void 0 ? void 0 : _e.name) === 'WalletConnect Safe App') {
205
+ if (!rpcProvider) {
206
+ return;
207
+ }
208
+ const contract = new Contract(accountPublicAddress, IS_VALID_SIGNATURE_ABI, yield rpcProvider());
209
+ const safeTransactionPromise = waitForSafeTransaction(signature, messageToSign, contract);
210
+ const timeoutPromise = new Promise((resolve) => {
211
+ setTimeout(resolve, 120000);
212
+ });
213
+ yield Promise.race([safeTransactionPromise, timeoutPromise]);
214
+ }
215
+ });
216
+ // this is a hack for safe
217
+ // before sending the signature downstream, we need to make sure
218
+ // the transaction is recorded first on the blockchain
219
+ // redcoast verify WILL fail if it attempts to verify the signature
220
+ // that has not yet been properly processed!
221
+ const waitForSafeTransaction = (signature, messageToSign, contract) => __awaiter(void 0, void 0, void 0, function* () {
222
+ // wait for safe wallet to finish txn on the blockchain contract
223
+ for (let i = 0; i < 120; i++) {
224
+ try {
225
+ // this will result in an exception if the transaction is still not ready
226
+ // we need to catch it below
227
+ const result = yield contract.isValidSignature(ethers.utils.hashMessage(messageToSign), signature);
228
+ if (result === MAGIC_VALUE)
229
+ return;
230
+ }
231
+ catch (err) {
232
+ logger.info('Safe transaction cannot be validated yet. Retrying.');
233
+ }
234
+ // try again after 2 seconds
235
+ yield sleep(2000);
236
+ }
185
237
  });
186
238
 
187
239
  export { createSession, fetchWalletConnectCosmosPublicAddress, fetchWalletConnectEVMPublicAddress, getDeepLink, initClient, killWalletConnectSession, setupWalletConnectEventListeners, signWalletConnectPersonalMessage, teardownWalletConnectEventListeners, useDeepLink };
@@ -150,7 +150,7 @@ class EthProviderHelper {
150
150
  // nothing to teardown
151
151
  };
152
152
  }
153
- const provider = web3Provider.provider;
153
+ const externalProvider = web3Provider.provider;
154
154
  this.handleAccountChange = (accounts) => tslib.__awaiter(this, void 0, void 0, function* () {
155
155
  var _a, _b;
156
156
  if (accounts.length === 0) {
@@ -171,19 +171,26 @@ class EthProviderHelper {
171
171
  }
172
172
  yield ((_d = listeners.onDisconnect) === null || _d === void 0 ? void 0 : _d.call(listeners));
173
173
  });
174
- provider.on('accountsChanged', this.handleAccountChange);
175
- provider.on('chainChanged', this.handleChainChange);
176
- provider.on('disconnect', this.handleDisconnect);
174
+ externalProvider.on('accountsChanged', this.handleAccountChange);
175
+ externalProvider.on('chainChanged', this.handleChainChange);
176
+ externalProvider.on('disconnect', this.handleDisconnect);
177
177
  return () => { };
178
178
  }
179
179
  _teardownEventListeners(name) {
180
180
  const web3Provider = this.findProvider(name);
181
- if (!web3Provider) {
181
+ if (!web3Provider || !(web3Provider === null || web3Provider === void 0 ? void 0 : web3Provider.provider)) {
182
182
  return;
183
183
  }
184
- web3Provider.off('accountsChanged', this.handleAccountChange);
185
- web3Provider.off('chainChangedm', this.handleChainChange);
186
- web3Provider.off('disconnect', this.handleDisconnect);
184
+ const externalProvider = web3Provider.provider;
185
+ if (this.handleAccountChange) {
186
+ externalProvider.removeListener('accountsChanged', this.handleAccountChange);
187
+ }
188
+ if (this.handleChainChange) {
189
+ externalProvider.removeListener('chainChanged', this.handleChainChange);
190
+ }
191
+ if (this.handleDisconnect) {
192
+ externalProvider.removeListener('disconnect', this.handleDisconnect);
193
+ }
187
194
  }
188
195
  }
189
196
 
@@ -146,7 +146,7 @@ class EthProviderHelper {
146
146
  // nothing to teardown
147
147
  };
148
148
  }
149
- const provider = web3Provider.provider;
149
+ const externalProvider = web3Provider.provider;
150
150
  this.handleAccountChange = (accounts) => __awaiter(this, void 0, void 0, function* () {
151
151
  var _a, _b;
152
152
  if (accounts.length === 0) {
@@ -167,19 +167,26 @@ class EthProviderHelper {
167
167
  }
168
168
  yield ((_d = listeners.onDisconnect) === null || _d === void 0 ? void 0 : _d.call(listeners));
169
169
  });
170
- provider.on('accountsChanged', this.handleAccountChange);
171
- provider.on('chainChanged', this.handleChainChange);
172
- provider.on('disconnect', this.handleDisconnect);
170
+ externalProvider.on('accountsChanged', this.handleAccountChange);
171
+ externalProvider.on('chainChanged', this.handleChainChange);
172
+ externalProvider.on('disconnect', this.handleDisconnect);
173
173
  return () => { };
174
174
  }
175
175
  _teardownEventListeners(name) {
176
176
  const web3Provider = this.findProvider(name);
177
- if (!web3Provider) {
177
+ if (!web3Provider || !(web3Provider === null || web3Provider === void 0 ? void 0 : web3Provider.provider)) {
178
178
  return;
179
179
  }
180
- web3Provider.off('accountsChanged', this.handleAccountChange);
181
- web3Provider.off('chainChangedm', this.handleChainChange);
182
- web3Provider.off('disconnect', this.handleDisconnect);
180
+ const externalProvider = web3Provider.provider;
181
+ if (this.handleAccountChange) {
182
+ externalProvider.removeListener('accountsChanged', this.handleAccountChange);
183
+ }
184
+ if (this.handleChainChange) {
185
+ externalProvider.removeListener('chainChanged', this.handleChainChange);
186
+ }
187
+ if (this.handleDisconnect) {
188
+ externalProvider.removeListener('disconnect', this.handleDisconnect);
189
+ }
183
190
  }
184
191
  }
185
192
 
@@ -94,7 +94,9 @@ class WalletConnect extends ethProvider.EthProvider {
94
94
  }
95
95
  signMessage(messageToSign) {
96
96
  return tslib.__awaiter(this, void 0, void 0, function* () {
97
- return walletConnect.signWalletConnectPersonalMessage(messageToSign, walletBook.getWalletBookWallet(this.name), this.getClient());
97
+ return walletConnect.signWalletConnectPersonalMessage(messageToSign, walletBook.getWalletBookWallet(this.name), this.getClient(),
98
+ // don't call getRpcProvider until we really need to
99
+ () => tslib.__awaiter(this, void 0, void 0, function* () { return this.getRpcProvider(); }));
98
100
  });
99
101
  }
100
102
  proveOwnership(messageToSign) {
@@ -88,7 +88,9 @@ class WalletConnect extends EthProvider {
88
88
  }
89
89
  signMessage(messageToSign) {
90
90
  return __awaiter(this, void 0, void 0, function* () {
91
- return signWalletConnectPersonalMessage(messageToSign, getWalletBookWallet(this.name), this.getClient());
91
+ return signWalletConnectPersonalMessage(messageToSign, getWalletBookWallet(this.name), this.getClient(),
92
+ // don't call getRpcProvider until we really need to
93
+ () => __awaiter(this, void 0, void 0, function* () { return this.getRpcProvider(); }));
92
94
  });
93
95
  }
94
96
  proveOwnership(messageToSign) {