@0xsequence/provider 0.34.1 → 0.35.0
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 +25 -0
- package/dist/0xsequence-provider.cjs.dev.js +103 -36
- package/dist/0xsequence-provider.cjs.prod.js +103 -36
- package/dist/0xsequence-provider.esm.js +104 -38
- package/dist/declarations/src/commands/index.d.ts +3 -3
- package/dist/declarations/src/transports/base-provider-transport.d.ts +1 -1
- package/dist/declarations/src/transports/base-wallet-transport.d.ts +1 -1
- package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +1 -0
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +3 -1
- package/dist/declarations/src/utils.d.ts +12 -2
- package/dist/declarations/src/wallet.d.ts +1 -1
- package/package.json +8 -8
- package/src/transports/wallet-request-handler.ts +56 -36
- package/src/utils.ts +47 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @0xsequence/provider
|
|
2
2
|
|
|
3
|
+
## 0.35.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- - config: add buildStubSignature
|
|
8
|
+
- provider: add checks to signing cases for wallet deployment and config statuses
|
|
9
|
+
- provider: add prompt for wallet deployment
|
|
10
|
+
- relayer: add BaseRelayer.prependWalletDeploy
|
|
11
|
+
- relayer: add Relayer.feeOptions
|
|
12
|
+
- relayer: account for wallet deployment in fee estimation
|
|
13
|
+
- transactions: add fromTransactionish
|
|
14
|
+
- wallet: add Account.prependConfigUpdate
|
|
15
|
+
- wallet: add Account.getFeeOptions
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @0xsequence/abi@0.35.0
|
|
21
|
+
- @0xsequence/auth@0.35.0
|
|
22
|
+
- @0xsequence/config@0.35.0
|
|
23
|
+
- @0xsequence/network@0.35.0
|
|
24
|
+
- @0xsequence/transactions@0.35.0
|
|
25
|
+
- @0xsequence/utils@0.35.0
|
|
26
|
+
- @0xsequence/wallet@0.35.0
|
|
27
|
+
|
|
3
28
|
## 0.34.1
|
|
4
29
|
|
|
5
30
|
### 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:';
|
|
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
|
-
|
|
1739
|
-
|
|
1740
|
-
//
|
|
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 (
|
|
1754
|
-
|
|
1790
|
+
if (request.method === 'personal_sign') {
|
|
1791
|
+
const [data, address] = request.params;
|
|
1792
|
+
message = data;
|
|
1755
1793
|
} else {
|
|
1756
|
-
|
|
1757
|
-
|
|
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
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
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
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
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:';
|
|
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
|
-
|
|
1739
|
-
|
|
1740
|
-
//
|
|
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 (
|
|
1754
|
-
|
|
1790
|
+
if (request.method === 'personal_sign') {
|
|
1791
|
+
const [data, address] = request.params;
|
|
1792
|
+
message = data;
|
|
1755
1793
|
} else {
|
|
1756
|
-
|
|
1757
|
-
|
|
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
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
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
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
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:';
|
|
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
|
-
|
|
1735
|
-
|
|
1736
|
-
//
|
|
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 (
|
|
1750
|
-
|
|
1786
|
+
if (request.method === 'personal_sign') {
|
|
1787
|
+
const [data, address] = request.params;
|
|
1788
|
+
message = data;
|
|
1751
1789
|
} else {
|
|
1752
|
-
|
|
1753
|
-
|
|
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
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
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
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
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 };
|
|
@@ -14,7 +14,7 @@ export declare class WalletCommands {
|
|
|
14
14
|
isValidSignature(address: string, digest: Uint8Array, signature: string, chainId: number, walletContext?: WalletContext): Promise<boolean | undefined>;
|
|
15
15
|
isValidMessageSignature(address: string, message: string | Uint8Array, signature: string, chainId: number, walletContext?: WalletContext): Promise<boolean | undefined>;
|
|
16
16
|
isValidTypedDataSignature(address: string, typedData: TypedData, signature: string, chainId: number, walletContext?: WalletContext): Promise<boolean | undefined>;
|
|
17
|
-
recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?:
|
|
18
|
-
recoverWalletConfigFromMessage: (address: string, message: string | Uint8Array, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?:
|
|
19
|
-
recoverWalletConfigFromTypedData: (address: string, typedData: TypedData, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?:
|
|
17
|
+
recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
18
|
+
recoverWalletConfigFromMessage: (address: string, message: string | Uint8Array, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
19
|
+
recoverWalletConfigFromTypedData: (address: string, typedData: TypedData, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
20
20
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProviderTransport, ProviderMessage, ProviderMessageRequest, ProviderEventTypes, ProviderMessageResponse, ProviderMessageResponseCallback, OpenState, OpenWalletIntent, ConnectDetails, WalletSession, ProviderRpcError, InitState, TypedEventEmitter } from '../types';
|
|
2
|
-
import { NetworkConfig, WalletContext } from '@0xsequence/network';
|
|
2
|
+
import { NetworkConfig, WalletContext, JsonRpcRequest, JsonRpcResponseCallback } from '@0xsequence/network';
|
|
3
3
|
export declare const PROVIDER_OPEN_TIMEOUT = 30000;
|
|
4
4
|
export declare const nextMessageIdx: () => number;
|
|
5
5
|
export declare abstract class BaseProviderTransport implements ProviderTransport {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WalletTransport, ProviderMessage, ProviderMessageRequest, ProviderMessageResponse, ProviderRpcError, InitState, ConnectDetails, WalletSession, TransportSession } from '../types';
|
|
2
2
|
import { WalletRequestHandler } from './wallet-request-handler';
|
|
3
|
-
import { NetworkConfig, WalletContext } from '@0xsequence/network';
|
|
3
|
+
import { NetworkConfig, WalletContext, JsonRpcRequest, JsonRpcResponseCallback } from '@0xsequence/network';
|
|
4
4
|
export declare abstract class BaseWalletTransport implements WalletTransport {
|
|
5
5
|
protected walletRequestHandler: WalletRequestHandler;
|
|
6
6
|
protected _sessionId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProviderMessage, ProviderTransport, ProviderEventTypes, ProviderMessageRequest, ProviderMessageResponse, WalletSession, OpenWalletIntent, ConnectDetails } from '../../types';
|
|
2
|
+
import { JsonRpcRequest, JsonRpcResponseCallback } from '@0xsequence/network';
|
|
2
3
|
export declare class MuxMessageProvider implements ProviderTransport {
|
|
3
4
|
private messageProviders;
|
|
4
5
|
private provider;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProviderMessageRequest, ProviderMessageResponse, ProviderMessageRequestHandler, MessageToSign, ProviderRpcError, ConnectOptions, ConnectDetails, PromptConnectDetails, WalletSession, ProviderEventTypes } from '../types';
|
|
2
2
|
import { ExternalProvider } from '@ethersproject/providers';
|
|
3
|
-
import { Networks, NetworkConfig, JsonRpcHandler } from '@0xsequence/network';
|
|
3
|
+
import { Networks, NetworkConfig, JsonRpcHandler, JsonRpcRequest, JsonRpcResponseCallback } from '@0xsequence/network';
|
|
4
4
|
import { Signer } from '@0xsequence/wallet';
|
|
5
5
|
import { TransactionRequest } from '@0xsequence/transactions';
|
|
6
6
|
export interface WalletSignInOptions {
|
|
@@ -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>;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { BigNumberish, BytesLike } from 'ethers';
|
|
2
|
+
import { WalletContext } from '@0xsequence/network';
|
|
2
3
|
import { WalletConfig, DecodedSignature } from '@0xsequence/config';
|
|
3
4
|
import { Web3Provider } from './provider';
|
|
4
|
-
|
|
5
|
-
export declare const
|
|
5
|
+
import { Signer } from '@0xsequence/wallet';
|
|
6
|
+
export declare const isValidSignature: (address: string, digest: Uint8Array, sig: string, provider: Web3Provider, chainId?: number | undefined, walletContext?: WalletContext | undefined) => Promise<boolean | undefined>;
|
|
7
|
+
export declare const recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
6
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>;
|
|
7
17
|
export declare class LocalStore<T extends Object = string> {
|
|
8
18
|
def?: T | undefined;
|
|
9
19
|
readonly key: string;
|
|
@@ -50,7 +50,7 @@ export declare class Wallet implements WalletProvider {
|
|
|
50
50
|
isConnected(): boolean;
|
|
51
51
|
getSession: () => WalletSession | undefined;
|
|
52
52
|
getAddress: () => Promise<string>;
|
|
53
|
-
getNetworks: (chainId?:
|
|
53
|
+
getNetworks: (chainId?: ChainIdLike | undefined) => Promise<NetworkConfig[]>;
|
|
54
54
|
getChainId: () => Promise<number>;
|
|
55
55
|
getAuthChainId: () => Promise<number>;
|
|
56
56
|
openWallet: (path?: string | undefined, intent?: OpenWalletIntent | undefined, networkId?: string | number | undefined) => Promise<boolean>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
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,13 +13,13 @@
|
|
|
13
13
|
"typecheck": "tsc --noEmit"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@0xsequence/abi": "^0.
|
|
17
|
-
"@0xsequence/auth": "^0.
|
|
18
|
-
"@0xsequence/config": "^0.
|
|
19
|
-
"@0xsequence/network": "^0.
|
|
20
|
-
"@0xsequence/transactions": "^0.
|
|
21
|
-
"@0xsequence/utils": "^0.
|
|
22
|
-
"@0xsequence/wallet": "^0.
|
|
16
|
+
"@0xsequence/abi": "^0.35.0",
|
|
17
|
+
"@0xsequence/auth": "^0.35.0",
|
|
18
|
+
"@0xsequence/config": "^0.35.0",
|
|
19
|
+
"@0xsequence/network": "^0.35.0",
|
|
20
|
+
"@0xsequence/transactions": "^0.35.0",
|
|
21
|
+
"@0xsequence/utils": "^0.35.0",
|
|
22
|
+
"@0xsequence/wallet": "^0.35.0",
|
|
23
23
|
"@ethersproject/abstract-signer": "^5.5.0",
|
|
24
24
|
"@ethersproject/hash": "^5.5.0",
|
|
25
25
|
"@ethersproject/providers": "^5.5.1",
|
|
@@ -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 {
|
|
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 {
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
267
|
-
|
|
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
|
-
|
|
291
|
-
|
|
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
|
-
|
|
328
|
-
|
|
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 |
|
|
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 =>
|
|
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> {
|