@0xsequence/provider 0.42.8 → 0.42.10

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.
@@ -483,12 +483,13 @@ class WalletRequestHandler {
483
483
  // signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
484
484
  // value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
485
485
  // a Signer value is the actually interface to a signed-in account
486
- constructor(_signer, prompter, mainnetNetworks, testnetNetworks = []) {
486
+ constructor(_signer, prompter, auxDataProvider, mainnetNetworks, testnetNetworks = []) {
487
487
  var _this = this;
488
488
 
489
489
  this.signer = void 0;
490
490
  this.signerReadyCallbacks = [];
491
491
  this.prompter = void 0;
492
+ this.auxDataProvider = void 0;
492
493
  this.mainnetNetworks = void 0;
493
494
  this.testnetNetworks = void 0;
494
495
  this._openIntent = void 0;
@@ -962,6 +963,7 @@ class WalletRequestHandler {
962
963
 
963
964
  this.signer = _signer;
964
965
  this.prompter = prompter;
966
+ this.auxDataProvider = auxDataProvider;
965
967
  this.mainnetNetworks = mainnetNetworks;
966
968
  this.testnetNetworks = testnetNetworks;
967
969
  }
@@ -1055,6 +1057,16 @@ class WalletRequestHandler {
1055
1057
  chainId: ethers.ethers.utils.hexlify(await this.getChainId())
1056
1058
  };
1057
1059
 
1060
+ if (options && options.askForEmail) {
1061
+ var _this$auxDataProvider;
1062
+
1063
+ const email = await ((_this$auxDataProvider = this.auxDataProvider) == null ? void 0 : _this$auxDataProvider.get('email'));
1064
+
1065
+ if (email) {
1066
+ connectDetails.email = email;
1067
+ }
1068
+ }
1069
+
1058
1070
  if (options && options.authorize) {
1059
1071
  // Perform ethauth eip712 request and construct the ConnectDetails response
1060
1072
  // including the auth proof
@@ -1339,7 +1351,7 @@ function isSequenceProvider(provider) {
1339
1351
  }
1340
1352
  class LocalWeb3Provider extends Web3Provider {
1341
1353
  constructor(signer, networks) {
1342
- const walletRequestHandler = new WalletRequestHandler(signer, null, networks || []);
1354
+ const walletRequestHandler = new WalletRequestHandler(signer, null, null, networks || []);
1343
1355
  super(walletRequestHandler);
1344
1356
  }
1345
1357
 
@@ -1719,6 +1731,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
1719
1731
  return result;
1720
1732
  };
1721
1733
 
1734
+ function messageIsExemptFromEIP191Prefix(message) {
1735
+ return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
1736
+ }
1737
+ const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
1738
+ {
1739
+ name: 'Decentraland Exception',
1740
+ predicate: isDecentralandLoginMessage
1741
+ }, // NOTE: 0x v3 does not support 191 correctly.
1742
+ // See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
1743
+ {
1744
+ name: '0x v3 Exception',
1745
+ predicate: isZeroExV3Order
1746
+ }];
1747
+ const DCL_REGEX = /^Decentraland Login\nEphemeral address: 0x[a-fA-F0-9]{40}\nExpiration: (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$/;
1748
+ function isDecentralandLoginMessage(bytes) {
1749
+ try {
1750
+ const stringified = ethers.ethers.utils.toUtf8String(bytes);
1751
+ return DCL_REGEX.test(stringified);
1752
+ } catch (_unused) {
1753
+ return false;
1754
+ }
1755
+ } // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
1756
+ // see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
1757
+
1758
+ function isZeroExV3Order(bytes) {
1759
+ const abi = new ethers.ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
1760
+
1761
+ try {
1762
+ abi.decodeFunctionData('OrderWithHash', bytes);
1763
+ return true;
1764
+ } catch (err) {
1765
+ // failed to decode ABI, so it's not a v3 order.
1766
+ return false;
1767
+ }
1768
+ }
1769
+ const ZeroXV3EIP1271OrderWithHashAbi = [{
1770
+ inputs: [{
1771
+ components: [{
1772
+ internalType: 'address',
1773
+ name: 'makerAddress',
1774
+ type: 'address'
1775
+ }, {
1776
+ internalType: 'address',
1777
+ name: 'takerAddress',
1778
+ type: 'address'
1779
+ }, {
1780
+ internalType: 'address',
1781
+ name: 'feeRecipientAddress',
1782
+ type: 'address'
1783
+ }, {
1784
+ internalType: 'address',
1785
+ name: 'senderAddress',
1786
+ type: 'address'
1787
+ }, {
1788
+ internalType: 'uint256',
1789
+ name: 'makerAssetAmount',
1790
+ type: 'uint256'
1791
+ }, {
1792
+ internalType: 'uint256',
1793
+ name: 'takerAssetAmount',
1794
+ type: 'uint256'
1795
+ }, {
1796
+ internalType: 'uint256',
1797
+ name: 'makerFee',
1798
+ type: 'uint256'
1799
+ }, {
1800
+ internalType: 'uint256',
1801
+ name: 'takerFee',
1802
+ type: 'uint256'
1803
+ }, {
1804
+ internalType: 'uint256',
1805
+ name: 'expirationTimeSeconds',
1806
+ type: 'uint256'
1807
+ }, {
1808
+ internalType: 'uint256',
1809
+ name: 'salt',
1810
+ type: 'uint256'
1811
+ }, {
1812
+ internalType: 'bytes',
1813
+ name: 'makerAssetData',
1814
+ type: 'bytes'
1815
+ }, {
1816
+ internalType: 'bytes',
1817
+ name: 'takerAssetData',
1818
+ type: 'bytes'
1819
+ }, {
1820
+ internalType: 'bytes',
1821
+ name: 'makerFeeAssetData',
1822
+ type: 'bytes'
1823
+ }, {
1824
+ internalType: 'bytes',
1825
+ name: 'takerFeeAssetData',
1826
+ type: 'bytes'
1827
+ }],
1828
+ internalType: 'struct IEIP1271Data.Order',
1829
+ name: 'order',
1830
+ type: 'tuple'
1831
+ }, {
1832
+ internalType: 'bytes32',
1833
+ name: 'orderHash',
1834
+ type: 'bytes32'
1835
+ }],
1836
+ name: 'OrderWithHash',
1837
+ outputs: [],
1838
+ stateMutability: 'pure',
1839
+ type: 'function'
1840
+ }];
1841
+
1722
1842
  const eip191prefix = ethers.ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
1723
1843
  const messageToBytes = message => {
1724
1844
  if (ethers.ethers.utils.isBytes(message) || ethers.ethers.utils.isHexString(message)) {
@@ -1729,7 +1849,12 @@ const messageToBytes = message => {
1729
1849
  };
1730
1850
  const prefixEIP191Message = message => {
1731
1851
  const messageBytes = messageToBytes(message);
1732
- return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1852
+
1853
+ if (messageIsExemptFromEIP191Prefix(messageBytes)) {
1854
+ return messageBytes;
1855
+ } else {
1856
+ return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1857
+ }
1733
1858
  };
1734
1859
  const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
1735
1860
  if (!chainId) {
@@ -483,12 +483,13 @@ class WalletRequestHandler {
483
483
  // signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
484
484
  // value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
485
485
  // a Signer value is the actually interface to a signed-in account
486
- constructor(_signer, prompter, mainnetNetworks, testnetNetworks = []) {
486
+ constructor(_signer, prompter, auxDataProvider, mainnetNetworks, testnetNetworks = []) {
487
487
  var _this = this;
488
488
 
489
489
  this.signer = void 0;
490
490
  this.signerReadyCallbacks = [];
491
491
  this.prompter = void 0;
492
+ this.auxDataProvider = void 0;
492
493
  this.mainnetNetworks = void 0;
493
494
  this.testnetNetworks = void 0;
494
495
  this._openIntent = void 0;
@@ -962,6 +963,7 @@ class WalletRequestHandler {
962
963
 
963
964
  this.signer = _signer;
964
965
  this.prompter = prompter;
966
+ this.auxDataProvider = auxDataProvider;
965
967
  this.mainnetNetworks = mainnetNetworks;
966
968
  this.testnetNetworks = testnetNetworks;
967
969
  }
@@ -1055,6 +1057,16 @@ class WalletRequestHandler {
1055
1057
  chainId: ethers.ethers.utils.hexlify(await this.getChainId())
1056
1058
  };
1057
1059
 
1060
+ if (options && options.askForEmail) {
1061
+ var _this$auxDataProvider;
1062
+
1063
+ const email = await ((_this$auxDataProvider = this.auxDataProvider) == null ? void 0 : _this$auxDataProvider.get('email'));
1064
+
1065
+ if (email) {
1066
+ connectDetails.email = email;
1067
+ }
1068
+ }
1069
+
1058
1070
  if (options && options.authorize) {
1059
1071
  // Perform ethauth eip712 request and construct the ConnectDetails response
1060
1072
  // including the auth proof
@@ -1339,7 +1351,7 @@ function isSequenceProvider(provider) {
1339
1351
  }
1340
1352
  class LocalWeb3Provider extends Web3Provider {
1341
1353
  constructor(signer, networks) {
1342
- const walletRequestHandler = new WalletRequestHandler(signer, null, networks || []);
1354
+ const walletRequestHandler = new WalletRequestHandler(signer, null, null, networks || []);
1343
1355
  super(walletRequestHandler);
1344
1356
  }
1345
1357
 
@@ -1719,6 +1731,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
1719
1731
  return result;
1720
1732
  };
1721
1733
 
1734
+ function messageIsExemptFromEIP191Prefix(message) {
1735
+ return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
1736
+ }
1737
+ const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
1738
+ {
1739
+ name: 'Decentraland Exception',
1740
+ predicate: isDecentralandLoginMessage
1741
+ }, // NOTE: 0x v3 does not support 191 correctly.
1742
+ // See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
1743
+ {
1744
+ name: '0x v3 Exception',
1745
+ predicate: isZeroExV3Order
1746
+ }];
1747
+ const DCL_REGEX = /^Decentraland Login\nEphemeral address: 0x[a-fA-F0-9]{40}\nExpiration: (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$/;
1748
+ function isDecentralandLoginMessage(bytes) {
1749
+ try {
1750
+ const stringified = ethers.ethers.utils.toUtf8String(bytes);
1751
+ return DCL_REGEX.test(stringified);
1752
+ } catch (_unused) {
1753
+ return false;
1754
+ }
1755
+ } // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
1756
+ // see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
1757
+
1758
+ function isZeroExV3Order(bytes) {
1759
+ const abi = new ethers.ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
1760
+
1761
+ try {
1762
+ abi.decodeFunctionData('OrderWithHash', bytes);
1763
+ return true;
1764
+ } catch (err) {
1765
+ // failed to decode ABI, so it's not a v3 order.
1766
+ return false;
1767
+ }
1768
+ }
1769
+ const ZeroXV3EIP1271OrderWithHashAbi = [{
1770
+ inputs: [{
1771
+ components: [{
1772
+ internalType: 'address',
1773
+ name: 'makerAddress',
1774
+ type: 'address'
1775
+ }, {
1776
+ internalType: 'address',
1777
+ name: 'takerAddress',
1778
+ type: 'address'
1779
+ }, {
1780
+ internalType: 'address',
1781
+ name: 'feeRecipientAddress',
1782
+ type: 'address'
1783
+ }, {
1784
+ internalType: 'address',
1785
+ name: 'senderAddress',
1786
+ type: 'address'
1787
+ }, {
1788
+ internalType: 'uint256',
1789
+ name: 'makerAssetAmount',
1790
+ type: 'uint256'
1791
+ }, {
1792
+ internalType: 'uint256',
1793
+ name: 'takerAssetAmount',
1794
+ type: 'uint256'
1795
+ }, {
1796
+ internalType: 'uint256',
1797
+ name: 'makerFee',
1798
+ type: 'uint256'
1799
+ }, {
1800
+ internalType: 'uint256',
1801
+ name: 'takerFee',
1802
+ type: 'uint256'
1803
+ }, {
1804
+ internalType: 'uint256',
1805
+ name: 'expirationTimeSeconds',
1806
+ type: 'uint256'
1807
+ }, {
1808
+ internalType: 'uint256',
1809
+ name: 'salt',
1810
+ type: 'uint256'
1811
+ }, {
1812
+ internalType: 'bytes',
1813
+ name: 'makerAssetData',
1814
+ type: 'bytes'
1815
+ }, {
1816
+ internalType: 'bytes',
1817
+ name: 'takerAssetData',
1818
+ type: 'bytes'
1819
+ }, {
1820
+ internalType: 'bytes',
1821
+ name: 'makerFeeAssetData',
1822
+ type: 'bytes'
1823
+ }, {
1824
+ internalType: 'bytes',
1825
+ name: 'takerFeeAssetData',
1826
+ type: 'bytes'
1827
+ }],
1828
+ internalType: 'struct IEIP1271Data.Order',
1829
+ name: 'order',
1830
+ type: 'tuple'
1831
+ }, {
1832
+ internalType: 'bytes32',
1833
+ name: 'orderHash',
1834
+ type: 'bytes32'
1835
+ }],
1836
+ name: 'OrderWithHash',
1837
+ outputs: [],
1838
+ stateMutability: 'pure',
1839
+ type: 'function'
1840
+ }];
1841
+
1722
1842
  const eip191prefix = ethers.ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
1723
1843
  const messageToBytes = message => {
1724
1844
  if (ethers.ethers.utils.isBytes(message) || ethers.ethers.utils.isHexString(message)) {
@@ -1729,7 +1849,12 @@ const messageToBytes = message => {
1729
1849
  };
1730
1850
  const prefixEIP191Message = message => {
1731
1851
  const messageBytes = messageToBytes(message);
1732
- return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1852
+
1853
+ if (messageIsExemptFromEIP191Prefix(messageBytes)) {
1854
+ return messageBytes;
1855
+ } else {
1856
+ return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1857
+ }
1733
1858
  };
1734
1859
  const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
1735
1860
  if (!chainId) {
@@ -479,12 +479,13 @@ class WalletRequestHandler {
479
479
  // signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
480
480
  // value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
481
481
  // a Signer value is the actually interface to a signed-in account
482
- constructor(_signer, prompter, mainnetNetworks, testnetNetworks = []) {
482
+ constructor(_signer, prompter, auxDataProvider, mainnetNetworks, testnetNetworks = []) {
483
483
  var _this = this;
484
484
 
485
485
  this.signer = void 0;
486
486
  this.signerReadyCallbacks = [];
487
487
  this.prompter = void 0;
488
+ this.auxDataProvider = void 0;
488
489
  this.mainnetNetworks = void 0;
489
490
  this.testnetNetworks = void 0;
490
491
  this._openIntent = void 0;
@@ -958,6 +959,7 @@ class WalletRequestHandler {
958
959
 
959
960
  this.signer = _signer;
960
961
  this.prompter = prompter;
962
+ this.auxDataProvider = auxDataProvider;
961
963
  this.mainnetNetworks = mainnetNetworks;
962
964
  this.testnetNetworks = testnetNetworks;
963
965
  }
@@ -1051,6 +1053,16 @@ class WalletRequestHandler {
1051
1053
  chainId: ethers.utils.hexlify(await this.getChainId())
1052
1054
  };
1053
1055
 
1056
+ if (options && options.askForEmail) {
1057
+ var _this$auxDataProvider;
1058
+
1059
+ const email = await ((_this$auxDataProvider = this.auxDataProvider) == null ? void 0 : _this$auxDataProvider.get('email'));
1060
+
1061
+ if (email) {
1062
+ connectDetails.email = email;
1063
+ }
1064
+ }
1065
+
1054
1066
  if (options && options.authorize) {
1055
1067
  // Perform ethauth eip712 request and construct the ConnectDetails response
1056
1068
  // including the auth proof
@@ -1335,7 +1347,7 @@ function isSequenceProvider(provider) {
1335
1347
  }
1336
1348
  class LocalWeb3Provider extends Web3Provider {
1337
1349
  constructor(signer, networks) {
1338
- const walletRequestHandler = new WalletRequestHandler(signer, null, networks || []);
1350
+ const walletRequestHandler = new WalletRequestHandler(signer, null, null, networks || []);
1339
1351
  super(walletRequestHandler);
1340
1352
  }
1341
1353
 
@@ -1715,6 +1727,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
1715
1727
  return result;
1716
1728
  };
1717
1729
 
1730
+ function messageIsExemptFromEIP191Prefix(message) {
1731
+ return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
1732
+ }
1733
+ const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
1734
+ {
1735
+ name: 'Decentraland Exception',
1736
+ predicate: isDecentralandLoginMessage
1737
+ }, // NOTE: 0x v3 does not support 191 correctly.
1738
+ // See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
1739
+ {
1740
+ name: '0x v3 Exception',
1741
+ predicate: isZeroExV3Order
1742
+ }];
1743
+ const DCL_REGEX = /^Decentraland Login\nEphemeral address: 0x[a-fA-F0-9]{40}\nExpiration: (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$/;
1744
+ function isDecentralandLoginMessage(bytes) {
1745
+ try {
1746
+ const stringified = ethers.utils.toUtf8String(bytes);
1747
+ return DCL_REGEX.test(stringified);
1748
+ } catch (_unused) {
1749
+ return false;
1750
+ }
1751
+ } // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
1752
+ // see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
1753
+
1754
+ function isZeroExV3Order(bytes) {
1755
+ const abi = new ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
1756
+
1757
+ try {
1758
+ abi.decodeFunctionData('OrderWithHash', bytes);
1759
+ return true;
1760
+ } catch (err) {
1761
+ // failed to decode ABI, so it's not a v3 order.
1762
+ return false;
1763
+ }
1764
+ }
1765
+ const ZeroXV3EIP1271OrderWithHashAbi = [{
1766
+ inputs: [{
1767
+ components: [{
1768
+ internalType: 'address',
1769
+ name: 'makerAddress',
1770
+ type: 'address'
1771
+ }, {
1772
+ internalType: 'address',
1773
+ name: 'takerAddress',
1774
+ type: 'address'
1775
+ }, {
1776
+ internalType: 'address',
1777
+ name: 'feeRecipientAddress',
1778
+ type: 'address'
1779
+ }, {
1780
+ internalType: 'address',
1781
+ name: 'senderAddress',
1782
+ type: 'address'
1783
+ }, {
1784
+ internalType: 'uint256',
1785
+ name: 'makerAssetAmount',
1786
+ type: 'uint256'
1787
+ }, {
1788
+ internalType: 'uint256',
1789
+ name: 'takerAssetAmount',
1790
+ type: 'uint256'
1791
+ }, {
1792
+ internalType: 'uint256',
1793
+ name: 'makerFee',
1794
+ type: 'uint256'
1795
+ }, {
1796
+ internalType: 'uint256',
1797
+ name: 'takerFee',
1798
+ type: 'uint256'
1799
+ }, {
1800
+ internalType: 'uint256',
1801
+ name: 'expirationTimeSeconds',
1802
+ type: 'uint256'
1803
+ }, {
1804
+ internalType: 'uint256',
1805
+ name: 'salt',
1806
+ type: 'uint256'
1807
+ }, {
1808
+ internalType: 'bytes',
1809
+ name: 'makerAssetData',
1810
+ type: 'bytes'
1811
+ }, {
1812
+ internalType: 'bytes',
1813
+ name: 'takerAssetData',
1814
+ type: 'bytes'
1815
+ }, {
1816
+ internalType: 'bytes',
1817
+ name: 'makerFeeAssetData',
1818
+ type: 'bytes'
1819
+ }, {
1820
+ internalType: 'bytes',
1821
+ name: 'takerFeeAssetData',
1822
+ type: 'bytes'
1823
+ }],
1824
+ internalType: 'struct IEIP1271Data.Order',
1825
+ name: 'order',
1826
+ type: 'tuple'
1827
+ }, {
1828
+ internalType: 'bytes32',
1829
+ name: 'orderHash',
1830
+ type: 'bytes32'
1831
+ }],
1832
+ name: 'OrderWithHash',
1833
+ outputs: [],
1834
+ stateMutability: 'pure',
1835
+ type: 'function'
1836
+ }];
1837
+
1718
1838
  const eip191prefix = ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
1719
1839
  const messageToBytes = message => {
1720
1840
  if (ethers.utils.isBytes(message) || ethers.utils.isHexString(message)) {
@@ -1725,7 +1845,12 @@ const messageToBytes = message => {
1725
1845
  };
1726
1846
  const prefixEIP191Message = message => {
1727
1847
  const messageBytes = messageToBytes(message);
1728
- return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1848
+
1849
+ if (messageIsExemptFromEIP191Prefix(messageBytes)) {
1850
+ return messageBytes;
1851
+ } else {
1852
+ return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
1853
+ }
1729
1854
  };
1730
1855
  const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
1731
1856
  if (!chainId) {
@@ -0,0 +1,3 @@
1
+ export declare function messageIsExemptFromEIP191Prefix(message: Uint8Array): boolean;
2
+ export declare function isDecentralandLoginMessage(bytes: Uint8Array): boolean;
3
+ export declare function isZeroExV3Order(bytes: Uint8Array): boolean;
@@ -13,6 +13,7 @@ export declare class WalletRequestHandler implements ExternalProvider, JsonRpcHa
13
13
  private signer;
14
14
  private signerReadyCallbacks;
15
15
  private prompter;
16
+ private auxDataProvider;
16
17
  private mainnetNetworks;
17
18
  private testnetNetworks;
18
19
  private _openIntent?;
@@ -20,7 +21,7 @@ export declare class WalletRequestHandler implements ExternalProvider, JsonRpcHa
20
21
  private _defaultNetworkId?;
21
22
  private _chainId?;
22
23
  private events;
23
- constructor(signer: Signer | null | undefined, prompter: WalletUserPrompter | null, mainnetNetworks: NetworkConfig[], testnetNetworks?: NetworkConfig[]);
24
+ constructor(signer: Signer | null | undefined, prompter: WalletUserPrompter | null, auxDataProvider: AuxDataProvider | null, mainnetNetworks: NetworkConfig[], testnetNetworks?: NetworkConfig[]);
24
25
  signIn(signer: Signer | null, options?: WalletSignInOptions): Promise<void>;
25
26
  signOut(): void;
26
27
  signerReset(): void;
@@ -58,3 +59,6 @@ export interface WalletUserPrompter {
58
59
  promptSendTransaction(txn: TransactionRequest, chaindId?: number, options?: ConnectOptions): Promise<string>;
59
60
  promptConfirmWalletDeploy(chainId: number, options?: ConnectOptions): Promise<boolean>;
60
61
  }
62
+ export interface AuxDataProvider {
63
+ get(key: string): Promise<any>;
64
+ }
@@ -121,7 +121,7 @@ export interface ConnectOptions {
121
121
  expiry?: number;
122
122
  /** authorize will perform an ETHAuth eip712 signing and return the proof to the dapp. */
123
123
  authorize?: boolean;
124
- /** *Currently not used* askForEmail will prompt to give permission to the dapp to access email address */
124
+ /** askForEmail will prompt to give permission to the dapp to access email address */
125
125
  askForEmail?: boolean;
126
126
  /** refresh flag will force a full re-connect (ie. disconnect then connect again) */
127
127
  refresh?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xsequence/provider",
3
- "version": "0.42.8",
3
+ "version": "0.42.10",
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",
@@ -9,17 +9,18 @@
9
9
  "author": "Horizon Blockchain Games",
10
10
  "license": "Apache-2.0",
11
11
  "scripts": {
12
- "test": "echo",
12
+ "test": "yarn test:file tests/**/*.spec.ts",
13
+ "test:file": "TS_NODE_PROJECT=../../tsconfig.test.json mocha -r ts-node/register --timeout 30000",
13
14
  "typecheck": "tsc --noEmit"
14
15
  },
15
16
  "dependencies": {
16
- "@0xsequence/abi": "^0.42.8",
17
- "@0xsequence/auth": "^0.42.8",
18
- "@0xsequence/config": "^0.42.8",
19
- "@0xsequence/network": "^0.42.8",
20
- "@0xsequence/transactions": "^0.42.8",
21
- "@0xsequence/utils": "^0.42.8",
22
- "@0xsequence/wallet": "^0.42.8",
17
+ "@0xsequence/abi": "^0.42.10",
18
+ "@0xsequence/auth": "^0.42.10",
19
+ "@0xsequence/config": "^0.42.10",
20
+ "@0xsequence/network": "^0.42.10",
21
+ "@0xsequence/transactions": "^0.42.10",
22
+ "@0xsequence/utils": "^0.42.10",
23
+ "@0xsequence/wallet": "^0.42.10",
23
24
  "@ethersproject/abstract-signer": "^5.5.0",
24
25
  "@ethersproject/hash": "^5.5.0",
25
26
  "@ethersproject/providers": "^5.5.1",
@@ -34,4 +35,4 @@
34
35
  "src",
35
36
  "dist"
36
37
  ]
37
- }
38
+ }
@@ -0,0 +1,137 @@
1
+ import { ethers } from 'ethers'
2
+
3
+ export function messageIsExemptFromEIP191Prefix(message: Uint8Array): boolean {
4
+ return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message))
5
+ }
6
+
7
+ const EIP_191_PREFIX_EXCEPTIONS: Array<{
8
+ name: string
9
+ predicate: (message: Uint8Array) => boolean
10
+ }> = [
11
+ // NOTE: Decentraland does not support 191 correctly.
12
+ {
13
+ name: 'Decentraland Exception',
14
+ predicate: isDecentralandLoginMessage
15
+ },
16
+
17
+ // NOTE: 0x v3 does not support 191 correctly.
18
+ // See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
19
+ { name: '0x v3 Exception', predicate: isZeroExV3Order }
20
+ ]
21
+
22
+ const DCL_REGEX =
23
+ /^Decentraland Login\nEphemeral address: 0x[a-fA-F0-9]{40}\nExpiration: (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$/
24
+ export function isDecentralandLoginMessage(bytes: Uint8Array): boolean {
25
+ try {
26
+ const stringified = ethers.utils.toUtf8String(bytes)
27
+ return DCL_REGEX.test(stringified)
28
+ } catch {
29
+ return false
30
+ }
31
+ }
32
+
33
+ // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
34
+ // see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
35
+ export function isZeroExV3Order(bytes: Uint8Array): boolean {
36
+ const abi = new ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi)
37
+ try {
38
+ abi.decodeFunctionData('OrderWithHash', bytes)
39
+ return true
40
+ } catch (err) {
41
+ // failed to decode ABI, so it's not a v3 order.
42
+ return false
43
+ }
44
+ }
45
+
46
+ const ZeroXV3EIP1271OrderWithHashAbi = [
47
+ {
48
+ inputs: [
49
+ {
50
+ components: [
51
+ {
52
+ internalType: 'address',
53
+ name: 'makerAddress',
54
+ type: 'address'
55
+ },
56
+ {
57
+ internalType: 'address',
58
+ name: 'takerAddress',
59
+ type: 'address'
60
+ },
61
+ {
62
+ internalType: 'address',
63
+ name: 'feeRecipientAddress',
64
+ type: 'address'
65
+ },
66
+ {
67
+ internalType: 'address',
68
+ name: 'senderAddress',
69
+ type: 'address'
70
+ },
71
+ {
72
+ internalType: 'uint256',
73
+ name: 'makerAssetAmount',
74
+ type: 'uint256'
75
+ },
76
+ {
77
+ internalType: 'uint256',
78
+ name: 'takerAssetAmount',
79
+ type: 'uint256'
80
+ },
81
+ {
82
+ internalType: 'uint256',
83
+ name: 'makerFee',
84
+ type: 'uint256'
85
+ },
86
+ {
87
+ internalType: 'uint256',
88
+ name: 'takerFee',
89
+ type: 'uint256'
90
+ },
91
+ {
92
+ internalType: 'uint256',
93
+ name: 'expirationTimeSeconds',
94
+ type: 'uint256'
95
+ },
96
+ {
97
+ internalType: 'uint256',
98
+ name: 'salt',
99
+ type: 'uint256'
100
+ },
101
+ {
102
+ internalType: 'bytes',
103
+ name: 'makerAssetData',
104
+ type: 'bytes'
105
+ },
106
+ {
107
+ internalType: 'bytes',
108
+ name: 'takerAssetData',
109
+ type: 'bytes'
110
+ },
111
+ {
112
+ internalType: 'bytes',
113
+ name: 'makerFeeAssetData',
114
+ type: 'bytes'
115
+ },
116
+ {
117
+ internalType: 'bytes',
118
+ name: 'takerFeeAssetData',
119
+ type: 'bytes'
120
+ }
121
+ ],
122
+ internalType: 'struct IEIP1271Data.Order',
123
+ name: 'order',
124
+ type: 'tuple'
125
+ },
126
+ {
127
+ internalType: 'bytes32',
128
+ name: 'orderHash',
129
+ type: 'bytes32'
130
+ }
131
+ ],
132
+ name: 'OrderWithHash',
133
+ outputs: [],
134
+ stateMutability: 'pure',
135
+ type: 'function'
136
+ }
137
+ ]
package/src/provider.ts CHANGED
@@ -94,7 +94,7 @@ export function isSequenceProvider(provider: any): provider is Web3Provider {
94
94
 
95
95
  export class LocalWeb3Provider extends Web3Provider {
96
96
  constructor(signer: Signer, networks?: NetworkConfig[]) {
97
- const walletRequestHandler = new WalletRequestHandler(signer, null, networks || [])
97
+ const walletRequestHandler = new WalletRequestHandler(signer, null, null, networks || [])
98
98
  super(walletRequestHandler)
99
99
  }
100
100
  }
@@ -44,6 +44,7 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
44
44
  private signerReadyCallbacks: Array<() => void> = []
45
45
 
46
46
  private prompter: WalletUserPrompter | null
47
+ private auxDataProvider: AuxDataProvider | null
47
48
  private mainnetNetworks: NetworkConfig[]
48
49
  private testnetNetworks: NetworkConfig[]
49
50
 
@@ -57,11 +58,13 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
57
58
  constructor(
58
59
  signer: Signer | null | undefined,
59
60
  prompter: WalletUserPrompter | null,
61
+ auxDataProvider: AuxDataProvider | null,
60
62
  mainnetNetworks: NetworkConfig[],
61
63
  testnetNetworks: NetworkConfig[] = []
62
64
  ) {
63
65
  this.signer = signer
64
66
  this.prompter = prompter
67
+ this.auxDataProvider = auxDataProvider
65
68
  this.mainnetNetworks = mainnetNetworks
66
69
  this.testnetNetworks = testnetNetworks
67
70
  }
@@ -152,6 +155,13 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
152
155
  chainId: ethers.utils.hexlify(await this.getChainId())
153
156
  }
154
157
 
158
+ if (options && options.askForEmail) {
159
+ const email = await this.auxDataProvider?.get('email')
160
+ if (email) {
161
+ connectDetails.email = email
162
+ }
163
+ }
164
+
155
165
  if (options && options.authorize) {
156
166
  // Perform ethauth eip712 request and construct the ConnectDetails response
157
167
  // including the auth proof
@@ -802,6 +812,10 @@ export interface WalletUserPrompter {
802
812
  promptConfirmWalletDeploy(chainId: number, options?: ConnectOptions): Promise<boolean>
803
813
  }
804
814
 
815
+ export interface AuxDataProvider {
816
+ get(key: string): Promise<any>
817
+ }
818
+
805
819
  const permittedJsonRpcMethods = [
806
820
  'net_version',
807
821
  'eth_chainId',
package/src/types.ts CHANGED
@@ -156,8 +156,7 @@ export interface ConnectOptions {
156
156
  /** authorize will perform an ETHAuth eip712 signing and return the proof to the dapp. */
157
157
  authorize?: boolean
158
158
 
159
- /** *Currently not used* askForEmail will prompt to give permission to the dapp to access email address */
160
- // TODO: this feature is currently not used as the wallet does not report emails yet
159
+ /** askForEmail will prompt to give permission to the dapp to access email address */
161
160
  askForEmail?: boolean
162
161
 
163
162
  /** refresh flag will force a full re-connect (ie. disconnect then connect again) */
@@ -113,7 +113,13 @@ export class WalletUtils {
113
113
  walletContext?: WalletContext
114
114
  ): Promise<WalletConfig> => {
115
115
  walletContext = walletContext || (await this.wallet.getWalletContext())
116
- return recoverWalletConfig(address, encodeMessageDigest(prefixEIP191Message(message)), signature, chainId, walletContext)
116
+ return recoverWalletConfig(
117
+ address,
118
+ encodeMessageDigest(prefixEIP191Message(message)),
119
+ signature,
120
+ chainId,
121
+ walletContext
122
+ )
117
123
  }
118
124
 
119
125
  // Recover the WalletConfig from a signature of a typedData object
package/src/utils.ts CHANGED
@@ -4,6 +4,7 @@ import { WalletConfig, addressOf, DecodedSignature, isConfigEqual } from '@0xseq
4
4
  import { packMessageData, encodeMessageDigest, TypedData, encodeTypedDataDigest } from '@0xsequence/utils'
5
5
  import { Web3Provider } from './provider'
6
6
  import { isValidSignature as _isValidSignature, recoverConfig, Signer } from '@0xsequence/wallet'
7
+ import { messageIsExemptFromEIP191Prefix } from './eip191exceptions'
7
8
 
8
9
  const eip191prefix = ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n')
9
10
 
@@ -17,7 +18,11 @@ export const messageToBytes = (message: BytesLike): Uint8Array => {
17
18
 
18
19
  export const prefixEIP191Message = (message: BytesLike): Uint8Array => {
19
20
  const messageBytes = messageToBytes(message)
20
- return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes])
21
+ if (messageIsExemptFromEIP191Prefix(messageBytes)) {
22
+ return messageBytes
23
+ } else {
24
+ return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes])
25
+ }
21
26
  }
22
27
 
23
28
  export const isValidSignature = async (