@0xsequence/provider 0.34.1 → 0.35.3
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 +119 -40
- package/dist/0xsequence-provider.cjs.prod.js +119 -40
- package/dist/0xsequence-provider.esm.js +120 -42
- 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/transports/window-transport/window-message-handler.d.ts +1 -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/transports/window-transport/window-message-handler.ts +2 -2
- package/src/transports/window-transport/window-message-provider.ts +17 -5
- package/src/utils.ts +47 -6
- package/CHANGELOG.md +0 -1101
|
@@ -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) {
|
|
@@ -1399,8 +1446,20 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
1399
1446
|
} // Open popup window on center of the app window
|
|
1400
1447
|
|
|
1401
1448
|
|
|
1402
|
-
|
|
1403
|
-
|
|
1449
|
+
let windowSize;
|
|
1450
|
+
let windowPos;
|
|
1451
|
+
|
|
1452
|
+
if (isBrowserExtension()) {
|
|
1453
|
+
windowSize = [450, 750];
|
|
1454
|
+
windowPos = [window.screenX, window.screenY]; // windowPos = [
|
|
1455
|
+
// Math.abs(window.screen.width / 2 - windowSize[0] / 2),
|
|
1456
|
+
// Math.abs(window.screen.height / 2 - windowSize[1] / 2)
|
|
1457
|
+
// ]
|
|
1458
|
+
} else {
|
|
1459
|
+
windowSize = [450, 750];
|
|
1460
|
+
windowPos = [Math.abs(window.screenX + window.innerWidth / 2 - windowSize[0] / 2), Math.abs(window.screenY + window.innerHeight / 2 - windowSize[1] / 2)];
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1404
1463
|
const windowFeatures = `toolbar=0,location=0,menubar=0,scrollbars=yes,status=yes` + `,width=${windowSize[0]},height=${windowSize[1]}` + `,left=${windowPos[0]},top=${windowPos[1]}`; // serialize params
|
|
1405
1464
|
|
|
1406
1465
|
walletURL.search = windowSessionParams.toString();
|
|
@@ -1532,7 +1591,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1532
1591
|
this._init = InitState.NIL;
|
|
1533
1592
|
}
|
|
1534
1593
|
|
|
1535
|
-
register() {
|
|
1594
|
+
register(windowHref) {
|
|
1536
1595
|
const isPopup = parent.window.opener !== null;
|
|
1537
1596
|
this._isPopup = isPopup;
|
|
1538
1597
|
|
|
@@ -1544,7 +1603,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1544
1603
|
const {
|
|
1545
1604
|
pathname,
|
|
1546
1605
|
search: rawParams
|
|
1547
|
-
} = new URL(window.location.href);
|
|
1606
|
+
} = new URL(windowHref || window.location.href);
|
|
1548
1607
|
let session = this.getWindowTransportSession(rawParams); // provider should always include sid when opening a new window
|
|
1549
1608
|
|
|
1550
1609
|
const isNewWindowSession = !!session.sessionId; // attempt to restore previous session in the case of a redirect or window reload
|
|
@@ -1729,37 +1788,21 @@ class WalletRequestHandler {
|
|
|
1729
1788
|
}
|
|
1730
1789
|
|
|
1731
1790
|
case 'personal_sign':
|
|
1791
|
+
case 'eth_sign':
|
|
1732
1792
|
{
|
|
1733
1793
|
// note: message from json-rpc input is in hex format
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
//
|
|
1794
|
+
let message; // there is a difference in the order of the params:
|
|
1795
|
+
// personal_sign: [data, address]
|
|
1796
|
+
// eth_sign: [address, data]
|
|
1737
1797
|
|
|
1738
|
-
if (
|
|
1739
|
-
|
|
1740
|
-
|
|
1798
|
+
if (request.method === 'personal_sign') {
|
|
1799
|
+
const [data, address] = request.params;
|
|
1800
|
+
message = data;
|
|
1741
1801
|
} else {
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
chainId: chainId,
|
|
1745
|
-
message: message
|
|
1746
|
-
});
|
|
1802
|
+
const [address, data] = request.params;
|
|
1803
|
+
message = data;
|
|
1747
1804
|
}
|
|
1748
1805
|
|
|
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
1806
|
let sig = ''; // TODO:
|
|
1764
1807
|
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
1765
1808
|
|
|
@@ -1767,11 +1810,14 @@ class WalletRequestHandler {
|
|
|
1767
1810
|
// prompter is null, so we'll sign from here
|
|
1768
1811
|
sig = await signer.signMessage(ethers.utils.arrayify(message), chainId);
|
|
1769
1812
|
} else {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1813
|
+
const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
|
|
1814
|
+
|
|
1815
|
+
if (promptResultForDeployment) {
|
|
1816
|
+
sig = await _this.prompter.promptSignMessage({
|
|
1817
|
+
chainId: chainId,
|
|
1818
|
+
message: message
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1775
1821
|
}
|
|
1776
1822
|
|
|
1777
1823
|
if (sig && sig.length > 0) {
|
|
@@ -1810,11 +1856,14 @@ class WalletRequestHandler {
|
|
|
1810
1856
|
// prompter is null, so we'll sign from here
|
|
1811
1857
|
sig = await signer.signTypedData(typedData.domain, typedData.types, typedData.message, chainId);
|
|
1812
1858
|
} else {
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1859
|
+
const promptResultForDeployment = await _this.handleConfirmWalletDeployPrompt(_this.prompter, signer, chainId);
|
|
1860
|
+
|
|
1861
|
+
if (promptResultForDeployment) {
|
|
1862
|
+
sig = await _this.prompter.promptSignMessage({
|
|
1863
|
+
chainId: chainId,
|
|
1864
|
+
typedData: typedData
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1818
1867
|
}
|
|
1819
1868
|
|
|
1820
1869
|
if (sig && sig.length > 0) {
|
|
@@ -2342,6 +2391,35 @@ class WalletRequestHandler {
|
|
|
2342
2391
|
this.signer = signer;
|
|
2343
2392
|
}
|
|
2344
2393
|
|
|
2394
|
+
async handleConfirmWalletDeployPrompt(prompter, signer, chainId) {
|
|
2395
|
+
// check if wallet is deployed and up to date, if not, prompt user to deploy
|
|
2396
|
+
// if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
|
|
2397
|
+
if (!chainId) {
|
|
2398
|
+
return true;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
const isUpToDate = await isWalletUpToDate(signer, chainId);
|
|
2402
|
+
|
|
2403
|
+
if (isUpToDate) {
|
|
2404
|
+
return true;
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
const promptResult = await prompter.promptConfirmWalletDeploy(chainId); // if client returned true, check again to make sure wallet is deployed and up to date
|
|
2408
|
+
|
|
2409
|
+
if (promptResult) {
|
|
2410
|
+
const isPromptResultCorrect = await isWalletUpToDate(signer, chainId);
|
|
2411
|
+
|
|
2412
|
+
if (!isPromptResultCorrect) {
|
|
2413
|
+
logger.error('WalletRequestHandler: result for promptConfirmWalletDeploy is not correct');
|
|
2414
|
+
return false;
|
|
2415
|
+
} else {
|
|
2416
|
+
return true;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
return false;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2345
2423
|
}
|
|
2346
2424
|
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
2425
|
|
|
@@ -3549,4 +3627,4 @@ const DefaultProviderConfig = {
|
|
|
3549
3627
|
}
|
|
3550
3628
|
};
|
|
3551
3629
|
|
|
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 };
|
|
3630
|
+
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>;
|
|
@@ -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;
|
|
@@ -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.3",
|
|
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.3",
|
|
17
|
+
"@0xsequence/auth": "^0.35.3",
|
|
18
|
+
"@0xsequence/config": "^0.35.3",
|
|
19
|
+
"@0xsequence/network": "^0.35.3",
|
|
20
|
+
"@0xsequence/transactions": "^0.35.3",
|
|
21
|
+
"@0xsequence/utils": "^0.35.3",
|
|
22
|
+
"@0xsequence/wallet": "^0.35.3",
|
|
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
|
|
|
@@ -101,11 +101,23 @@ export class WindowMessageProvider extends BaseProviderTransport {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Open popup window on center of the app window
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
let windowSize: number[]
|
|
105
|
+
let windowPos: number[]
|
|
106
|
+
|
|
107
|
+
if (isBrowserExtension()) {
|
|
108
|
+
windowSize = [450, 750]
|
|
109
|
+
windowPos = [window.screenX, window.screenY]
|
|
110
|
+
// windowPos = [
|
|
111
|
+
// Math.abs(window.screen.width / 2 - windowSize[0] / 2),
|
|
112
|
+
// Math.abs(window.screen.height / 2 - windowSize[1] / 2)
|
|
113
|
+
// ]
|
|
114
|
+
} else {
|
|
115
|
+
windowSize = [450, 750]
|
|
116
|
+
windowPos = [
|
|
117
|
+
Math.abs(window.screenX + window.innerWidth / 2 - windowSize[0] / 2),
|
|
118
|
+
Math.abs(window.screenY + window.innerHeight / 2 - windowSize[1] / 2)
|
|
119
|
+
]
|
|
120
|
+
}
|
|
109
121
|
|
|
110
122
|
const windowFeatures =
|
|
111
123
|
`toolbar=0,location=0,menubar=0,scrollbars=yes,status=yes` +
|
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> {
|