@0xsequence/provider 0.42.8 → 0.42.9
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/dist/0xsequence-provider.cjs.dev.js +114 -1
- package/dist/0xsequence-provider.cjs.prod.js +114 -1
- package/dist/0xsequence-provider.esm.js +114 -1
- package/dist/declarations/src/eip191exceptions.d.ts +3 -0
- package/package.json +11 -10
- package/src/eip191exceptions.ts +137 -0
- package/src/utils/index.ts +7 -1
- package/src/utils.ts +6 -1
|
@@ -1719,6 +1719,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
|
|
|
1719
1719
|
return result;
|
|
1720
1720
|
};
|
|
1721
1721
|
|
|
1722
|
+
function messageIsExemptFromEIP191Prefix(message) {
|
|
1723
|
+
return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
|
|
1724
|
+
}
|
|
1725
|
+
const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
|
|
1726
|
+
{
|
|
1727
|
+
name: 'Decentraland Exception',
|
|
1728
|
+
predicate: isDecentralandLoginMessage
|
|
1729
|
+
}, // NOTE: 0x v3 does not support 191 correctly.
|
|
1730
|
+
// See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
|
|
1731
|
+
{
|
|
1732
|
+
name: '0x v3 Exception',
|
|
1733
|
+
predicate: isZeroExV3Order
|
|
1734
|
+
}];
|
|
1735
|
+
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)?)$/;
|
|
1736
|
+
function isDecentralandLoginMessage(bytes) {
|
|
1737
|
+
try {
|
|
1738
|
+
const stringified = ethers.ethers.utils.toUtf8String(bytes);
|
|
1739
|
+
return DCL_REGEX.test(stringified);
|
|
1740
|
+
} catch (_unused) {
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1743
|
+
} // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
|
|
1744
|
+
// see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
|
|
1745
|
+
|
|
1746
|
+
function isZeroExV3Order(bytes) {
|
|
1747
|
+
const abi = new ethers.ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
1748
|
+
|
|
1749
|
+
try {
|
|
1750
|
+
abi.decodeFunctionData('OrderWithHash', bytes);
|
|
1751
|
+
return true;
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
// failed to decode ABI, so it's not a v3 order.
|
|
1754
|
+
return false;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
const ZeroXV3EIP1271OrderWithHashAbi = [{
|
|
1758
|
+
inputs: [{
|
|
1759
|
+
components: [{
|
|
1760
|
+
internalType: 'address',
|
|
1761
|
+
name: 'makerAddress',
|
|
1762
|
+
type: 'address'
|
|
1763
|
+
}, {
|
|
1764
|
+
internalType: 'address',
|
|
1765
|
+
name: 'takerAddress',
|
|
1766
|
+
type: 'address'
|
|
1767
|
+
}, {
|
|
1768
|
+
internalType: 'address',
|
|
1769
|
+
name: 'feeRecipientAddress',
|
|
1770
|
+
type: 'address'
|
|
1771
|
+
}, {
|
|
1772
|
+
internalType: 'address',
|
|
1773
|
+
name: 'senderAddress',
|
|
1774
|
+
type: 'address'
|
|
1775
|
+
}, {
|
|
1776
|
+
internalType: 'uint256',
|
|
1777
|
+
name: 'makerAssetAmount',
|
|
1778
|
+
type: 'uint256'
|
|
1779
|
+
}, {
|
|
1780
|
+
internalType: 'uint256',
|
|
1781
|
+
name: 'takerAssetAmount',
|
|
1782
|
+
type: 'uint256'
|
|
1783
|
+
}, {
|
|
1784
|
+
internalType: 'uint256',
|
|
1785
|
+
name: 'makerFee',
|
|
1786
|
+
type: 'uint256'
|
|
1787
|
+
}, {
|
|
1788
|
+
internalType: 'uint256',
|
|
1789
|
+
name: 'takerFee',
|
|
1790
|
+
type: 'uint256'
|
|
1791
|
+
}, {
|
|
1792
|
+
internalType: 'uint256',
|
|
1793
|
+
name: 'expirationTimeSeconds',
|
|
1794
|
+
type: 'uint256'
|
|
1795
|
+
}, {
|
|
1796
|
+
internalType: 'uint256',
|
|
1797
|
+
name: 'salt',
|
|
1798
|
+
type: 'uint256'
|
|
1799
|
+
}, {
|
|
1800
|
+
internalType: 'bytes',
|
|
1801
|
+
name: 'makerAssetData',
|
|
1802
|
+
type: 'bytes'
|
|
1803
|
+
}, {
|
|
1804
|
+
internalType: 'bytes',
|
|
1805
|
+
name: 'takerAssetData',
|
|
1806
|
+
type: 'bytes'
|
|
1807
|
+
}, {
|
|
1808
|
+
internalType: 'bytes',
|
|
1809
|
+
name: 'makerFeeAssetData',
|
|
1810
|
+
type: 'bytes'
|
|
1811
|
+
}, {
|
|
1812
|
+
internalType: 'bytes',
|
|
1813
|
+
name: 'takerFeeAssetData',
|
|
1814
|
+
type: 'bytes'
|
|
1815
|
+
}],
|
|
1816
|
+
internalType: 'struct IEIP1271Data.Order',
|
|
1817
|
+
name: 'order',
|
|
1818
|
+
type: 'tuple'
|
|
1819
|
+
}, {
|
|
1820
|
+
internalType: 'bytes32',
|
|
1821
|
+
name: 'orderHash',
|
|
1822
|
+
type: 'bytes32'
|
|
1823
|
+
}],
|
|
1824
|
+
name: 'OrderWithHash',
|
|
1825
|
+
outputs: [],
|
|
1826
|
+
stateMutability: 'pure',
|
|
1827
|
+
type: 'function'
|
|
1828
|
+
}];
|
|
1829
|
+
|
|
1722
1830
|
const eip191prefix = ethers.ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
1723
1831
|
const messageToBytes = message => {
|
|
1724
1832
|
if (ethers.ethers.utils.isBytes(message) || ethers.ethers.utils.isHexString(message)) {
|
|
@@ -1729,7 +1837,12 @@ const messageToBytes = message => {
|
|
|
1729
1837
|
};
|
|
1730
1838
|
const prefixEIP191Message = message => {
|
|
1731
1839
|
const messageBytes = messageToBytes(message);
|
|
1732
|
-
|
|
1840
|
+
|
|
1841
|
+
if (messageIsExemptFromEIP191Prefix(messageBytes)) {
|
|
1842
|
+
return messageBytes;
|
|
1843
|
+
} else {
|
|
1844
|
+
return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
|
|
1845
|
+
}
|
|
1733
1846
|
};
|
|
1734
1847
|
const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
|
|
1735
1848
|
if (!chainId) {
|
|
@@ -1719,6 +1719,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
|
|
|
1719
1719
|
return result;
|
|
1720
1720
|
};
|
|
1721
1721
|
|
|
1722
|
+
function messageIsExemptFromEIP191Prefix(message) {
|
|
1723
|
+
return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
|
|
1724
|
+
}
|
|
1725
|
+
const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
|
|
1726
|
+
{
|
|
1727
|
+
name: 'Decentraland Exception',
|
|
1728
|
+
predicate: isDecentralandLoginMessage
|
|
1729
|
+
}, // NOTE: 0x v3 does not support 191 correctly.
|
|
1730
|
+
// See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
|
|
1731
|
+
{
|
|
1732
|
+
name: '0x v3 Exception',
|
|
1733
|
+
predicate: isZeroExV3Order
|
|
1734
|
+
}];
|
|
1735
|
+
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)?)$/;
|
|
1736
|
+
function isDecentralandLoginMessage(bytes) {
|
|
1737
|
+
try {
|
|
1738
|
+
const stringified = ethers.ethers.utils.toUtf8String(bytes);
|
|
1739
|
+
return DCL_REGEX.test(stringified);
|
|
1740
|
+
} catch (_unused) {
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1743
|
+
} // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
|
|
1744
|
+
// see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
|
|
1745
|
+
|
|
1746
|
+
function isZeroExV3Order(bytes) {
|
|
1747
|
+
const abi = new ethers.ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
1748
|
+
|
|
1749
|
+
try {
|
|
1750
|
+
abi.decodeFunctionData('OrderWithHash', bytes);
|
|
1751
|
+
return true;
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
// failed to decode ABI, so it's not a v3 order.
|
|
1754
|
+
return false;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
const ZeroXV3EIP1271OrderWithHashAbi = [{
|
|
1758
|
+
inputs: [{
|
|
1759
|
+
components: [{
|
|
1760
|
+
internalType: 'address',
|
|
1761
|
+
name: 'makerAddress',
|
|
1762
|
+
type: 'address'
|
|
1763
|
+
}, {
|
|
1764
|
+
internalType: 'address',
|
|
1765
|
+
name: 'takerAddress',
|
|
1766
|
+
type: 'address'
|
|
1767
|
+
}, {
|
|
1768
|
+
internalType: 'address',
|
|
1769
|
+
name: 'feeRecipientAddress',
|
|
1770
|
+
type: 'address'
|
|
1771
|
+
}, {
|
|
1772
|
+
internalType: 'address',
|
|
1773
|
+
name: 'senderAddress',
|
|
1774
|
+
type: 'address'
|
|
1775
|
+
}, {
|
|
1776
|
+
internalType: 'uint256',
|
|
1777
|
+
name: 'makerAssetAmount',
|
|
1778
|
+
type: 'uint256'
|
|
1779
|
+
}, {
|
|
1780
|
+
internalType: 'uint256',
|
|
1781
|
+
name: 'takerAssetAmount',
|
|
1782
|
+
type: 'uint256'
|
|
1783
|
+
}, {
|
|
1784
|
+
internalType: 'uint256',
|
|
1785
|
+
name: 'makerFee',
|
|
1786
|
+
type: 'uint256'
|
|
1787
|
+
}, {
|
|
1788
|
+
internalType: 'uint256',
|
|
1789
|
+
name: 'takerFee',
|
|
1790
|
+
type: 'uint256'
|
|
1791
|
+
}, {
|
|
1792
|
+
internalType: 'uint256',
|
|
1793
|
+
name: 'expirationTimeSeconds',
|
|
1794
|
+
type: 'uint256'
|
|
1795
|
+
}, {
|
|
1796
|
+
internalType: 'uint256',
|
|
1797
|
+
name: 'salt',
|
|
1798
|
+
type: 'uint256'
|
|
1799
|
+
}, {
|
|
1800
|
+
internalType: 'bytes',
|
|
1801
|
+
name: 'makerAssetData',
|
|
1802
|
+
type: 'bytes'
|
|
1803
|
+
}, {
|
|
1804
|
+
internalType: 'bytes',
|
|
1805
|
+
name: 'takerAssetData',
|
|
1806
|
+
type: 'bytes'
|
|
1807
|
+
}, {
|
|
1808
|
+
internalType: 'bytes',
|
|
1809
|
+
name: 'makerFeeAssetData',
|
|
1810
|
+
type: 'bytes'
|
|
1811
|
+
}, {
|
|
1812
|
+
internalType: 'bytes',
|
|
1813
|
+
name: 'takerFeeAssetData',
|
|
1814
|
+
type: 'bytes'
|
|
1815
|
+
}],
|
|
1816
|
+
internalType: 'struct IEIP1271Data.Order',
|
|
1817
|
+
name: 'order',
|
|
1818
|
+
type: 'tuple'
|
|
1819
|
+
}, {
|
|
1820
|
+
internalType: 'bytes32',
|
|
1821
|
+
name: 'orderHash',
|
|
1822
|
+
type: 'bytes32'
|
|
1823
|
+
}],
|
|
1824
|
+
name: 'OrderWithHash',
|
|
1825
|
+
outputs: [],
|
|
1826
|
+
stateMutability: 'pure',
|
|
1827
|
+
type: 'function'
|
|
1828
|
+
}];
|
|
1829
|
+
|
|
1722
1830
|
const eip191prefix = ethers.ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
1723
1831
|
const messageToBytes = message => {
|
|
1724
1832
|
if (ethers.ethers.utils.isBytes(message) || ethers.ethers.utils.isHexString(message)) {
|
|
@@ -1729,7 +1837,12 @@ const messageToBytes = message => {
|
|
|
1729
1837
|
};
|
|
1730
1838
|
const prefixEIP191Message = message => {
|
|
1731
1839
|
const messageBytes = messageToBytes(message);
|
|
1732
|
-
|
|
1840
|
+
|
|
1841
|
+
if (messageIsExemptFromEIP191Prefix(messageBytes)) {
|
|
1842
|
+
return messageBytes;
|
|
1843
|
+
} else {
|
|
1844
|
+
return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
|
|
1845
|
+
}
|
|
1733
1846
|
};
|
|
1734
1847
|
const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
|
|
1735
1848
|
if (!chainId) {
|
|
@@ -1715,6 +1715,114 @@ const hexlifyTransaction = (transaction, allowExtra) => {
|
|
|
1715
1715
|
return result;
|
|
1716
1716
|
};
|
|
1717
1717
|
|
|
1718
|
+
function messageIsExemptFromEIP191Prefix(message) {
|
|
1719
|
+
return EIP_191_PREFIX_EXCEPTIONS.some(e => e.predicate(message));
|
|
1720
|
+
}
|
|
1721
|
+
const EIP_191_PREFIX_EXCEPTIONS = [// NOTE: Decentraland does not support 191 correctly.
|
|
1722
|
+
{
|
|
1723
|
+
name: 'Decentraland Exception',
|
|
1724
|
+
predicate: isDecentralandLoginMessage
|
|
1725
|
+
}, // NOTE: 0x v3 does not support 191 correctly.
|
|
1726
|
+
// See https://gov.0x.org/t/zeip-proposal-fix-v3-eip-191-non-compliance-when-validating-eip-1271-signatures/3396 for more info.
|
|
1727
|
+
{
|
|
1728
|
+
name: '0x v3 Exception',
|
|
1729
|
+
predicate: isZeroExV3Order
|
|
1730
|
+
}];
|
|
1731
|
+
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)?)$/;
|
|
1732
|
+
function isDecentralandLoginMessage(bytes) {
|
|
1733
|
+
try {
|
|
1734
|
+
const stringified = ethers.utils.toUtf8String(bytes);
|
|
1735
|
+
return DCL_REGEX.test(stringified);
|
|
1736
|
+
} catch (_unused) {
|
|
1737
|
+
return false;
|
|
1738
|
+
}
|
|
1739
|
+
} // try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
|
|
1740
|
+
// see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
|
|
1741
|
+
|
|
1742
|
+
function isZeroExV3Order(bytes) {
|
|
1743
|
+
const abi = new ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
1744
|
+
|
|
1745
|
+
try {
|
|
1746
|
+
abi.decodeFunctionData('OrderWithHash', bytes);
|
|
1747
|
+
return true;
|
|
1748
|
+
} catch (err) {
|
|
1749
|
+
// failed to decode ABI, so it's not a v3 order.
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
const ZeroXV3EIP1271OrderWithHashAbi = [{
|
|
1754
|
+
inputs: [{
|
|
1755
|
+
components: [{
|
|
1756
|
+
internalType: 'address',
|
|
1757
|
+
name: 'makerAddress',
|
|
1758
|
+
type: 'address'
|
|
1759
|
+
}, {
|
|
1760
|
+
internalType: 'address',
|
|
1761
|
+
name: 'takerAddress',
|
|
1762
|
+
type: 'address'
|
|
1763
|
+
}, {
|
|
1764
|
+
internalType: 'address',
|
|
1765
|
+
name: 'feeRecipientAddress',
|
|
1766
|
+
type: 'address'
|
|
1767
|
+
}, {
|
|
1768
|
+
internalType: 'address',
|
|
1769
|
+
name: 'senderAddress',
|
|
1770
|
+
type: 'address'
|
|
1771
|
+
}, {
|
|
1772
|
+
internalType: 'uint256',
|
|
1773
|
+
name: 'makerAssetAmount',
|
|
1774
|
+
type: 'uint256'
|
|
1775
|
+
}, {
|
|
1776
|
+
internalType: 'uint256',
|
|
1777
|
+
name: 'takerAssetAmount',
|
|
1778
|
+
type: 'uint256'
|
|
1779
|
+
}, {
|
|
1780
|
+
internalType: 'uint256',
|
|
1781
|
+
name: 'makerFee',
|
|
1782
|
+
type: 'uint256'
|
|
1783
|
+
}, {
|
|
1784
|
+
internalType: 'uint256',
|
|
1785
|
+
name: 'takerFee',
|
|
1786
|
+
type: 'uint256'
|
|
1787
|
+
}, {
|
|
1788
|
+
internalType: 'uint256',
|
|
1789
|
+
name: 'expirationTimeSeconds',
|
|
1790
|
+
type: 'uint256'
|
|
1791
|
+
}, {
|
|
1792
|
+
internalType: 'uint256',
|
|
1793
|
+
name: 'salt',
|
|
1794
|
+
type: 'uint256'
|
|
1795
|
+
}, {
|
|
1796
|
+
internalType: 'bytes',
|
|
1797
|
+
name: 'makerAssetData',
|
|
1798
|
+
type: 'bytes'
|
|
1799
|
+
}, {
|
|
1800
|
+
internalType: 'bytes',
|
|
1801
|
+
name: 'takerAssetData',
|
|
1802
|
+
type: 'bytes'
|
|
1803
|
+
}, {
|
|
1804
|
+
internalType: 'bytes',
|
|
1805
|
+
name: 'makerFeeAssetData',
|
|
1806
|
+
type: 'bytes'
|
|
1807
|
+
}, {
|
|
1808
|
+
internalType: 'bytes',
|
|
1809
|
+
name: 'takerFeeAssetData',
|
|
1810
|
+
type: 'bytes'
|
|
1811
|
+
}],
|
|
1812
|
+
internalType: 'struct IEIP1271Data.Order',
|
|
1813
|
+
name: 'order',
|
|
1814
|
+
type: 'tuple'
|
|
1815
|
+
}, {
|
|
1816
|
+
internalType: 'bytes32',
|
|
1817
|
+
name: 'orderHash',
|
|
1818
|
+
type: 'bytes32'
|
|
1819
|
+
}],
|
|
1820
|
+
name: 'OrderWithHash',
|
|
1821
|
+
outputs: [],
|
|
1822
|
+
stateMutability: 'pure',
|
|
1823
|
+
type: 'function'
|
|
1824
|
+
}];
|
|
1825
|
+
|
|
1718
1826
|
const eip191prefix = ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
1719
1827
|
const messageToBytes = message => {
|
|
1720
1828
|
if (ethers.utils.isBytes(message) || ethers.utils.isHexString(message)) {
|
|
@@ -1725,7 +1833,12 @@ const messageToBytes = message => {
|
|
|
1725
1833
|
};
|
|
1726
1834
|
const prefixEIP191Message = message => {
|
|
1727
1835
|
const messageBytes = messageToBytes(message);
|
|
1728
|
-
|
|
1836
|
+
|
|
1837
|
+
if (messageIsExemptFromEIP191Prefix(messageBytes)) {
|
|
1838
|
+
return messageBytes;
|
|
1839
|
+
} else {
|
|
1840
|
+
return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
|
|
1841
|
+
}
|
|
1729
1842
|
};
|
|
1730
1843
|
const isValidSignature = async (address, digest, sig, provider, chainId, walletContext) => {
|
|
1731
1844
|
if (!chainId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/provider",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.9",
|
|
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": "
|
|
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.
|
|
17
|
-
"@0xsequence/auth": "^0.42.
|
|
18
|
-
"@0xsequence/config": "^0.42.
|
|
19
|
-
"@0xsequence/network": "^0.42.
|
|
20
|
-
"@0xsequence/transactions": "^0.42.
|
|
21
|
-
"@0xsequence/utils": "^0.42.
|
|
22
|
-
"@0xsequence/wallet": "^0.42.
|
|
17
|
+
"@0xsequence/abi": "^0.42.9",
|
|
18
|
+
"@0xsequence/auth": "^0.42.9",
|
|
19
|
+
"@0xsequence/config": "^0.42.9",
|
|
20
|
+
"@0xsequence/network": "^0.42.9",
|
|
21
|
+
"@0xsequence/transactions": "^0.42.9",
|
|
22
|
+
"@0xsequence/utils": "^0.42.9",
|
|
23
|
+
"@0xsequence/wallet": "^0.42.9",
|
|
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/utils/index.ts
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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 (
|