@dynamic-labs/multi-wallet 0.16.5 → 0.16.6

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,11 @@
1
1
 
2
+ ### [0.16.6](https://github.com/dynamic-labs/DynamicAuth/compare/v0.16.5...v0.16.6) (2023-04-23)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * 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))
8
+
2
9
  ### [0.16.5](https://github.com/dynamic-labs/DynamicAuth/compare/v0.16.4...v0.16.5) (2023-04-22)
3
10
 
4
11
 
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.6",
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.6",
32
+ "@dynamic-labs/wallet-connector-core": "0.16.6"
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 };
@@ -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) {