@0xsequence/provider 0.33.3 → 0.35.1

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,5 +1,68 @@
1
1
  # @0xsequence/provider
2
2
 
3
+ ## 0.35.1
4
+
5
+ ### Patch Changes
6
+
7
+ - wallet: update config on undeployed too
8
+ - Updated dependencies
9
+ - @0xsequence/abi@0.35.1
10
+ - @0xsequence/auth@0.35.1
11
+ - @0xsequence/config@0.35.1
12
+ - @0xsequence/network@0.35.1
13
+ - @0xsequence/transactions@0.35.1
14
+ - @0xsequence/utils@0.35.1
15
+ - @0xsequence/wallet@0.35.1
16
+
17
+ ## 0.35.0
18
+
19
+ ### Minor Changes
20
+
21
+ - - config: add buildStubSignature
22
+ - provider: add checks to signing cases for wallet deployment and config statuses
23
+ - provider: add prompt for wallet deployment
24
+ - relayer: add BaseRelayer.prependWalletDeploy
25
+ - relayer: add Relayer.feeOptions
26
+ - relayer: account for wallet deployment in fee estimation
27
+ - transactions: add fromTransactionish
28
+ - wallet: add Account.prependConfigUpdate
29
+ - wallet: add Account.getFeeOptions
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies
34
+ - @0xsequence/abi@0.35.0
35
+ - @0xsequence/auth@0.35.0
36
+ - @0xsequence/config@0.35.0
37
+ - @0xsequence/network@0.35.0
38
+ - @0xsequence/transactions@0.35.0
39
+ - @0xsequence/utils@0.35.0
40
+ - @0xsequence/wallet@0.35.0
41
+
42
+ ## 0.34.1
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies
47
+ - @0xsequence/auth@0.34.1
48
+
49
+ ## 0.34.0
50
+
51
+ ### Minor Changes
52
+
53
+ - - upgrade deps
54
+
55
+ ### Patch Changes
56
+
57
+ - Updated dependencies
58
+ - @0xsequence/abi@0.34.0
59
+ - @0xsequence/auth@0.34.0
60
+ - @0xsequence/config@0.34.0
61
+ - @0xsequence/network@0.34.0
62
+ - @0xsequence/transactions@0.34.0
63
+ - @0xsequence/utils@0.34.0
64
+ - @0xsequence/wallet@0.34.0
65
+
3
66
  ## 0.33.3
4
67
 
5
68
  ### Patch Changes
@@ -494,7 +494,54 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
494
494
 
495
495
  return config$1;
496
496
  };
497
- const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'; // window.localstorage helper
497
+ const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
498
+ /**
499
+ * Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
500
+ *
501
+ * @param {Signer} signer
502
+ * @param {number} chainId
503
+ * @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
504
+ */
505
+
506
+ const isWalletUpToDate = async (signer, chainId) => {
507
+ var _walletState$find;
508
+
509
+ const walletState = await signer.getWalletState();
510
+ const networks = await signer.getNetworks();
511
+ const walletStateForRequiredChain = walletState.find(state => state.chainId === chainId);
512
+
513
+ if (!walletStateForRequiredChain) {
514
+ throw new Error(`WalletRequestHandler: could not find wallet state for chainId ${chainId}`);
515
+ }
516
+
517
+ const isDeployed = walletStateForRequiredChain.deployed;
518
+
519
+ if (!networks) {
520
+ throw new Error(`isWalletUpToDate util: could not get networks from signer`);
521
+ }
522
+
523
+ const authChain = networks.find(network => network.isAuthChain);
524
+
525
+ if (!authChain) {
526
+ throw new Error(`isWalletUpToDate util: could not get auth chain network information`);
527
+ }
528
+
529
+ const authChainId = authChain.chainId;
530
+ const authChainConfig = (_walletState$find = walletState.find(state => state.chainId === authChainId)) == null ? void 0 : _walletState$find.config;
531
+
532
+ if (!authChainConfig) {
533
+ throw new Error(`isWalletUpToDate util: could not get auth chain config`);
534
+ }
535
+
536
+ const requiredChainConfig = walletStateForRequiredChain.config;
537
+
538
+ if (!requiredChainConfig) {
539
+ throw new Error(`isWalletUpToDate util: could not get config for chainId ${chainId}`);
540
+ }
541
+
542
+ const isUpToDate = config.isConfigEqual(authChainConfig, requiredChainConfig);
543
+ return isDeployed && isUpToDate;
544
+ }; // window.localstorage helper
498
545
 
