@0xsequence/provider 0.34.0 → 0.35.2
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 +60 -0
- package/dist/0xsequence-provider.cjs.dev.js +105 -38
- package/dist/0xsequence-provider.cjs.prod.js +105 -38
- package/dist/0xsequence-provider.esm.js +106 -40
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +2 -0
- package/dist/declarations/src/transports/window-transport/window-message-handler.d.ts +1 -1
- package/dist/declarations/src/utils.d.ts +9 -0
- package/package.json +8 -8
- package/src/transports/wallet-request-handler.ts +56 -36
- package/src/transports/window-transport/window-message-handler.ts +2 -2
- package/src/utils.ts +47 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @0xsequence/provider
|
|
2
2
|
|
|
3
|
+
## 0.35.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- - provider: WindowMessageHandler accept optional windowHref
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @0xsequence/abi@0.35.2
|
|
10
|
+
- @0xsequence/auth@0.35.2
|
|
11
|
+
- @0xsequence/config@0.35.2
|
|
12
|
+
- @0xsequence/network@0.35.2
|
|
13
|
+
- @0xsequence/transactions@0.35.2
|
|
14
|
+
- @0xsequence/utils@0.35.2
|
|
15
|
+
- @0xsequence/wallet@0.35.2
|
|
16
|
+
|
|
17
|
+
## 0.35.1
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- wallet: update config on undeployed too
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @0xsequence/abi@0.35.1
|
|
24
|
+
- @0xsequence/auth@0.35.1
|
|
25
|
+
- @0xsequence/config@0.35.1
|
|
26
|
+
- @0xsequence/network@0.35.1
|
|
27
|
+
- @0xsequence/transactions@0.35.1
|
|
28
|
+
- @0xsequence/utils@0.35.1
|
|
29
|
+
- @0xsequence/wallet@0.35.1
|
|
30
|
+
|
|
31
|
+
## 0.35.0
|
|
32
|
+
|
|
33
|
+
### Minor Changes
|
|
34
|
+
|
|
35
|
+
- - config: add buildStubSignature
|
|
36
|
+
- provider: add checks to signing cases for wallet deployment and config statuses
|
|
37
|
+
- provider: add prompt for wallet deployment
|
|
38
|
+
- relayer: add BaseRelayer.prependWalletDeploy
|
|
39
|
+
- relayer: add Relayer.feeOptions
|
|
40
|
+
- relayer: account for wallet deployment in fee estimation
|
|
41
|
+
- transactions: add fromTransactionish
|
|
42
|
+
- wallet: add Account.prependConfigUpdate
|
|
43
|
+
- wallet: add Account.getFeeOptions
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies
|
|
48
|
+
- @0xsequence/abi@0.35.0
|
|
49
|
+
- @0xsequence/auth@0.35.0
|
|
50
|
+
- @0xsequence/config@0.35.0
|
|
51
|
+
- @0xsequence/network@0.35.0
|
|
52
|
+
- @0xsequence/transactions@0.35.0
|
|
53
|
+
- @0xsequence/utils@0.35.0
|
|
54
|
+
- @0xsequence/wallet@0.35.0
|
|
55
|
+
|
|
56
|
+
## 0.34.1
|
|
57
|
+
|
|
58
|
+
### Patch Changes
|
|
59
|
+
|
|
60
|
+
- Updated dependencies
|
|
61
|
+
- @0xsequence/auth@0.34.1
|
|
62
|
+
|
|
3
63
|
## 0.34.0
|
|
4
64
|
|
|
5
65
|
### Minor 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) {
|
|
@@ -1536,7 +1583,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1536
1583
|
this._init = exports.InitState.NIL;
|
|
1537
1584
|
}
|
|
1538
1585
|
|
|
1539
|
-
register() {
|
|
1586
|
+
register(windowHref) {
|
|
1540
1587
|
const isPopup = parent.window.opener !== null;
|
|
1541
1588
|
this._isPopup = isPopup;
|
|
1542
1589
|
|
|
@@ -1548,7 +1595,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1548
1595
|
const {
|
|
1549
1596
|
pathname,
|
|
1550
1597
|
search: rawParams
|
|
1551
|
-
} = new URL(window.location.href);
|
|
1598
|
+
} = new URL(windowHref || window.location.href);
|
|
1552
1599
|
let session = this.getWindowTransportSession(rawParams); // provider should always include sid when opening a new window
|
|
1553
1600
|
|
|
1554
1601
|
const isNewWindowSession = !!session.sessionId; // attempt to restore previous session in the case of a redirect or window reload
|
|
@@ -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
|
-
//
|
|
1786
|
+
let message; // there is a difference in the order of the params:
|
|
1787
|
+
// personal_sign: [data, address]
|
|
1788
|
+
// eth_sign: [address, data]
|
|
1741
1789
|
|
|
1742
|
-
if (
|
|
1743
|
-
|
|
1744
|
-
|
|
1790
|
+
if (request.method === 'personal_sign') {
|
|
1791
|
+
const [data, address] = request.params;
|
|
1792
|
+
message = data;
|
|
1745
1793
|
} else {
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
chainId: chainId,
|
|
1749
|
-
message: message
|
|
1750
|
-
});
|
|
1794
|
+
const [address, data] = request.params;
|
|
1795
|
+
message = data;
|
|
1751
1796
|
}
|
|
1752
1797
|
|
|
1753
|
-
if (sig && sig.length > 0) {
|
|
1754
|
-
response.result = sig;
|
|
1755
|
-
} else {
|
|
1756
|
-
// The user has declined the request when value is null
|
|
1757
|
-
throw new Error('declined by user');
|
|
1758
|
-
}
|
|
1759
|
-
|
|
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) {
|
|
@@ -1536,7 +1583,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1536
1583
|
this._init = exports.InitState.NIL;
|
|
1537
1584
|
}
|
|
1538
1585
|
|
|
1539
|
-
register() {
|
|
1586
|
+
register(windowHref) {
|
|
1540
1587
|
const isPopup = parent.window.opener !== null;
|
|
1541
1588
|
this._isPopup = isPopup;
|
|
1542
1589
|
|
|
@@ -1548,7 +1595,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1548
1595
|
const {
|
|
1549
1596
|
pathname,
|
|
1550
1597
|
search: rawParams
|
|
1551
|
-
} = new URL(window.location.href);
|
|
1598
|
+
} = new URL(windowHref || window.location.href);
|
|
1552
1599
|
let session = this.getWindowTransportSession(rawParams); // provider should always include sid when opening a new window
|
|
1553
1600
|
|
|
1554
1601
|
const isNewWindowSession = !!session.sessionId; // attempt to restore previous session in the case of a redirect or window reload
|
|
@@ -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
|
-
//
|
|
1786
|
+
let message; // there is a difference in the order of the params:
|
|
1787
|
+
// personal_sign: [data, address]
|
|
1788
|
+
// eth_sign: [address, data]
|
|
1741
1789
|
|
|
1742
|
-
if (
|
|
1743
|
-
|
|
1744
|
-
|
|
1790
|
+
if (request.method === 'personal_sign') {
|
|
1791
|
+
const [data, address] = request.params;
|
|
1792
|
+
message = data;
|
|
1745
1793
|
} else {
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
chainId: chainId,
|
|
1749
|
-
message: message
|
|
1750
|
-
});
|
|
1794
|
+
const [address, data] = request.params;
|
|
1795
|
+
message = data;
|
|
1751
1796
|
}
|
|
1752
1797
|
|
|
1753
|
-
if (sig && sig.length > 0) {
|
|
1754
|
-
response.result = sig;
|
|
1755
|
-
} else {
|
|
1756
|
-
// The user has declined the request when value is null
|
|
1757
|
-
throw new Error('declined by user');
|
|
1758
|
-
}
|
|
1759
|
-
|
|
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) {
|
|
@@ -1532,7 +1579,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1532
1579
|
this._init = InitState.NIL;
|
|
1533
1580
|
}
|
|
1534
1581
|
|
|
1535
|
-
register() {
|
|
1582
|
+
register(windowHref) {
|
|
1536
1583
|
const isPopup = parent.window.opener !== null;
|
|
1537
1584
|
this._isPopup = isPopup;
|
|
1538
1585
|
|
|
@@ -1544,7 +1591,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1544
1591
|
const {
|
|
1545
1592
|
pathname,
|
|
1546
1593
|
search: rawParams
|
|
1547
|
-
} = new URL(window.location.href);
|
|
1594
|
+
} = new URL(windowHref || window.location.href);
|
|
1548
1595
|
let session = this.getWindowTransportSession(rawParams); // provider should always include sid when opening a new window
|
|
1549
1596
|
|
|
1550
1597
|
const isNewWindowSession = !!session.sessionId; // attempt to restore previous session in the case of a redirect or window reload
|
|
@@ -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
|
-
//
|
|
1782
|
+
let message; // there is a difference in the order of the params:
|
|
1783
|
+
// personal_sign: [data, address]
|
|
1784
|
+
// eth_sign: [address, data]
|
|
1737
1785
|
|
|
1738
|
-
if (
|
|
1739
|
-
|
|
1740
|
-
|
|
1786
|
+
if (request.method === 'personal_sign') {
|
|
1787
|
+
const [data, address] = request.params;
|
|
1788
|
+
message = data;
|
|
1741
1789
|
} else {
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
chainId: chainId,
|
|
1745
|
-
message: message
|
|
1746
|
-
});
|
|
1790
|
+
const [address, data] = request.params;
|
|
1791
|
+
message = data;
|
|
1747
1792
|
}
|
|
1748
1793
|
|
|
1749
|
-
if (sig && sig.length > 0) {
|
|
1750
|
-
response.result = sig;
|
|
1751
|
-
} else {
|
|
1752
|
-
// The user has declined the request when value is null
|
|
1753
|
-
throw new Error('declined by user');
|
|
1754
|
-
}
|
|
1755
|
-
|
|
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 };
|
|
@@ -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>;
|
|
@@ -5,7 +5,7 @@ export declare class WindowMessageHandler extends BaseWalletTransport {
|
|
|
5
5
|
protected parentWindow: Window;
|
|
6
6
|
private _isPopup;
|
|
7
7
|
constructor(walletRequestHandler: WalletRequestHandler);
|
|
8
|
-
register(): void;
|
|
8
|
+
register(windowHref?: any): void;
|
|
9
9
|
unregister(): void;
|
|
10
10
|
private onWindowEvent;
|
|
11
11
|
sendMessage(message: ProviderMessage<any>): void;
|
|
@@ -2,9 +2,18 @@ import { BigNumberish, BytesLike } from 'ethers';
|
|
|
2
2
|
import { WalletContext } from '@0xsequence/network';
|
|
3
3
|
import { WalletConfig, DecodedSignature } from '@0xsequence/config';
|
|
4
4
|
import { Web3Provider } from './provider';
|
|
5
|
+
import { Signer } from '@0xsequence/wallet';
|
|
5
6
|
export declare const isValidSignature: (address: string, digest: Uint8Array, sig: string, provider: Web3Provider, chainId?: number | undefined, walletContext?: WalletContext | undefined) => Promise<boolean | undefined>;
|
|
6
7
|
export declare const recoverWalletConfig: (address: string, digest: BytesLike, signature: string | DecodedSignature, chainId: BigNumberish, walletContext?: WalletContext | undefined) => Promise<WalletConfig>;
|
|
7
8
|
export declare const isBrowserExtension: () => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Returns the status of a signer's wallet on given chain by checking wallet deployment and config status
|
|
11
|
+
*
|
|
12
|
+
* @param {Signer} signer
|
|
13
|
+
* @param {number} chainId
|
|
14
|
+
* @return {Promise<boolean>} Promise that returns true if the wallet is up to date, false otherwise
|
|
15
|
+
*/
|
|
16
|
+
export declare const isWalletUpToDate: (signer: Signer, chainId: number) => Promise<boolean>;
|
|
8
17
|
export declare class LocalStore<T extends Object = string> {
|
|
9
18
|
def?: T | undefined;
|
|
10
19
|
readonly key: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.2",
|
|
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.2",
|
|
17
|
+
"@0xsequence/auth": "^0.35.2",
|
|
18
|
+
"@0xsequence/config": "^0.35.2",
|
|
19
|
+
"@0xsequence/network": "^0.35.2",
|
|
20
|
+
"@0xsequence/transactions": "^0.35.2",
|
|
21
|
+
"@0xsequence/utils": "^0.35.2",
|
|
22
|
+
"@0xsequence/wallet": "^0.35.2",
|
|
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>
|
|
@@ -22,7 +22,7 @@ export class WindowMessageHandler extends BaseWalletTransport {
|
|
|
22
22
|
this._init = InitState.NIL
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
register() {
|
|
25
|
+
register(windowHref?: any) {
|
|
26
26
|
const isPopup = parent.window.opener !== null
|
|
27
27
|
this._isPopup = isPopup
|
|
28
28
|
if (isPopup !== true) {
|
|
@@ -30,7 +30,7 @@ export class WindowMessageHandler extends BaseWalletTransport {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// record open details (sessionId + default network) from the window url
|
|
33
|
-
const { pathname, search: rawParams } = new URL(window.location.href)
|
|
33
|
+
const { pathname, search: rawParams } = new URL(windowHref || window.location.href)
|
|
34
34
|
|
|
35
35
|
let session: TransportSession | null = this.getWindowTransportSession(rawParams)
|
|
36
36
|
|
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> {
|