@0xsequence/provider 0.42.7 → 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 +117 -2
- package/dist/0xsequence-provider.cjs.prod.js +117 -2
- package/dist/0xsequence-provider.esm.js +117 -3
- package/dist/declarations/src/eip191exceptions.d.ts +3 -0
- package/dist/declarations/src/utils.d.ts +1 -0
- package/package.json +11 -10
- package/src/eip191exceptions.ts +137 -0
- package/src/transports/window-transport/window-message-provider.ts +2 -2
- package/src/utils/index.ts +7 -1
- package/src/utils.ts +8 -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) {
|
|
@@ -1769,6 +1882,7 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
|
|
|
1769
1882
|
return config$1;
|
|
1770
1883
|
};
|
|
1771
1884
|
const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
|
|
1885
|
+
const isUnityPlugin = () => !!navigator.userAgent.match(/UnitySequence/i);
|
|
1772
1886
|
/**
|
|
1773
1887
|
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
1774
1888
|
*
|
|
@@ -2746,7 +2860,7 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
2746
2860
|
if (!intent.options) intent.options = {}; // skip setting origin host if we're in an browser extension execution context
|
|
2747
2861
|
// allow origin that is passed in
|
|
2748
2862
|
|
|
2749
|
-
if (!isBrowserExtension()) {
|
|
2863
|
+
if (!isBrowserExtension() && !isUnityPlugin()) {
|
|
2750
2864
|
intent.options.origin = window.location.origin;
|
|
2751
2865
|
}
|
|
2752
2866
|
} // encode intent as base64 url-encoded param
|
|
@@ -4116,6 +4230,7 @@ exports.getWallet = getWallet;
|
|
|
4116
4230
|
exports.initWallet = initWallet;
|
|
4117
4231
|
exports.isBrowserExtension = isBrowserExtension;
|
|
4118
4232
|
exports.isSequenceProvider = isSequenceProvider;
|
|
4233
|
+
exports.isUnityPlugin = isUnityPlugin;
|
|
4119
4234
|
exports.isValidMessageSignature = isValidMessageSignature;
|
|
4120
4235
|
exports.isValidSignature = isValidSignature;
|
|
4121
4236
|
exports.isValidTypedDataSignature = isValidTypedDataSignature;
|
|
@@ -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) {
|
|
@@ -1769,6 +1882,7 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
|
|
|
1769
1882
|
return config$1;
|
|
1770
1883
|
};
|
|
1771
1884
|
const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
|
|
1885
|
+
const isUnityPlugin = () => !!navigator.userAgent.match(/UnitySequence/i);
|
|
1772
1886
|
/**
|
|
1773
1887
|
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
1774
1888
|
*
|
|
@@ -2746,7 +2860,7 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
2746
2860
|
if (!intent.options) intent.options = {}; // skip setting origin host if we're in an browser extension execution context
|
|
2747
2861
|
// allow origin that is passed in
|
|
2748
2862
|
|
|
2749
|
-
if (!isBrowserExtension()) {
|
|
2863
|
+
if (!isBrowserExtension() && !isUnityPlugin()) {
|
|
2750
2864
|
intent.options.origin = window.location.origin;
|
|
2751
2865
|
}
|
|
2752
2866
|
} // encode intent as base64 url-encoded param
|
|
@@ -4116,6 +4230,7 @@ exports.getWallet = getWallet;
|
|
|
4116
4230
|
exports.initWallet = initWallet;
|
|
4117
4231
|
exports.isBrowserExtension = isBrowserExtension;
|
|
4118
4232
|
exports.isSequenceProvider = isSequenceProvider;
|
|
4233
|
+
exports.isUnityPlugin = isUnityPlugin;
|
|
4119
4234
|
exports.isValidMessageSignature = isValidMessageSignature;
|
|
4120
4235
|
exports.isValidSignature = isValidSignature;
|
|
4121
4236
|
exports.isValidTypedDataSignature = isValidTypedDataSignature;
|
|
@@ -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) {
|
|
@@ -1765,6 +1878,7 @@ const recoverWalletConfig = async (address, digest, signature, chainId, walletCo
|
|
|
1765
1878
|
return config;
|
|
1766
1879
|
};
|
|
1767
1880
|
const isBrowserExtension = () => window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:';
|
|
1881
|
+
const isUnityPlugin = () => !!navigator.userAgent.match(/UnitySequence/i);
|
|
1768
1882
|
/**
|
|
1769
1883
|
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
1770
1884
|
*
|
|
@@ -2742,7 +2856,7 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
2742
2856
|
if (!intent.options) intent.options = {}; // skip setting origin host if we're in an browser extension execution context
|
|
2743
2857
|
// allow origin that is passed in
|
|
2744
2858
|
|
|
2745
|
-
if (!isBrowserExtension()) {
|
|
2859
|
+
if (!isBrowserExtension() && !isUnityPlugin()) {
|
|
2746
2860
|
intent.options.origin = window.location.origin;
|
|
2747
2861
|
}
|
|
2748
2862
|
} // encode intent as base64 url-encoded param
|
|
@@ -4081,4 +4195,4 @@ const getWallet = () => {
|
|
|
4081
4195
|
return walletInstance;
|
|
4082
4196
|
};
|
|
4083
4197
|
|
|
4084
|
-
export { BaseInjectedTransport, BaseProviderTransport, BaseWalletTransport, CHANNEL_ID, DefaultProviderConfig, ErrSignedInRequired, EventType, ExtensionMessageHandler, ExtensionMessageProvider, InitState, LocalStorage, LocalStore, LocalWeb3Provider, MuxMessageProvider, OpenState, PROVIDER_OPEN_TIMEOUT, ProviderError, ProxyMessageChannel, ProxyMessageChannelPort, ProxyMessageHandler, ProxyMessageProvider, UnrealMessageHandler, UnrealMessageProvider, Wallet, WalletRequestHandler, Web3Provider, Web3Signer, WindowMessageHandler, WindowMessageProvider, WindowSessionParams, getWallet, initWallet, isBrowserExtension, isSequenceProvider, isValidMessageSignature, isValidSignature, isValidTypedDataSignature, isWalletUpToDate, messageToBytes, nextMessageIdx, prefixEIP191Message, recoverWalletConfig };
|
|
4198
|
+
export { BaseInjectedTransport, BaseProviderTransport, BaseWalletTransport, CHANNEL_ID, DefaultProviderConfig, ErrSignedInRequired, EventType, ExtensionMessageHandler, ExtensionMessageProvider, InitState, LocalStorage, LocalStore, LocalWeb3Provider, MuxMessageProvider, OpenState, PROVIDER_OPEN_TIMEOUT, ProviderError, ProxyMessageChannel, ProxyMessageChannelPort, ProxyMessageHandler, ProxyMessageProvider, UnrealMessageHandler, UnrealMessageProvider, Wallet, WalletRequestHandler, Web3Provider, Web3Signer, WindowMessageHandler, WindowMessageProvider, WindowSessionParams, getWallet, initWallet, isBrowserExtension, isSequenceProvider, isUnityPlugin, isValidMessageSignature, isValidSignature, isValidTypedDataSignature, isWalletUpToDate, messageToBytes, nextMessageIdx, prefixEIP191Message, recoverWalletConfig };
|
|
@@ -11,6 +11,7 @@ export declare const isValidMessageSignature: (address: string, message: string
|
|
|
11
11
|
export declare const isValidTypedDataSignature: (address: string, typedData: TypedData, signature: string, provider: Web3Provider | ethers.providers.Web3Provider, chainId?: number | undefined, walletContext?: WalletContext | undefined) => Promise<boolean | undefined>;
|
|
12
12
|
export declare const recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
13
13
|
export declare const isBrowserExtension: () => boolean;
|
|
14
|
+
export declare const isUnityPlugin: () => boolean;
|
|
14
15
|
/**
|
|
15
16
|
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
16
17
|
*
|
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
|
+
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenWalletIntent, ProviderMessage, InitState, EventType, WindowSessionParams } from '../../types'
|
|
2
2
|
import { BaseProviderTransport } from '../base-provider-transport'
|
|
3
3
|
import { logger, base64EncodeObject } from '@0xsequence/utils'
|
|
4
|
-
import { isBrowserExtension } from '../../utils'
|
|
4
|
+
import { isBrowserExtension, isUnityPlugin } from '../../utils'
|
|
5
5
|
|
|
6
6
|
// ..
|
|
7
7
|
let registeredWindowMessageProvider: WindowMessageProvider | undefined
|
|
@@ -92,7 +92,7 @@ export class WindowMessageProvider extends BaseProviderTransport {
|
|
|
92
92
|
|
|
93
93
|
// skip setting origin host if we're in an browser extension execution context
|
|
94
94
|
// allow origin that is passed in
|
|
95
|
-
if (!isBrowserExtension()) {
|
|
95
|
+
if (!isBrowserExtension() && !isUnityPlugin()) {
|
|
96
96
|
intent.options.origin = window.location.origin
|
|
97
97
|
}
|
|
98
98
|
}
|
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 (
|
|
@@ -86,6 +91,8 @@ export const recoverWalletConfig = async (
|
|
|
86
91
|
export const isBrowserExtension = (): boolean =>
|
|
87
92
|
window.location.protocol === 'chrome-extension:' || window.location.protocol === 'moz-extension:'
|
|
88
93
|
|
|
94
|
+
export const isUnityPlugin = (): boolean => !!navigator.userAgent.match(/UnitySequence/i)
|
|
95
|
+
|
|
89
96
|
/**
|
|
90
97
|
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
91
98
|
*
|