499
546
  class LocalStore {
500
547
  constructor(key, def) {
@@ -1733,37 +1780,21 @@ class WalletRequestHandler {
1733
1780
  }
1734
1781
 
1735
1782
  case 'personal_sign':
1783
+ case 'eth_sign':
1736
1784
  {
1737
1785
  // note: message from json-rpc input is in hex format
1738
- const [message, signingAddress] = request.params;
1739
- let sig = ''; // TODO:
1740
- // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1741
-
1742
- if (_this.prompter === null) {
1743
- // prompter is null, so we'll sign from here
1744
- sig = await signer.signMessage(ethers.ethers.utils.arrayify(message), chainId);
1745
- } else {
1746
- // prompt user to provide the response
1747
- sig = await _this.prompter.promptSignMessage({
1748
- chainId: chainId,
1749
- message: message
1750
- });
1751
- }
1786
+ let message; // there is a difference in the order of the params:
1787
+ // personal_sign: [data, address]
1788
+ // eth_sign: [address, data]
1752
1789
 
1753
- if (sig && sig.length > 0) {
1754
- response.result = sig;
1790
+ if (request.method === 'personal_sign') {
1791
+ const [data, address] = request.params;
1792
+ message = data;
1755
1793
  } else {
1756
- // The user has declined the request when value is null
1757
- throw new Error('declined by user');
1794
+ const [address, data] = request.params;
1795
+ message = data;
1758
1796
  }
1759
1797
 
1760
- break;
1761
- }
1762
-
1763
- case 'eth_sign':
1764
- {
1765
- // note: message from json-rpc input is in hex format
1766
- const [signingAddress, message] = request.params;
1767
1798
  let sig = ''; // TODO:
1768
1799
  // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1769
1800
 
@@ -1771,11 +1802,14 @@ class WalletRequestHandler {
1771
1802
  // prompter is null, so we'll sign from here
1772
1803
  sig = await signer.signMessage(ethers.ethers.utils.arrayify(message), chainId);
1773
1804
  } else {
1774
- // prompt user to provide the response
1775
- sig = await _this.prompter.promptSignMessage({
1776
- chainId: chainId,
1777
- message: message
1778
- });
1805
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1806
+
1807
+ if (promptResultForDeployment) {
1808
+ sig = await _this.prompter.promptSignMessage({
1809
+ chainId: chainId,
1810
+ message: message
1811
+ });
1812
+ }
1779
1813
  }
1780
1814
 
1781
1815
  if (sig && sig.length > 0) {
@@ -1814,11 +1848,14 @@ class WalletRequestHandler {
1814
1848
  // prompter is null, so we'll sign from here
1815
1849
  sig = await signer.signTypedData(typedData.domain, typedData.types, typedData.message, chainId);
1816
1850
  } else {
1817
- // prompt user to provide the response
1818
- sig = await _this.prompter.promptSignMessage({
1819
- chainId: chainId,
1820
- typedData: typedData
1821
- });
1851
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1852
+
1853
+ if (promptResultForDeployment) {
1854
+ sig = await _this.prompter.promptSignMessage({
1855
+ chainId: chainId,
1856
+ typedData: typedData
1857
+ });
1858
+ }
1822
1859
  }
1823
1860
 
1824
1861
  if (sig && sig.length > 0) {
@@ -2346,6 +2383,35 @@ class WalletRequestHandler {
2346
2383
  this.signer = signer;
2347
2384
  }
2348
2385
 
2386
+ async handleConfirmWalletDeployPrompt(prompter, signer, chainId) {
2387
+ // check if wallet is deployed and up to date, if not, prompt user to deploy
2388
+ // if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
2389
+ if (!chainId) {
2390
+ return true;
2391
+ }
2392
+
2393
+ const isUpToDate = await isWalletUpToDate(signer, chainId);
2394
+
2395
+ if (isUpToDate) {
2396
+ return true;
2397
+ }
2398
+
2399
+ const promptResult = await prompter.promptConfirmWalletDeploy(chainId); // if client returned true, check again to make sure wallet is deployed and up to date
2400
+
2401
+ if (promptResult) {
2402
+ const isPromptResultCorrect = await isWalletUpToDate(signer, chainId);
2403
+
2404
+ if (!isPromptResultCorrect) {
2405
+ utils.logger.error('WalletRequestHandler: result for promptConfirmWalletDeploy is not correct');
2406
+ return false;
2407
+ } else {
2408
+ return true;
2409
+ }
2410
+ }
2411
+
2412
+ return false;
2413
+ }
2414
+
2349
2415
  }
2350
2416
  const permittedJsonRpcMethods = ['net_version', 'eth_chainId', 'eth_getBalance', 'eth_getTransactionCount', 'eth_blockNumber', 'eth_getBlockByNumber', 'eth_getBlockByHash', 'eth_getTransactionByHash', 'eth_getCode', 'eth_estimateGas', 'eth_gasPrice', 'sequence_getWalletContext', 'sequence_getNetworks', 'sequence_setDefaultNetwork'];
2351
2417
 
@@ -3580,5 +3646,6 @@ exports.WindowSessionParams = WindowSessionParams;
3580
3646
  exports.isBrowserExtension = isBrowserExtension;
3581
3647
  exports.isSequenceProvider = isSequenceProvider;
3582
3648
  exports.isValidSignature = isValidSignature;
3649
+ exports.isWalletUpToDate = isWalletUpToDate;
3583
3650
  exports.nextMessageIdx = nextMessageIdx;
3584
3651
  exports.recoverWalletConfig = recoverWalletConfig;
@@ -494,7 +494,54 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
494
494
 
495
495
  return config$1;
496
496
  };
497
- const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'; // window.localstorage helper
497
+ const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
498
+ /**
499
+ * Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
500
+ *
501
+ * @param {Signer} signer
502
+ * @param {number} chainId
503
+ * @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
504
+ */
505
+
506
+ const isWalletUpToDate = async (signer, chainId) => {
507
+ var _walletState$find;
508
+
509
+ const walletState = await signer.getWalletState();
510
+ const networks = await signer.getNetworks();
511
+ const walletStateForRequiredChain = walletState.find(state => state.chainId === chainId);
512
+
513
+ if (!walletStateForRequiredChain) {
514
+ throw new Error(`WalletRequestHandler: could not find wallet state for chainId ${chainId}`);
515
+ }
516
+
517
+ const isDeployed = walletStateForRequiredChain.deployed;
518
+
519
+ if (!networks) {
520
+ throw new Error(`isWalletUpToDate util: could not get networks from signer`);
521
+ }
522
+
523
+ const authChain = networks.find(network => network.isAuthChain);
524
+
525
+ if (!authChain) {
526
+ throw new Error(`isWalletUpToDate util: could not get auth chain network information`);
527
+ }
528
+
529
+ const authChainId = authChain.chainId;
530
+ const authChainConfig = (_walletState$find = walletState.find(state => state.chainId === authChainId)) == null ? void 0 : _walletState$find.config;
531
+
532
+ if (!authChainConfig) {
533
+ throw new Error(`isWalletUpToDate util: could not get auth chain config`);
534
+ }
535
+
536
+ const requiredChainConfig = walletStateForRequiredChain.config;
537
+
538
+ if (!requiredChainConfig) {
539
+ throw new Error(`isWalletUpToDate util: could not get config for chainId ${chainId}`);
540
+ }
541
+
542
+ const isUpToDate = config.isConfigEqual(authChainConfig, requiredChainConfig);
543
+ return isDeployed && isUpToDate;
544
+ }; // window.localstorage helper
498
545
 
499
546
  class LocalStore {
500
547
  constructor(key, def) {
@@ -1733,37 +1780,21 @@ class WalletRequestHandler {
1733
1780
  }
1734
1781
 
1735
1782
  case 'personal_sign':
1783
+ case 'eth_sign':
1736
1784
  {
1737
1785
  // note: message from json-rpc input is in hex format
1738
- const [message, signingAddress] = request.params;
1739
- let sig = ''; // TODO:
1740
- // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1741
-
1742
- if (_this.prompter === null) {
1743
- // prompter is null, so we'll sign from here
1744
- sig = await signer.signMessage(ethers.ethers.utils.arrayify(message), chainId);
1745
- } else {
1746
- // prompt user to provide the response
1747
- sig = await _this.prompter.promptSignMessage({
1748
- chainId: chainId,
1749
- message: message
1750
- });
1751
- }
1786
+ let message; // there is a difference in the order of the params:
1787
+ // personal_sign: [data, address]
1788
+ // eth_sign: [address, data]
1752
1789
 
1753
- if (sig && sig.length > 0) {
1754
- response.result = sig;
1790
+ if (request.method === 'personal_sign') {
1791
+ const [data, address] = request.params;
1792
+ message = data;
1755
1793
  } else {
1756
- // The user has declined the request when value is null
1757
- throw new Error('declined by user');
1794
+ const [address, data] = request.params;
1795
+ message = data;
1758
1796
  }
1759
1797
 
1760
- break;
1761
- }
1762
-
1763
- case 'eth_sign':
1764
- {
1765
- // note: message from json-rpc input is in hex format
1766
- const [signingAddress, message] = request.params;
1767
1798
  let sig = ''; // TODO:
1768
1799
  // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1769
1800
 
@@ -1771,11 +1802,14 @@ class WalletRequestHandler {
1771
1802
  // prompter is null, so we'll sign from here
1772
1803
  sig = await signer.signMessage(ethers.ethers.utils.arrayify(message), chainId);
1773
1804
  } else {
1774
- // prompt user to provide the response
1775
- sig = await _this.prompter.promptSignMessage({
1776
- chainId: chainId,
1777
- message: message
1778
- });
1805
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1806
+
1807
+ if (promptResultForDeployment) {
1808
+ sig = await _this.prompter.promptSignMessage({
1809
+ chainId: chainId,
1810
+ message: message
1811
+ });
1812
+ }
1779
1813
  }
1780
1814
 
1781
1815
  if (sig && sig.length > 0) {
@@ -1814,11 +1848,14 @@ class WalletRequestHandler {
1814
1848
  // prompter is null, so we'll sign from here
1815
1849
  sig = await signer.signTypedData(typedData.domain, typedData.types, typedData.message, chainId);
1816
1850
  } else {
1817
- // prompt user to provide the response
1818
- sig = await _this.prompter.promptSignMessage({
1819
- chainId: chainId,
1820
- typedData: typedData
1821
- });
1851
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1852
+
1853
+ if (promptResultForDeployment) {
1854
+ sig = await _this.prompter.promptSignMessage({
1855
+ chainId: chainId,
1856
+ typedData: typedData
1857
+ });
1858
+ }
1822
1859
  }
1823
1860
 
1824
1861
  if (sig && sig.length > 0) {
@@ -2346,6 +2383,35 @@ class WalletRequestHandler {
2346
2383
  this.signer = signer;
2347
2384
  }
2348
2385
 
2386
+ async handleConfirmWalletDeployPrompt(prompter, signer, chainId) {
2387
+ // check if wallet is deployed and up to date, if not, prompt user to deploy
2388
+ // if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
2389
+ if (!chainId) {
2390
+ return true;
2391
+ }
2392
+
2393
+ const isUpToDate = await isWalletUpToDate(signer, chainId);
2394
+
2395
+ if (isUpToDate) {
2396
+ return true;
2397
+ }
2398
+
2399
+ const promptResult = await prompter.promptConfirmWalletDeploy(chainId); // if client returned true, check again to make sure wallet is deployed and up to date
2400
+
2401
+ if (promptResult) {
2402
+ const isPromptResultCorrect = await isWalletUpToDate(signer, chainId);
2403
+
2404
+ if (!isPromptResultCorrect) {
2405
+ utils.logger.error('WalletRequestHandler: result for promptConfirmWalletDeploy is not correct');
2406
+ return false;
2407
+ } else {
2408
+ return true;
2409
+ }
2410
+ }
2411
+
2412
+ return false;
2413
+ }
2414
+
2349
2415
  }
2350
2416
  const permittedJsonRpcMethods = ['net_version', 'eth_chainId', 'eth_getBalance', 'eth_getTransactionCount', 'eth_blockNumber', 'eth_getBlockByNumber', 'eth_getBlockByHash', 'eth_getTransactionByHash', 'eth_getCode', 'eth_estimateGas', 'eth_gasPrice', 'sequence_getWalletContext', 'sequence_getNetworks', 'sequence_setDefaultNetwork'];
2351
2417
 
@@ -3580,5 +3646,6 @@ exports.WindowSessionParams = WindowSessionParams;
3580
3646
  exports.isBrowserExtension = isBrowserExtension;
3581
3647
  exports.isSequenceProvider = isSequenceProvider;
3582
3648
  exports.isValidSignature = isValidSignature;
3649
+ exports.isWalletUpToDate = isWalletUpToDate;
3583
3650
  exports.nextMessageIdx = nextMessageIdx;
3584
3651
  exports.recoverWalletConfig = recoverWalletConfig;
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter2 } from 'eventemitter2';
2
2
  import { logger, packMessageData, sanitizeNumberString, sanitizeHost, sanitizeAlphanumeric, base64EncodeObject, base64DecodeObject, shallowCopy, resolveProperties, encodeMessageDigest, encodeTypedDataDigest } from '@0xsequence/utils';
3
3
  import { ethers, BigNumber } from 'ethers';
4
- import { addressOf } from '@0xsequence/config';
4
+ import { addressOf, isConfigEqual } from '@0xsequence/config';
5
5
  import { isValidSignature as isValidSignature$1, recoverConfig, Signer, resolveArrayProperties } from '@0xsequence/wallet';
6
6
  import { isSignedTransactions } from '@0xsequence/transactions';
7
7
  import { signAuthorization } from '@0xsequence/auth';
@@ -490,7 +490,54 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
490
490
 
491
491
  return config;
492
492
  };
493
- const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'; // window.localstorage helper
493
+ const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
494
+ /**
495
+ * Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
496
+ *
497
+ * @param {Signer} signer
498
+ * @param {number} chainId
499
+ * @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
500
+ */
501
+
502
+ const isWalletUpToDate = async (signer, chainId) => {
503
+ var _walletState$find;
504
+
505
+ const walletState = await signer.getWalletState();
506
+ const networks = await signer.getNetworks();
507
+ const walletStateForRequiredChain = walletState.find(state => state.chainId === chainId);
508
+
509
+ if (!walletStateForRequiredChain) {
510
+ throw new Error(`WalletRequestHandler: could not find wallet state for chainId ${chainId}`);
511
+ }
512
+
513
+ const isDeployed = walletStateForRequiredChain.deployed;
514
+
515
+ if (!networks) {
516
+ throw new Error(`isWalletUpToDate util: could not get networks from signer`);
517
+ }
518
+
519
+ const authChain = networks.find(network => network.isAuthChain);
520
+
521
+ if (!authChain) {
522
+ throw new Error(`isWalletUpToDate util: could not get auth chain network information`);
523
+ }
524
+
525
+ const authChainId = authChain.chainId;
526
+ const authChainConfig = (_walletState$find = walletState.find(state => state.chainId === authChainId)) == null ? void 0 : _walletState$find.config;
527
+
528
+ if (!authChainConfig) {
529
+ throw new Error(`isWalletUpToDate util: could not get auth chain config`);
530
+ }
531
+
532
+ const requiredChainConfig = walletStateForRequiredChain.config;
533
+
534
+ if (!requiredChainConfig) {
535
+ throw new Error(`isWalletUpToDate util: could not get config for chainId ${chainId}`);
536
+ }
537
+
538
+ const isUpToDate = isConfigEqual(authChainConfig, requiredChainConfig);
539
+ return isDeployed && isUpToDate;
540
+ }; // window.localstorage helper
494
541
 
495
542
  class LocalStore {
496
543
  constructor(key, def) {
@@ -1729,37 +1776,21 @@ class WalletRequestHandler {
1729
1776
  }
1730
1777
 
1731
1778
  case 'personal_sign':
1779
+ case 'eth_sign':
1732
1780
  {
1733
1781
  // note: message from json-rpc input is in hex format
1734
- const [message, signingAddress] = request.params;
1735
- let sig = ''; // TODO:
1736
- // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1737
-
1738
- if (_this.prompter === null) {
1739
- // prompter is null, so we'll sign from here
1740
- sig = await signer.signMessage(ethers.utils.arrayify(message), chainId);
1741
- } else {
1742
- // prompt user to provide the response
1743
- sig = await _this.prompter.promptSignMessage({
1744
- chainId: chainId,
1745
- message: message
1746
- });
1747
- }
1782
+ let message; // there is a difference in the order of the params:
1783
+ // personal_sign: [data, address]
1784
+ // eth_sign: [address, data]
1748
1785
 
1749
- if (sig && sig.length > 0) {
1750
- response.result = sig;
1786
+ if (request.method === 'personal_sign') {
1787
+ const [data, address] = request.params;
1788
+ message = data;
1751
1789
  } else {
1752
- // The user has declined the request when value is null
1753
- throw new Error('declined by user');
1790
+ const [address, data] = request.params;
1791
+ message = data;
1754
1792
  }
1755
1793
 
1756
- break;
1757
- }
1758
-
1759
- case 'eth_sign':
1760
- {
1761
- // note: message from json-rpc input is in hex format
1762
- const [signingAddress, message] = request.params;
1763
1794
  let sig = ''; // TODO:
1764
1795
  // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
1765
1796
 
@@ -1767,11 +1798,14 @@ class WalletRequestHandler {
1767
1798
  // prompter is null, so we'll sign from here
1768
1799
  sig = await signer.signMessage(ethers.utils.arrayify(message), chainId);
1769
1800
  } else {
1770
- // prompt user to provide the response
1771
- sig = await _this.prompter.promptSignMessage({
1772
- chainId: chainId,
1773
- message: message
1774
- });
1801
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1802
+
1803
+ if (promptResultForDeployment) {
1804
+ sig = await _this.prompter.promptSignMessage({
1805
+ chainId: chainId,
1806
+ message: message
1807
+ });
1808
+ }
1775
1809
  }
1776
1810
 
1777
1811
  if (sig && sig.length > 0) {
@@ -1810,11 +1844,14 @@ class WalletRequestHandler {
1810
1844
  // prompter is null, so we'll sign from here
1811
1845
  sig = await signer.signTypedData(typedData.domain, typedData.types, typedData.message, chainId);
1812
1846
  } else {
1813
- // prompt user to provide the response
1814
- sig = await _this.prompter.promptSignMessage({
1815
- chainId: chainId,
1816
- typedData: typedData
1817
- });
1847
+ const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
1848
+
1849
+ if (promptResultForDeployment) {
1850
+ sig = await _this.prompter.promptSignMessage({
1851
+ chainId: chainId,
1852
+ typedData: typedData
1853
+ });
1854
+ }
1818
1855
  }
1819
1856
 
1820
1857
  if (sig && sig.length > 0) {
@@ -2342,6 +2379,35 @@ class WalletRequestHandler {
2342
2379
  this.signer = signer;
2343
2380
  }
2344
2381
 
2382
+ async handleConfirmWalletDeployPrompt(prompter, signer, chainId) {
2383
+ // check if wallet is deployed and up to date, if not, prompt user to deploy
2384
+ // if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
2385
+ if (!chainId) {
2386
+ return true;
2387
+ }
2388
+
2389
+ const isUpToDate = await isWalletUpToDate(signer, chainId);
2390
+
2391
+ if (isUpToDate) {
2392
+ return true;
2393
+ }
2394
+
2395
+ const promptResult = await prompter.promptConfirmWalletDeploy(chainId); // if client returned true, check again to make sure wallet is deployed and up to date
2396
+
2397
+ if (promptResult) {
2398
+ const isPromptResultCorrect = await isWalletUpToDate(signer, chainId);
2399
+
2400
+ if (!isPromptResultCorrect) {
2401
+ logger.error('WalletRequestHandler: result for promptConfirmWalletDeploy is not correct');
2402
+ return false;
2403
+ } else {
2404
+ return true;
2405
+ }
2406
+ }
2407
+
2408
+ return false;
2409
+ }
2410
+
2345
2411
  }
2346
2412
  const permittedJsonRpcMethods = ['net_version', 'eth_chainId', 'eth_getBalance', 'eth_getTransactionCount', 'eth_blockNumber', 'eth_getBlockByNumber', 'eth_getBlockByHash', 'eth_getTransactionByHash', 'eth_getCode', 'eth_estimateGas', 'eth_gasPrice', 'sequence_getWalletContext', 'sequence_getNetworks', 'sequence_setDefaultNetwork'];
2347
2413
 
@@ -3549,4 +3615,4 @@ const DefaultProviderConfig = {
3549
3615
  }
3550
3616
  };
3551
3617
 
3552
- export { BaseInjectedTransport, BaseProviderTransport, BaseWalletTransport, CHANNEL_ID, DefaultProviderConfig, ErrSignedInRequired, EventType, ExtensionMessageHandler, ExtensionMessageProvider, InitState, LocalStore, LocalWeb3Provider, MuxMessageProvider, OpenState, PROVIDER_OPEN_TIMEOUT, ProviderError, ProxyMessageChannel, ProxyMessageChannelPort, ProxyMessageHandler, ProxyMessageProvider, Wallet, WalletRequestHandler, Web3Provider, Web3Signer, WindowMessageHandler, WindowMessageProvider, WindowSessionParams, isBrowserExtension, isSequenceProvider, isValidSignature, nextMessageIdx, recoverWalletConfig };
3618
+ export { BaseInjectedTransport, BaseProviderTransport, BaseWalletTransport, CHANNEL_ID, DefaultProviderConfig, ErrSignedInRequired, EventType, ExtensionMessageHandler, ExtensionMessageProvider, InitState, LocalStore, LocalWeb3Provider, MuxMessageProvider, OpenState, PROVIDER_OPEN_TIMEOUT, ProviderError, ProxyMessageChannel, ProxyMessageChannelPort, ProxyMessageHandler, ProxyMessageProvider, Wallet, WalletRequestHandler, Web3Provider, Web3Signer, WindowMessageHandler, WindowMessageProvider, WindowSessionParams, isBrowserExtension, isSequenceProvider, isValidSignature, isWalletUpToDate, nextMessageIdx, recoverWalletConfig };
@@ -42,8 +42,10 @@ export declare class WalletRequestHandler implements ExternalProvider, JsonRpcHa
42
42
  isSignedIn(): boolean;
43
43
  getSigner(): Signer | null;
44
44
  setSigner(signer: Signer | null): void;
45
+ private handleConfirmWalletDeployPrompt;
45
46
  }
46
47
  export interface WalletUserPrompter {
48
+ promptConfirmWalletDeploy(chainId: number): Promise<boolean>;
47
49
  promptConnect(options?: ConnectOptions): Promise<PromptConnectDetails>;
48
50
  promptSignMessage(message: MessageToSign): Promise<string>;
49
51
  promptSignTransaction(txn: TransactionRequest, chaindId?: number): Promise<string>;
@@ -2,9 +2,18 @@ import { BigNumberish, BytesLike } from 'ethers';
2
2
  import { WalletContext } from '@0xsequence/network';
3
3
  import { WalletConfig, DecodedSignature } from '@0xsequence/config';
4
4
  import { Web3Provider } from './provider';
5
+ import { Signer } from '@0xsequence/wallet';
5
6
  export declare const isValidSignature: (address: string, digest: Uint8Array, sig: string, provider: Web3Provider, chainId?: number | undefined, walletContext?: WalletContext | undefined) => Promise<boolean | undefined>;
6
7
  export declare const recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
7
8
  export declare const isBrowserExtension: () => boolean;
9
+ /**
10
+ * Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
11
+ *
12
+ * @param {Signer} signer
13
+ * @param {number} chainId
14
+ * @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
15
+ */
16
+ export declare const isWalletUpToDate: (signer: Signer, chainId: number) => Promise<boolean>;
8
17
  export declare class LocalStore<T extends Object = string> {
9
18
  def?: T | undefined;
10
19
  readonly key: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xsequence/provider",
3
- "version": "0.33.3",
3
+ "version": "0.35.1",
4
4
  "description": "provider sub-package for Sequence",
5
5
  "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/provider",
6
6
  "source": "src/index.ts",
@@ -13,18 +13,18 @@
13
13
  "typecheck": "tsc --noEmit"
14
14
  },
15
15
  "dependencies": {
16
- "@0xsequence/abi": "^0.31.0",
17
- "@0xsequence/auth": "^0.33.3",
18
- "@0xsequence/config": "^0.31.0",
19
- "@0xsequence/network": "^0.31.0",
20
- "@0xsequence/transactions": "^0.33.2",
21
- "@0xsequence/utils": "^0.31.0",
22
- "@0xsequence/wallet": "^0.33.3",
16
+ "@0xsequence/abi": "^0.35.1",
17
+ "@0xsequence/auth": "^0.35.1",
18
+ "@0xsequence/config": "^0.35.1",
19
+ "@0xsequence/network": "^0.35.1",
20
+ "@0xsequence/transactions": "^0.35.1",
21
+ "@0xsequence/utils": "^0.35.1",
22
+ "@0xsequence/wallet": "^0.35.1",
23
23
  "@ethersproject/abstract-signer": "^5.5.0",
24
24
  "@ethersproject/hash": "^5.5.0",
25
- "@ethersproject/providers": "^5.5.0",
26
- "@ethersproject/web": "^5.5.0",
27
- "ethers": "^5.5.1",
25
+ "@ethersproject/providers": "^5.5.1",
26
+ "@ethersproject/web": "^5.5.1",
27
+ "ethers": "^5.5.2",
28
28
  "eventemitter2": "^6.4.5",
29
29
  "webextension-polyfill-ts": "^0.26.0"
30
30
  },
@@ -1,10 +1,8 @@
1
1
  import { EventEmitter2 as EventEmitter } from 'eventemitter2'
2
2
 
3
3
  import {
4
- ProviderMessage,
5
4
  ProviderMessageRequest,
6
5
  ProviderMessageResponse,
7
- ProviderMessageResponseCallback,
8
6
  ProviderMessageRequestHandler,
9
7
  MessageToSign,
10
8
  ProviderRpcError,
@@ -18,7 +16,7 @@ import {
18
16
  } from '../types'
19
17
 
20
18
  import { BigNumber, ethers } from 'ethers'
21
- import { JsonRpcProvider, ExternalProvider } from '@ethersproject/providers'
19
+ import { ExternalProvider } from '@ethersproject/providers'
22
20
 
23
21
  import {
24
22
  Networks,
@@ -28,14 +26,13 @@ import {
28
26
  JsonRpcResponseCallback,
29
27
  JsonRpcResponse
30
28
  } from '@0xsequence/network'
31
-
32
- import { Signer, Account } from '@0xsequence/wallet'
33
- import { isSignedTransactions, SignedTransactions, TransactionRequest } from '@0xsequence/transactions'
34
-
29
+ import { Signer } from '@0xsequence/wallet'
30
+ import { isSignedTransactions, TransactionRequest } from '@0xsequence/transactions'
35
31
  import { signAuthorization, AuthorizationOptions } from '@0xsequence/auth'
36
-
37
32
  import { logger, TypedData } from '@0xsequence/utils'
38
33
 
34
+ import { isWalletUpToDate } from '../utils'
35
+
39
36
  export interface WalletSignInOptions {
40
37
  connect?: boolean
41
38
  mainnetNetworks?: Networks
@@ -252,43 +249,34 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
252
249
  break
253
250
  }
254
251
 
255
- case 'personal_sign': {
252
+ case 'personal_sign':
253
+ case 'eth_sign': {
256
254
  // note: message from json-rpc input is in hex format
257
- const [message, signingAddress] = request.params!
258
-
259
- let sig = ''
260
- // TODO:
261
- // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
262
- if (this.prompter === null) {
263
- // prompter is null, so we'll sign from here
264
- sig = await signer.signMessage(ethers.utils.arrayify(message), chainId)
255
+ let message: any
256
+
257
+ // there is a difference in the order of the params:
258
+ // personal_sign: [data, address]
259
+ // eth_sign: [address, data]
260
+ if (request.method === 'personal_sign') {
261
+ const [data, address] = request.params!
262
+ message = data
265
263
  } else {
266
- // prompt user to provide the response
267
- sig = await this.prompter.promptSignMessage({ chainId: chainId, message: message })
264
+ const [address, data] = request.params!
265
+ message = data
268
266
  }
269
267
 
270
- if (sig && sig.length > 0) {
271
- response.result = sig
272
- } else {
273
- // The user has declined the request when value is null
274
- throw new Error('declined by user')
275
- }
276
- break
277
- }
278
-
279
- case 'eth_sign': {
280
- // note: message from json-rpc input is in hex format
281
- const [signingAddress, message] = request.params!
282
-
283
268
  let sig = ''
269
+
284
270
  // TODO:
285
271
  // if (process.env.TEST_MODE === 'true' && this.prompter === null) {
286
272
  if (this.prompter === null) {
287
273
  // prompter is null, so we'll sign from here
288
274
  sig = await signer.signMessage(ethers.utils.arrayify(message), chainId)
289
275
  } else {
290
- // prompt user to provide the response
291
- sig = await this.prompter.promptSignMessage({ chainId: chainId, message: message })
276
+ const promptResultForDeployment = await this.handleConfirmWalletDeployPrompt(this.prompter, signer, chainId)
277
+ if (promptResultForDeployment) {
278
+ sig = await this.prompter.promptSignMessage({ chainId: chainId, message: message })
279
+ }
292
280
  }
293
281
 
294
282
  if (sig && sig.length > 0) {
@@ -320,12 +308,15 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
320
308
  }
321
309
 
322
310
  let sig = ''
311
+
323
312
  if (this.prompter === null) {
324
313
  // prompter is null, so we'll sign from here
325
314
  sig = await signer.signTypedData(typedData.domain, typedData.types, typedData.message, chainId)
326
315
  } else {
327
- // prompt user to provide the response
328
- sig = await this.prompter.promptSignMessage({ chainId: chainId, typedData: typedData })
316
+ const promptResultForDeployment = await this.handleConfirmWalletDeployPrompt(this.prompter, signer, chainId)
317
+ if (promptResultForDeployment) {
318
+ sig = await this.prompter.promptSignMessage({ chainId: chainId, typedData: typedData })
319
+ }
329
320
  }
330
321
 
331
322
  if (sig && sig.length > 0) {
@@ -698,9 +689,38 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
698
689
  setSigner(signer: Signer | null) {
699
690
  this.signer = signer
700
691
  }
692
+
693
+ private async handleConfirmWalletDeployPrompt(
694
+ prompter: WalletUserPrompter,
695
+ signer: Signer,
696
+ chainId?: number
697
+ ): Promise<boolean> {
698
+ // check if wallet is deployed and up to date, if not, prompt user to deploy
699
+ // if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
700
+ if (!chainId) {
701
+ return true
702
+ }
703
+ const isUpToDate = await isWalletUpToDate(signer, chainId)
704
+ if (isUpToDate) {
705
+ return true
706
+ }
707
+ const promptResult = await prompter.promptConfirmWalletDeploy(chainId)
708
+ // if client returned true, check again to make sure wallet is deployed and up to date
709
+ if (promptResult) {
710
+ const isPromptResultCorrect = await isWalletUpToDate(signer, chainId)
711
+ if (!isPromptResultCorrect) {
712
+ logger.error('WalletRequestHandler: result for promptConfirmWalletDeploy is not correct')
713
+ return false
714
+ } else {
715
+ return true
716
+ }
717
+ }
718
+ return false
719
+ }
701
720
  }
702
721
 
703
722
  export interface WalletUserPrompter {
723
+ promptConfirmWalletDeploy(chainId: number): Promise<boolean>
704
724
  promptConnect(options?: ConnectOptions): Promise<PromptConnectDetails>
705
725
  promptSignMessage(message: MessageToSign): Promise<string>
706
726
  promptSignTransaction(txn: TransactionRequest, chaindId?: number): Promise<string>
package/src/utils.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { BigNumberish, BytesLike } from 'ethers'
2
2
  import { WalletContext } from '@0xsequence/network'
3
- import { WalletConfig, addressOf, DecodedSignature } from '@0xsequence/config'
3
+ import { WalletConfig, addressOf, DecodedSignature, isConfigEqual } from '@0xsequence/config'
4
4
  import { packMessageData } from '@0xsequence/utils'
5
5
  import { Web3Provider } from './provider'
6
- import { isValidSignature as _isValidSignature, recoverConfig } from '@0xsequence/wallet'
6
+ import { isValidSignature as _isValidSignature, recoverConfig, Signer } from '@0xsequence/wallet'
7
7
 
8
8
  export const isValidSignature = async (
9
9
  address: string,
@@ -13,15 +13,15 @@ export const isValidSignature = async (
13
13
  chainId?: number,
14
14
  walletContext?: WalletContext
15
15
  ): Promise<boolean | undefined> => {
16
- chainId = chainId || await provider.getChainId()
17
- walletContext = walletContext || await provider.getSigner().getWalletContext()
16
+ chainId = chainId || (await provider.getChainId())
17
+ walletContext = walletContext || (await provider.getSigner().getWalletContext())
18
18
  return _isValidSignature(address, digest, sig, provider, walletContext, chainId)
19
19
  }
20
20
 
21
21
  export const recoverWalletConfig = async (
22
22
  address: string,
23
23
  digest: BytesLike,
24
- signature: string | DecodedSignature,
24
+ signature: string | DecodedSignature,
25
25
  chainId: BigNumberish,
26
26
  walletContext?: WalletContext
27
27
  ): Promise<WalletConfig> => {
@@ -40,7 +40,48 @@ export const recoverWalletConfig = async (
40
40
  return config
41
41
  }
42
42
 
43
- export const isBrowserExtension = (): boolean => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'
43
+ export const isBrowserExtension = (): boolean =>
44
+ window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'
45
+
46
+ /**
47
+ * Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
48
+ *
49
+ * @param {Signer} signer
50
+ * @param {number} chainId
51
+ * @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
52
+ */
53
+ export const isWalletUpToDate = async (signer: Signer, chainId: number): Promise<boolean> => {
54
+ const walletState = await signer.getWalletState()
55
+ const networks = await signer.getNetworks()
56
+
57
+ const walletStateForRequiredChain = walletState.find(state => state.chainId === chainId)
58
+ if (!walletStateForRequiredChain) {
59
+ throw new Error(`WalletRequestHandler: could not find wallet state for chainId ${chainId}`)
60
+ }
61
+
62
+ const isDeployed = walletStateForRequiredChain.deployed
63
+
64
+ if (!networks) {
65
+ throw new Error(`isWalletUpToDate util: could not get networks from signer`)
66
+ }
67
+ const authChain = networks.find(network => network.isAuthChain)
68
+ if (!authChain) {
69
+ throw new Error(`isWalletUpToDate util: could not get auth chain network information`)
70
+ }
71
+ const authChainId = authChain.chainId
72
+ const authChainConfig = walletState.find(state => state.chainId === authChainId)?.config
73
+ if (!authChainConfig) {
74
+ throw new Error(`isWalletUpToDate util: could not get auth chain config`)
75
+ }
76
+ const requiredChainConfig = walletStateForRequiredChain.config
77
+ if (!requiredChainConfig) {
78
+ throw new Error(`isWalletUpToDate util: could not get config for chainId ${chainId}`)
79
+ }
80
+
81
+ const isUpToDate = isConfigEqual(authChainConfig, requiredChainConfig)
82
+
83
+ return isDeployed && isUpToDate
84
+ }
44
85
 
45
86
  // window.localstorage helper
46
87
  export class LocalStore<T extends Object = string> {