@0xsequence/provider 1.10.15 → 2.0.1
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 +663 -653
- package/dist/0xsequence-provider.cjs.prod.js +663 -653
- package/dist/0xsequence-provider.esm.js +667 -657
- package/dist/declarations/src/client.d.ts +7 -3
- package/dist/declarations/src/provider.d.ts +31 -22
- package/dist/declarations/src/signer.d.ts +15 -14
- package/dist/declarations/src/transports/base-provider-transport.d.ts +6 -2
- package/dist/declarations/src/transports/base-wallet-transport.d.ts +6 -2
- package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +5 -2
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +7 -6
- package/dist/declarations/src/types.d.ts +6 -11
- package/dist/declarations/src/utils/index.d.ts +3 -3
- package/dist/declarations/src/utils.d.ts +7 -7
- package/package.json +12 -12
- package/src/client.ts +41 -51
- package/src/eip191exceptions.ts +2 -2
- package/src/extended.ts +5 -5
- package/src/init.ts +9 -10
- package/src/provider.ts +112 -66
- package/src/signer.ts +38 -43
- package/src/transactions.ts +4 -4
- package/src/transports/base-provider-transport.ts +19 -23
- package/src/transports/base-wallet-transport.ts +22 -13
- package/src/transports/mux-transport/mux-message-provider.ts +5 -6
- package/src/transports/proxy-transport/proxy-message-provider.ts +5 -2
- package/src/transports/unreal-transport/unreal-message-handler.ts +2 -2
- package/src/transports/unreal-transport/unreal-message-provider.ts +2 -2
- package/src/transports/wallet-request-handler.ts +91 -130
- package/src/transports/window-transport/window-message-handler.ts +5 -4
- package/src/transports/window-transport/window-message-provider.ts +4 -4
- package/src/types.ts +8 -11
- package/src/utils/index.ts +4 -4
- package/src/utils.ts +16 -18
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { walletContracts } from '@0xsequence/abi';
|
|
2
|
-
import { commons } from '@0xsequence/core';
|
|
3
|
-
import { ethers
|
|
2
|
+
import { commons, VERSION } from '@0xsequence/core';
|
|
3
|
+
import { ethers } from 'ethers';
|
|
4
4
|
import { EventEmitter2 } from 'eventemitter2';
|
|
5
|
-
import { logger, encodeMessageDigest, encodeTypedDataDigest, sanitizeNumberString, sanitizeHost, sanitizeAlphanumeric, base64EncodeObject, base64DecodeObject } from '@0xsequence/utils';
|
|
6
|
-
import { findSupportedNetwork, ChainId, findNetworkConfig, allNetworks,
|
|
5
|
+
import { logger, encodeMessageDigest, encodeTypedDataDigest, sanitizeNumberString, sanitizeHost, sanitizeAlphanumeric, base64EncodeObject, bigintReplacer, base64DecodeObject, bigintReviver, toHexString } from '@0xsequence/utils';
|
|
6
|
+
import { findSupportedNetwork, ChainId, findNetworkConfig, allNetworks, JsonRpcProvider, loggingProviderMiddleware, exceptionProviderMiddleware, CachedProvider } from '@0xsequence/network';
|
|
7
7
|
import { signAuthorization } from '@0xsequence/auth';
|
|
8
8
|
import { isBrowser, Databeat } from '@databeat/tracker';
|
|
9
9
|
|
|
10
|
-
const PROHIBITED_FUNCTIONS = new Map(['addHook(bytes4,address)', 'clearExtraImageHashes(bytes32[])', 'removeHook(bytes4)', 'setExtraImageHash(bytes32,uint256)', 'updateIPFSRoot(bytes32)', 'updateImageHash(bytes32)', 'updateImageHashAndIPFS(bytes32,bytes32)', 'updateImplementation(address)'].map(signature => [ethers.
|
|
10
|
+
const PROHIBITED_FUNCTIONS = new Map(['addHook(bytes4,address)', 'clearExtraImageHashes(bytes32[])', 'removeHook(bytes4)', 'setExtraImageHash(bytes32,uint256)', 'updateIPFSRoot(bytes32)', 'updateImageHash(bytes32)', 'updateImageHashAndIPFS(bytes32,bytes32)', 'updateImplementation(address)'].map(signature => [ethers.id(signature).slice(0, 10), signature]));
|
|
11
11
|
function validateTransactionRequest(wallet, transaction) {
|
|
12
12
|
const transactions = commons.transaction.fromTransactionish(wallet, transaction);
|
|
13
13
|
const unwound = commons.transaction.unwind(wallet, transactions);
|
|
@@ -16,7 +16,7 @@ function validateTransactionRequest(wallet, transaction) {
|
|
|
16
16
|
function validateTransaction(wallet, transaction) {
|
|
17
17
|
if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
|
|
18
18
|
if (transaction.data) {
|
|
19
|
-
const data = ethers.
|
|
19
|
+
const data = ethers.getBytes(transaction.data);
|
|
20
20
|
if (data.length >= 4 && !isCreateContractCall(data)) {
|
|
21
21
|
throw new Error('self calls are forbidden');
|
|
22
22
|
}
|
|
@@ -26,7 +26,7 @@ function validateTransaction(wallet, transaction) {
|
|
|
26
26
|
throw new Error('delegate calls are forbidden');
|
|
27
27
|
}
|
|
28
28
|
if (transaction.data) {
|
|
29
|
-
const data = ethers.
|
|
29
|
+
const data = ethers.hexlify(transaction.data);
|
|
30
30
|
const selector = data.slice(0, 10);
|
|
31
31
|
const signature = PROHIBITED_FUNCTIONS.get(selector);
|
|
32
32
|
if (signature) {
|
|
@@ -36,7 +36,7 @@ function validateTransaction(wallet, transaction) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
function isCreateContractCall(data) {
|
|
39
|
-
const walletInterface = new ethers.
|
|
39
|
+
const walletInterface = new ethers.Interface(walletContracts.mainModule.abi);
|
|
40
40
|
try {
|
|
41
41
|
walletInterface.decodeFunctionData('createContract', data);
|
|
42
42
|
return true;
|
|
@@ -64,6 +64,8 @@ function isProviderTransport(transport) {
|
|
|
64
64
|
return transport && typeof transport === 'object' && typeof transport.register === 'function' && typeof transport.unregister === 'function' && typeof transport.openWallet === 'function' && typeof transport.closeWallet === 'function' && typeof transport.isOpened === 'function' && typeof transport.isConnected === 'function' && typeof transport.on === 'function';
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
// Older versions of sequence.js will require a JsonRpcResponse result type, but newer versions use raw EIP1193 results
|
|
68
|
+
|
|
67
69
|
// ProviderMessageCallback is used to respond to ProviderMessage requests. The error
|
|
68
70
|
// argument is for exceptions during the execution, and response is the response payload
|
|
69
71
|
// which may contain the result or an error payload from the wallet.
|
|
@@ -121,8 +123,6 @@ const ErrSignedInRequired = new ProviderError('Wallet is not signed in. Connect
|
|
|
121
123
|
|
|
122
124
|
// TODO: lets build some nice error handling tools, prob in /utils ...
|
|
123
125
|
|
|
124
|
-
// This is required by viem, it expects a provider to have an EIP-1193 compliant `request` attribute.
|
|
125
|
-
|
|
126
126
|
const PROVIDER_OPEN_TIMEOUT = 30000; // in ms
|
|
127
127
|
|
|
128
128
|
let _messageIdx = 0;
|
|
@@ -143,42 +143,6 @@ class BaseProviderTransport {
|
|
|
143
143
|
this._sessionId = void 0;
|
|
144
144
|
this._init = void 0;
|
|
145
145
|
this._registered = void 0;
|
|
146
|
-
this.sendAsync = async function (request, callback, chainId) {
|
|
147
|
-
// here, we receive the message from the dapp provider call
|
|
148
|
-
|
|
149
|
-
if (_this.state === OpenState.CLOSED) {
|
|
150
|
-
// flag the wallet to auto-close once user submits input. ie.
|
|
151
|
-
// prompting to sign a message or transaction
|
|
152
|
-
_this.confirmationOnly = true;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// open/focus the wallet.
|
|
156
|
-
// automatically open the wallet when a provider request makes it here.
|
|
157
|
-
//
|
|
158
|
-
// NOTE: if we're not signed in, then the provider will fail, users must first connect+sign in.
|
|
159
|
-
//
|
|
160
|
-
// TODO: how does this behave with a session has expired?
|
|
161
|
-
_this.openWallet(undefined, {
|
|
162
|
-
type: 'jsonRpcRequest',
|
|
163
|
-
method: request.method
|
|
164
|
-
}, chainId);
|
|
165
|
-
|
|
166
|
-
// send message request, await, and then execute callback after receiving the response
|
|
167
|
-
try {
|
|
168
|
-
if (!_this.isOpened()) {
|
|
169
|
-
await _this.waitUntilOpened(); // will throw on timeout
|
|
170
|
-
}
|
|
171
|
-
const response = await _this.sendMessageRequest({
|
|
172
|
-
idx: nextMessageIdx(),
|
|
173
|
-
type: EventType.MESSAGE,
|
|
174
|
-
data: request,
|
|
175
|
-
chainId: chainId
|
|
176
|
-
});
|
|
177
|
-
callback(undefined, response.data);
|
|
178
|
-
} catch (err) {
|
|
179
|
-
callback(err);
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
146
|
// sendMessageRequest sends a ProviderMessageRequest over the wire to the wallet
|
|
183
147
|
this.sendMessageRequest = async function (message) {
|
|
184
148
|
return new Promise((resolve, reject) => {
|
|
@@ -288,6 +252,36 @@ class BaseProviderTransport {
|
|
|
288
252
|
const session = (_this$openPayload2 = this.openPayload) == null ? void 0 : _this$openPayload2.session;
|
|
289
253
|
return this.registered && session !== undefined && !!session.accountAddress && session.accountAddress.length === 42 && !!session.networks && session.networks.length > 0;
|
|
290
254
|
}
|
|
255
|
+
async request(request) {
|
|
256
|
+
if (this.state === OpenState.CLOSED) {
|
|
257
|
+
// flag the wallet to auto-close once user submits input. ie.
|
|
258
|
+
// prompting to sign a message or transaction
|
|
259
|
+
this.confirmationOnly = true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// open/focus the wallet.
|
|
263
|
+
// automatically open the wallet when a provider request makes it here.
|
|
264
|
+
//
|
|
265
|
+
// NOTE: if we're not signed in, then the provider will fail, users must first connect+sign in.
|
|
266
|
+
//
|
|
267
|
+
// TODO: how does this behave with a session has expired?
|
|
268
|
+
this.openWallet(undefined, {
|
|
269
|
+
type: 'jsonRpcRequest',
|
|
270
|
+
method: request.method
|
|
271
|
+
}, request.chainId);
|
|
272
|
+
if (!this.isOpened()) {
|
|
273
|
+
await this.waitUntilOpened(); // will throw on timeout
|
|
274
|
+
}
|
|
275
|
+
const response = await this.sendMessageRequest({
|
|
276
|
+
idx: nextMessageIdx(),
|
|
277
|
+
type: EventType.MESSAGE,
|
|
278
|
+
data: request,
|
|
279
|
+
chainId: request.chainId,
|
|
280
|
+
clientVersion: VERSION
|
|
281
|
+
});
|
|
282
|
+
return response.data;
|
|
283
|
+
}
|
|
284
|
+
|
|
291
285
|
// handleMessage will handle message received from the remote wallet
|
|
292
286
|
handleMessage(message) {
|
|
293
287
|
var _this2 = this;
|
|
@@ -309,7 +303,8 @@ class BaseProviderTransport {
|
|
|
309
303
|
data: {
|
|
310
304
|
sessionId: this._sessionId,
|
|
311
305
|
nonce: nonce
|
|
312
|
-
}
|
|
306
|
+
},
|
|
307
|
+
clientVersion: VERSION
|
|
313
308
|
});
|
|
314
309
|
}
|
|
315
310
|
if (this._init !== InitState.OK) {
|
|
@@ -394,7 +389,7 @@ class BaseProviderTransport {
|
|
|
394
389
|
};
|
|
395
390
|
if (message.data && message.data.length > 0) {
|
|
396
391
|
this.accountsChangedPayload = {
|
|
397
|
-
accounts: [ethers.
|
|
392
|
+
accounts: [ethers.getAddress(message.data[0])],
|
|
398
393
|
origin: message.origin
|
|
399
394
|
};
|
|
400
395
|
this.events.emit('accountsChanged', this.accountsChangedPayload.accounts, this.accountsChangedPayload.origin);
|
|
@@ -499,7 +494,7 @@ const EIP_191_PREFIX_EXCEPTIONS = [
|
|
|
499
494
|
const DCL_REGEX = /^Decentraland Login\nEphemeral address: 0x[a-fA-F0-9]{40}\nExpiration: (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$/;
|
|
500
495
|
function isDecentralandLoginMessage(bytes) {
|
|
501
496
|
try {
|
|
502
|
-
const stringified = ethers.
|
|
497
|
+
const stringified = ethers.toUtf8String(bytes);
|
|
503
498
|
return DCL_REGEX.test(stringified);
|
|
504
499
|
} catch (_unused) {
|
|
505
500
|
return false;
|
|
@@ -509,7 +504,7 @@ function isDecentralandLoginMessage(bytes) {
|
|
|
509
504
|
// try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
|
|
510
505
|
// see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
|
|
511
506
|
function isZeroExV3Order(bytes) {
|
|
512
|
-
const abi = new ethers.
|
|
507
|
+
const abi = new ethers.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
513
508
|
try {
|
|
514
509
|
abi.decodeFunctionData('OrderWithHash', bytes);
|
|
515
510
|
return true;
|
|
@@ -591,19 +586,19 @@ const ZeroXV3EIP1271OrderWithHashAbi = [{
|
|
|
591
586
|
type: 'function'
|
|
592
587
|
}];
|
|
593
588
|
|
|
594
|
-
const eip191prefix = ethers.
|
|
589
|
+
const eip191prefix = ethers.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
595
590
|
const messageToBytes = message => {
|
|
596
|
-
if (ethers.
|
|
597
|
-
return ethers.
|
|
591
|
+
if (ethers.isBytesLike(message)) {
|
|
592
|
+
return ethers.getBytes(message);
|
|
598
593
|
}
|
|
599
|
-
return ethers.
|
|
594
|
+
return ethers.toUtf8Bytes(message);
|
|
600
595
|
};
|
|
601
596
|
const prefixEIP191Message = message => {
|
|
602
597
|
const messageBytes = messageToBytes(message);
|
|
603
598
|
if (messageIsExemptFromEIP191Prefix(messageBytes)) {
|
|
604
599
|
return messageBytes;
|
|
605
600
|
} else {
|
|
606
|
-
return ethers.
|
|
601
|
+
return ethers.getBytes(ethers.concat([eip191prefix, ethers.toUtf8Bytes(String(messageBytes.length)), messageBytes]));
|
|
607
602
|
}
|
|
608
603
|
};
|
|
609
604
|
const trimEIP191Prefix = prefixedMessage => {
|
|
@@ -628,9 +623,9 @@ const trimEIP191Prefix = prefixedMessage => {
|
|
|
628
623
|
let prefixCharLenght;
|
|
629
624
|
let prefixAsNumber;
|
|
630
625
|
try {
|
|
631
|
-
prefixAsNumber = Number(ethers.
|
|
626
|
+
prefixAsNumber = Number(ethers.toUtf8String(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
632
627
|
} catch (_unused) {
|
|
633
|
-
prefixAsNumber = Number(ethers.
|
|
628
|
+
prefixAsNumber = Number(ethers.hexlify(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
634
629
|
}
|
|
635
630
|
if (prefixAsNumber > ethereumSignedMessagePartSlicedArray.length || !Number.isInteger(prefixAsNumber)) {
|
|
636
631
|
prefixCharLenght = maxPrefixCharLength - 1;
|
|
@@ -745,9 +740,9 @@ function useBestStore() {
|
|
|
745
740
|
async function resolveArrayProperties(object) {
|
|
746
741
|
if (Array.isArray(object)) {
|
|
747
742
|
// T must include array type
|
|
748
|
-
return Promise.all(object.map(o => ethers.
|
|
743
|
+
return Promise.all(object.map(o => ethers.resolveProperties(o)));
|
|
749
744
|
}
|
|
750
|
-
return ethers.
|
|
745
|
+
return ethers.resolveProperties(object);
|
|
751
746
|
}
|
|
752
747
|
|
|
753
748
|
const TRANSPORT_SESSION_LS_KEY = '@sequence.transportSession';
|
|
@@ -764,9 +759,6 @@ class BaseWalletTransport {
|
|
|
764
759
|
// will auto-detect and set this value if it can. This is determined
|
|
765
760
|
// as the parent app/window which opened the wallet.
|
|
766
761
|
this.appOrigin = void 0;
|
|
767
|
-
this.sendAsync = async function (request, callback, chainId) {
|
|
768
|
-
throw new Error('abstract method');
|
|
769
|
-
};
|
|
770
762
|
this.handleMessage = async function (message) {
|
|
771
763
|
const request = message;
|
|
772
764
|
|
|
@@ -1002,7 +994,7 @@ class BaseWalletTransport {
|
|
|
1002
994
|
if (!networks || networks.length === 0) {
|
|
1003
995
|
this.notifyChainChanged('0x0');
|
|
1004
996
|
} else {
|
|
1005
|
-
this.notifyChainChanged(ethers.
|
|
997
|
+
this.notifyChainChanged(ethers.toQuantity(networks.find(network => network.isDefaultChain).chainId));
|
|
1006
998
|
}
|
|
1007
999
|
});
|
|
1008
1000
|
this.walletRequestHandler.on('chainChanged', (chainIdHex, origin) => {
|
|
@@ -1026,6 +1018,9 @@ class BaseWalletTransport {
|
|
|
1026
1018
|
unregister() {
|
|
1027
1019
|
throw new Error('abstract method');
|
|
1028
1020
|
}
|
|
1021
|
+
request(request) {
|
|
1022
|
+
throw new Error('abstract method');
|
|
1023
|
+
}
|
|
1029
1024
|
sendMessage(message) {
|
|
1030
1025
|
throw new Error('abstract method');
|
|
1031
1026
|
}
|
|
@@ -1044,7 +1039,8 @@ class BaseWalletTransport {
|
|
|
1044
1039
|
sessionId,
|
|
1045
1040
|
session,
|
|
1046
1041
|
error
|
|
1047
|
-
}
|
|
1042
|
+
},
|
|
1043
|
+
clientVersion: VERSION
|
|
1048
1044
|
});
|
|
1049
1045
|
}
|
|
1050
1046
|
notifyClose(error) {
|
|
@@ -1053,14 +1049,16 @@ class BaseWalletTransport {
|
|
|
1053
1049
|
type: EventType.CLOSE,
|
|
1054
1050
|
data: error ? {
|
|
1055
1051
|
error
|
|
1056
|
-
} : null
|
|
1052
|
+
} : null,
|
|
1053
|
+
clientVersion: VERSION
|
|
1057
1054
|
});
|
|
1058
1055
|
}
|
|
1059
1056
|
notifyConnect(connectDetails) {
|
|
1060
1057
|
this.sendMessage({
|
|
1061
1058
|
idx: -1,
|
|
1062
1059
|
type: EventType.CONNECT,
|
|
1063
|
-
data: connectDetails
|
|
1060
|
+
data: connectDetails,
|
|
1061
|
+
clientVersion: VERSION
|
|
1064
1062
|
});
|
|
1065
1063
|
}
|
|
1066
1064
|
notifyDisconnect(error, origin) {
|
|
@@ -1070,7 +1068,8 @@ class BaseWalletTransport {
|
|
|
1070
1068
|
data: error ? {
|
|
1071
1069
|
error
|
|
1072
1070
|
} : null,
|
|
1073
|
-
origin
|
|
1071
|
+
origin,
|
|
1072
|
+
clientVersion: VERSION
|
|
1074
1073
|
});
|
|
1075
1074
|
}
|
|
1076
1075
|
notifyAccountsChanged(accounts, origin) {
|
|
@@ -1078,7 +1077,8 @@ class BaseWalletTransport {
|
|
|
1078
1077
|
idx: -1,
|
|
1079
1078
|
type: EventType.ACCOUNTS_CHANGED,
|
|
1080
1079
|
data: accounts,
|
|
1081
|
-
origin
|
|
1080
|
+
origin,
|
|
1081
|
+
clientVersion: VERSION
|
|
1082
1082
|
});
|
|
1083
1083
|
}
|
|
1084
1084
|
notifyChainChanged(chainIdHex, origin) {
|
|
@@ -1086,21 +1086,24 @@ class BaseWalletTransport {
|
|
|
1086
1086
|
idx: -1,
|
|
1087
1087
|
type: EventType.CHAIN_CHANGED,
|
|
1088
1088
|
data: chainIdHex,
|
|
1089
|
-
origin
|
|
1089
|
+
origin,
|
|
1090
|
+
clientVersion: VERSION
|
|
1090
1091
|
});
|
|
1091
1092
|
}
|
|
1092
1093
|
notifyNetworks(networks) {
|
|
1093
1094
|
this.sendMessage({
|
|
1094
1095
|
idx: -1,
|
|
1095
1096
|
type: EventType.NETWORKS,
|
|
1096
|
-
data: networks
|
|
1097
|
+
data: networks,
|
|
1098
|
+
clientVersion: VERSION
|
|
1097
1099
|
});
|
|
1098
1100
|
}
|
|
1099
1101
|
notifyWalletContext(walletContext) {
|
|
1100
1102
|
this.sendMessage({
|
|
1101
1103
|
idx: -1,
|
|
1102
1104
|
type: EventType.WALLET_CONTEXT,
|
|
1103
|
-
data: walletContext
|
|
1105
|
+
data: walletContext,
|
|
1106
|
+
clientVersion: VERSION
|
|
1104
1107
|
});
|
|
1105
1108
|
}
|
|
1106
1109
|
isValidInitAck(message) {
|
|
@@ -1171,7 +1174,8 @@ class BaseWalletTransport {
|
|
|
1171
1174
|
type: EventType.INIT,
|
|
1172
1175
|
data: {
|
|
1173
1176
|
nonce: this._initNonce
|
|
1174
|
-
}
|
|
1177
|
+
},
|
|
1178
|
+
clientVersion: VERSION
|
|
1175
1179
|
});
|
|
1176
1180
|
this._init = InitState.SENT_NONCE;
|
|
1177
1181
|
|
|
@@ -1270,7 +1274,8 @@ class ProxyMessageProvider extends BaseProviderTransport {
|
|
|
1270
1274
|
intent,
|
|
1271
1275
|
networkId,
|
|
1272
1276
|
sessionId
|
|
1273
|
-
}
|
|
1277
|
+
},
|
|
1278
|
+
clientVersion: VERSION
|
|
1274
1279
|
});
|
|
1275
1280
|
}
|
|
1276
1281
|
};
|
|
@@ -1288,7 +1293,8 @@ class ProxyMessageProvider extends BaseProviderTransport {
|
|
|
1288
1293
|
this.sendMessage({
|
|
1289
1294
|
idx: -1,
|
|
1290
1295
|
type: EventType.CLOSE,
|
|
1291
|
-
data: null
|
|
1296
|
+
data: null,
|
|
1297
|
+
clientVersion: VERSION
|
|
1292
1298
|
});
|
|
1293
1299
|
this.close();
|
|
1294
1300
|
}
|
|
@@ -1451,7 +1457,7 @@ class UnrealMessageProvider extends BaseProviderTransport {
|
|
|
1451
1457
|
// all lowercase is an annoying limitation of Unreal CEF BindUObject
|
|
1452
1458
|
sendMessage(message) {
|
|
1453
1459
|
var _window$ue3;
|
|
1454
|
-
const postedMessage = typeof message !== 'string' ? JSON.stringify(message) : message;
|
|
1460
|
+
const postedMessage = typeof message !== 'string' ? JSON.stringify(message, bigintReplacer) : message;
|
|
1455
1461
|
console.log('Sending message to wallet:', postedMessage);
|
|
1456
1462
|
(_window$ue3 = window.ue) == null || (_window$ue3 = _window$ue3.sequencewallettransport) == null || _window$ue3.sendmessagetowallet(postedMessage);
|
|
1457
1463
|
}
|
|
@@ -1550,7 +1556,7 @@ class UnrealMessageHandler extends BaseWalletTransport {
|
|
|
1550
1556
|
return;
|
|
1551
1557
|
}
|
|
1552
1558
|
// prepare payload
|
|
1553
|
-
const payload = JSON.stringify(message);
|
|
1559
|
+
const payload = JSON.stringify(message, bigintReplacer);
|
|
1554
1560
|
|
|
1555
1561
|
// post-message to app.
|
|
1556
1562
|
(_window$ue3 = window.ue) == null || (_window$ue3 = _window$ue3.sequencewallettransport) == null || _window$ue3.sendmessagetosequencejs(payload);
|
|
@@ -1825,7 +1831,7 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
1825
1831
|
}
|
|
1826
1832
|
let message;
|
|
1827
1833
|
try {
|
|
1828
|
-
message = JSON.parse(event.data);
|
|
1834
|
+
message = JSON.parse(event.data, bigintReviver);
|
|
1829
1835
|
} catch (err) {
|
|
1830
1836
|
// event is not a ProviderMessage JSON object, skip
|
|
1831
1837
|
return;
|
|
@@ -1849,7 +1855,7 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
1849
1855
|
logger.warn('WindowMessageProvider: sendMessage failed as walletWindow is unavailable');
|
|
1850
1856
|
return;
|
|
1851
1857
|
}
|
|
1852
|
-
const postedMessage = typeof message !== 'string' ? JSON.stringify(message) : message;
|
|
1858
|
+
const postedMessage = typeof message !== 'string' ? JSON.stringify(message, bigintReplacer) : message;
|
|
1853
1859
|
this.walletWindow.postMessage(postedMessage, this.walletURL.origin);
|
|
1854
1860
|
}
|
|
1855
1861
|
}
|
|
@@ -1876,7 +1882,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1876
1882
|
// Wallet always expects json-rpc request messages from a dapp
|
|
1877
1883
|
let request;
|
|
1878
1884
|
try {
|
|
1879
|
-
request = JSON.parse(event.data);
|
|
1885
|
+
request = JSON.parse(event.data, bigintReviver);
|
|
1880
1886
|
} catch (err) {
|
|
1881
1887
|
// event is not a ProviderMessage JSON object, skip
|
|
1882
1888
|
return;
|
|
@@ -1915,7 +1921,6 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1915
1921
|
|
|
1916
1922
|
// record open details (sessionId + default network) from the window url
|
|
1917
1923
|
const {
|
|
1918
|
-
pathname,
|
|
1919
1924
|
search: rawParams
|
|
1920
1925
|
} = new URL(windowHref || window.location.href);
|
|
1921
1926
|
let session = this.getWindowTransportSession(rawParams);
|
|
@@ -1967,7 +1972,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1967
1972
|
// postMessage sends message to the dapp window
|
|
1968
1973
|
sendMessage(message) {
|
|
1969
1974
|
// prepare payload
|
|
1970
|
-
const payload = JSON.stringify(message);
|
|
1975
|
+
const payload = JSON.stringify(message, bigintReplacer);
|
|
1971
1976
|
|
|
1972
1977
|
// post-message to app.
|
|
1973
1978
|
// only for init requests, we send to '*' origin
|
|
@@ -2049,13 +2054,6 @@ class MuxMessageProvider {
|
|
|
2049
2054
|
}
|
|
2050
2055
|
this.messageProviders.forEach(m => m.openWallet(path, intent, networkId));
|
|
2051
2056
|
};
|
|
2052
|
-
this.sendAsync = async function (request, callback, chainId) {
|
|
2053
|
-
if (_this.provider) {
|
|
2054
|
-
_this.provider.sendAsync(request, callback, chainId);
|
|
2055
|
-
return;
|
|
2056
|
-
}
|
|
2057
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
2058
|
-
};
|
|
2059
2057
|
this.sendMessageRequest = async function (message) {
|
|
2060
2058
|
if (_this.provider) {
|
|
2061
2059
|
return _this.provider.sendMessageRequest(message);
|
|
@@ -2152,6 +2150,12 @@ class MuxMessageProvider {
|
|
|
2152
2150
|
}
|
|
2153
2151
|
return true;
|
|
2154
2152
|
}
|
|
2153
|
+
request(request) {
|
|
2154
|
+
if (!this.provider) {
|
|
2155
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
2156
|
+
}
|
|
2157
|
+
return this.provider.request(request);
|
|
2158
|
+
}
|
|
2155
2159
|
sendMessage(message) {
|
|
2156
2160
|
if (!message.idx || message.idx <= 0) {
|
|
2157
2161
|
throw new Error('message idx is empty');
|
|
@@ -2186,7 +2190,7 @@ function fromExtended(transaction) {
|
|
|
2186
2190
|
|
|
2187
2191
|
const SIGNER_READY_TIMEOUT = 10000;
|
|
2188
2192
|
class WalletRequestHandler {
|
|
2189
|
-
constructor(
|
|
2193
|
+
constructor(account, prompter, networks) {
|
|
2190
2194
|
var _this = this;
|
|
2191
2195
|
// signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
|
|
2192
2196
|
// value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
|
|
@@ -2219,417 +2223,6 @@ class WalletRequestHandler {
|
|
|
2219
2223
|
}
|
|
2220
2224
|
return promptConnectDetails;
|
|
2221
2225
|
};
|
|
2222
|
-
// sendAsync implements the JsonRpcHandler interface for sending JsonRpcRequests to the wallet
|
|
2223
|
-
this.sendAsync = async function (request, callback, chainId) {
|
|
2224
|
-
const response = {
|
|
2225
|
-
jsonrpc: '2.0',
|
|
2226
|
-
id: request.id,
|
|
2227
|
-
result: null
|
|
2228
|
-
};
|
|
2229
|
-
await _this.getAccount();
|
|
2230
|
-
try {
|
|
2231
|
-
var _this$account;
|
|
2232
|
-
// only allow public json rpc method to the provider when user is not logged in, aka signer is not set
|
|
2233
|
-
if ((!_this.account || _this.account === null) && !permittedJsonRpcMethods.includes(request.method)) {
|
|
2234
|
-
// throw new Error(`not logged in. ${request.method} is unavailable`)
|
|
2235
|
-
throw ErrSignedInRequired;
|
|
2236
|
-
}
|
|
2237
|
-
|
|
2238
|
-
// wallet account
|
|
2239
|
-
const account = _this.account;
|
|
2240
|
-
if (!account) throw new Error('WalletRequestHandler: wallet account is not configured');
|
|
2241
|
-
|
|
2242
|
-
// fetch the provider for the specific chain, or undefined will select defaultChain
|
|
2243
|
-
const provider = (_this$account = _this.account) == null ? void 0 : _this$account.providerFor(chainId != null ? chainId : _this.defaultChainId());
|
|
2244
|
-
if (!provider) throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${chainId}`);
|
|
2245
|
-
const jsonRpcProvider = provider instanceof ethers.providers.JsonRpcProvider ? provider : undefined;
|
|
2246
|
-
switch (request.method) {
|
|
2247
|
-
case 'net_version':
|
|
2248
|
-
{
|
|
2249
|
-
if (!jsonRpcProvider) {
|
|
2250
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2251
|
-
}
|
|
2252
|
-
const result = await jsonRpcProvider.send('net_version', []);
|
|
2253
|
-
response.result = result;
|
|
2254
|
-
break;
|
|
2255
|
-
}
|
|
2256
|
-
case 'eth_chainId':
|
|
2257
|
-
{
|
|
2258
|
-
if (!jsonRpcProvider) {
|
|
2259
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2260
|
-
}
|
|
2261
|
-
const result = await jsonRpcProvider.send('eth_chainId', []);
|
|
2262
|
-
response.result = result;
|
|
2263
|
-
break;
|
|
2264
|
-
}
|
|
2265
|
-
case 'eth_accounts':
|
|
2266
|
-
{
|
|
2267
|
-
const walletAddress = account.address;
|
|
2268
|
-
response.result = [walletAddress];
|
|
2269
|
-
break;
|
|
2270
|
-
}
|
|
2271
|
-
case 'eth_getBalance':
|
|
2272
|
-
{
|
|
2273
|
-
const [accountAddress, blockTag] = request.params;
|
|
2274
|
-
const walletBalance = await provider.getBalance(accountAddress, blockTag);
|
|
2275
|
-
response.result = walletBalance.toHexString();
|
|
2276
|
-
break;
|
|
2277
|
-
}
|
|
2278
|
-
case 'sequence_sign':
|
|
2279
|
-
case 'personal_sign':
|
|
2280
|
-
case 'eth_sign':
|
|
2281
|
-
{
|
|
2282
|
-
// note: message from json-rpc input is in hex format
|
|
2283
|
-
let message;
|
|
2284
|
-
|
|
2285
|
-
// there is a difference in the order of the params:
|
|
2286
|
-
// sequence_sign, personal_sign: [data, address]
|
|
2287
|
-
// eth_sign: [address, data]
|
|
2288
|
-
switch (request.method) {
|
|
2289
|
-
case 'sequence_sign':
|
|
2290
|
-
case 'personal_sign':
|
|
2291
|
-
{
|
|
2292
|
-
const [data, _address] = request.params;
|
|
2293
|
-
message = data;
|
|
2294
|
-
break;
|
|
2295
|
-
}
|
|
2296
|
-
case 'eth_sign':
|
|
2297
|
-
{
|
|
2298
|
-
const [_address, data] = request.params;
|
|
2299
|
-
message = data;
|
|
2300
|
-
break;
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
let sig = '';
|
|
2304
|
-
|
|
2305
|
-
// Message must be prefixed with "\x19Ethereum Signed Message:\n"
|
|
2306
|
-
// as defined by EIP-191
|
|
2307
|
-
const prefixedMessage = prefixEIP191Message(message);
|
|
2308
|
-
|
|
2309
|
-
// TODO:
|
|
2310
|
-
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
2311
|
-
const sequenceVerified = request.method === 'sequence_sign';
|
|
2312
|
-
if (_this.prompter === null) {
|
|
2313
|
-
// prompter is null, so we'll sign from here
|
|
2314
|
-
sig = await account.signMessage(prefixedMessage, chainId != null ? chainId : _this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2315
|
-
} else {
|
|
2316
|
-
sig = await _this.prompter.promptSignMessage({
|
|
2317
|
-
chainId: chainId,
|
|
2318
|
-
message: prefixedMessage,
|
|
2319
|
-
eip6492: sequenceVerified
|
|
2320
|
-
}, _this.connectOptions);
|
|
2321
|
-
}
|
|
2322
|
-
if (sig && sig.length > 0) {
|
|
2323
|
-
response.result = sig;
|
|
2324
|
-
} else {
|
|
2325
|
-
// The user has declined the request when value is null
|
|
2326
|
-
throw new Error('declined by user');
|
|
2327
|
-
}
|
|
2328
|
-
break;
|
|
2329
|
-
}
|
|
2330
|
-
case 'sequence_signTypedData_v4':
|
|
2331
|
-
case 'eth_signTypedData':
|
|
2332
|
-
case 'eth_signTypedData_v4':
|
|
2333
|
-
{
|
|
2334
|
-
// note: signingAddress from json-rpc input is in hex format, and typedDataObject
|
|
2335
|
-
// should be an object, but in some instances may be double string encoded
|
|
2336
|
-
const [signingAddress, typedDataObject] = request.params;
|
|
2337
|
-
let typedData = undefined;
|
|
2338
|
-
if (typeof typedDataObject === 'string') {
|
|
2339
|
-
try {
|
|
2340
|
-
typedData = JSON.parse(typedDataObject);
|
|
2341
|
-
} catch (e) {
|
|
2342
|
-
console.warn('walletRequestHandler: error parsing typedData', e);
|
|
2343
|
-
}
|
|
2344
|
-
} else {
|
|
2345
|
-
typedData = typedDataObject;
|
|
2346
|
-
}
|
|
2347
|
-
if (!typedData || !typedData.domain || !typedData.types || !typedData.message) {
|
|
2348
|
-
throw new Error('invalid typedData object');
|
|
2349
|
-
}
|
|
2350
|
-
let sig = '';
|
|
2351
|
-
const sequenceVerified = request.method === 'sequence_signTypedData_v4';
|
|
2352
|
-
if (_this.prompter === null) {
|
|
2353
|
-
// prompter is null, so we'll sign from here
|
|
2354
|
-
sig = await account.signTypedData(typedData.domain, typedData.types, typedData.message, chainId != null ? chainId : _this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2355
|
-
} else {
|
|
2356
|
-
sig = await _this.prompter.promptSignMessage({
|
|
2357
|
-
chainId: chainId,
|
|
2358
|
-
typedData: typedData,
|
|
2359
|
-
eip6492: sequenceVerified
|
|
2360
|
-
}, _this.connectOptions);
|
|
2361
|
-
}
|
|
2362
|
-
if (sig && sig.length > 0) {
|
|
2363
|
-
response.result = sig;
|
|
2364
|
-
} else {
|
|
2365
|
-
// The user has declined the request when value is null
|
|
2366
|
-
throw new Error('declined by user');
|
|
2367
|
-
}
|
|
2368
|
-
break;
|
|
2369
|
-
}
|
|
2370
|
-
case 'eth_sendTransaction':
|
|
2371
|
-
{
|
|
2372
|
-
// https://eth.wiki/json-rpc/API#eth_sendtransaction
|
|
2373
|
-
const transactionParams = fromExtended(request.params[0]).map(tx => {
|
|
2374
|
-
// eth_sendTransaction uses 'gas'
|
|
2375
|
-
// ethers and sequence use 'gasLimit'
|
|
2376
|
-
if ('gas' in tx && tx.gasLimit === undefined) {
|
|
2377
|
-
tx.gasLimit = tx.gas;
|
|
2378
|
-
delete tx.gas;
|
|
2379
|
-
}
|
|
2380
|
-
return tx;
|
|
2381
|
-
});
|
|
2382
|
-
validateTransactionRequest(account.address, transactionParams);
|
|
2383
|
-
let txnHash = '';
|
|
2384
|
-
if (_this.prompter === null) {
|
|
2385
|
-
var _txnResponse$hash;
|
|
2386
|
-
// prompter is null, so we'll send from here
|
|
2387
|
-
const txnResponse = await account.sendTransaction(transactionParams, chainId != null ? chainId : _this.defaultChainId());
|
|
2388
|
-
txnHash = (_txnResponse$hash = txnResponse == null ? void 0 : txnResponse.hash) != null ? _txnResponse$hash : '';
|
|
2389
|
-
} else {
|
|
2390
|
-
// prompt user to provide the response
|
|
2391
|
-
txnHash = await _this.prompter.promptSendTransaction(transactionParams, chainId, _this.connectOptions);
|
|
2392
|
-
}
|
|
2393
|
-
if (txnHash) {
|
|
2394
|
-
response.result = txnHash;
|
|
2395
|
-
} else {
|
|
2396
|
-
// The user has declined the request when value is null
|
|
2397
|
-
throw new Error('declined by user');
|
|
2398
|
-
}
|
|
2399
|
-
break;
|
|
2400
|
-
}
|
|
2401
|
-
case 'eth_signTransaction':
|
|
2402
|
-
{
|
|
2403
|
-
// https://eth.wiki/json-rpc/API#eth_signTransaction
|
|
2404
|
-
const [transaction] = request.params;
|
|
2405
|
-
const sender = ethers.utils.getAddress(transaction.from);
|
|
2406
|
-
if (sender !== account.address) {
|
|
2407
|
-
throw new Error('sender address does not match wallet');
|
|
2408
|
-
}
|
|
2409
|
-
validateTransactionRequest(account.address, transaction);
|
|
2410
|
-
if (_this.prompter === null) {
|
|
2411
|
-
// The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
|
|
2412
|
-
// this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
|
|
2413
|
-
//
|
|
2414
|
-
// TODO: verify serializing / transporting the SignedTransaction object works as expected, most likely however
|
|
2415
|
-
// we will want to resolveProperties the big number values to hex strings
|
|
2416
|
-
response.result = await account.signTransactions(transaction, chainId != null ? chainId : _this.defaultChainId());
|
|
2417
|
-
} else {
|
|
2418
|
-
response.result = await _this.prompter.promptSignTransaction(transaction, chainId, _this.connectOptions);
|
|
2419
|
-
}
|
|
2420
|
-
break;
|
|
2421
|
-
}
|
|
2422
|
-
case 'eth_sendRawTransaction':
|
|
2423
|
-
{
|
|
2424
|
-
// NOTE: we're not using a prompter here as the transaction is already signed
|
|
2425
|
-
// and would have prompted the user upon signing.
|
|
2426
|
-
|
|
2427
|
-
// https://eth.wiki/json-rpc/API#eth_sendRawTransaction
|
|
2428
|
-
if (commons.transaction.isSignedTransactionBundle(request.params[0])) {
|
|
2429
|
-
const txChainId = BigNumber.from(request.params[0].chainId).toNumber();
|
|
2430
|
-
const tx = await account.relayer(txChainId).relay(request.params[0]);
|
|
2431
|
-
response.result = tx.hash;
|
|
2432
|
-
} else {
|
|
2433
|
-
const tx = await provider.sendTransaction(request.params[0]);
|
|
2434
|
-
response.result = tx.hash;
|
|
2435
|
-
}
|
|
2436
|
-
break;
|
|
2437
|
-
}
|
|
2438
|
-
case 'eth_getTransactionCount':
|
|
2439
|
-
{
|
|
2440
|
-
const address = ethers.utils.getAddress(request.params[0]);
|
|
2441
|
-
const tag = request.params[1];
|
|
2442
|
-
|
|
2443
|
-
// TODO: Maybe we should fetch this data from the relayer or from the reader
|
|
2444
|
-
// but for now we keep it simple and just use the provider
|
|
2445
|
-
|
|
2446
|
-
const count = await provider.getTransactionCount(address, tag);
|
|
2447
|
-
response.result = ethers.BigNumber.from(count).toHexString();
|
|
2448
|
-
break;
|
|
2449
|
-
}
|
|
2450
|
-
case 'eth_blockNumber':
|
|
2451
|
-
{
|
|
2452
|
-
response.result = await provider.getBlockNumber();
|
|
2453
|
-
break;
|
|
2454
|
-
}
|
|
2455
|
-
case 'eth_getBlockByNumber':
|
|
2456
|
-
{
|
|
2457
|
-
response.result = await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2458
|
-
break;
|
|
2459
|
-
}
|
|
2460
|
-
case 'eth_getBlockByHash':
|
|
2461
|
-
{
|
|
2462
|
-
response.result = await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2463
|
-
break;
|
|
2464
|
-
}
|
|
2465
|
-
case 'eth_getTransactionByHash':
|
|
2466
|
-
{
|
|
2467
|
-
response.result = await provider.getTransaction(request.params[0]);
|
|
2468
|
-
break;
|
|
2469
|
-
}
|
|
2470
|
-
case 'eth_call':
|
|
2471
|
-
{
|
|
2472
|
-
const [transactionObject, blockTag] = request.params;
|
|
2473
|
-
response.result = await provider.call(transactionObject, blockTag);
|
|
2474
|
-
break;
|
|
2475
|
-
}
|
|
2476
|
-
case 'eth_getCode':
|
|
2477
|
-
{
|
|
2478
|
-
const [contractAddress, blockTag] = request.params;
|
|
2479
|
-
response.result = await provider.getCode(contractAddress, blockTag);
|
|
2480
|
-
break;
|
|
2481
|
-
}
|
|
2482
|
-
case 'eth_estimateGas':
|
|
2483
|
-
{
|
|
2484
|
-
const [transactionObject] = request.params;
|
|
2485
|
-
response.result = await provider.estimateGas(transactionObject);
|
|
2486
|
-
break;
|
|
2487
|
-
}
|
|
2488
|
-
case 'eth_gasPrice':
|
|
2489
|
-
{
|
|
2490
|
-
const gasPrice = await provider.getGasPrice();
|
|
2491
|
-
response.result = gasPrice.toHexString();
|
|
2492
|
-
break;
|
|
2493
|
-
}
|
|
2494
|
-
case 'wallet_switchEthereumChain':
|
|
2495
|
-
{
|
|
2496
|
-
const [switchParams] = request.params;
|
|
2497
|
-
if (!switchParams.chainId || switchParams.chainId.length === 0) {
|
|
2498
|
-
throw new Error('invalid chainId');
|
|
2499
|
-
}
|
|
2500
|
-
const _chainId = ethers.BigNumber.from(switchParams.chainId);
|
|
2501
|
-
_this.setDefaultChainId(_chainId.toNumber());
|
|
2502
|
-
response.result = null; // success
|
|
2503
|
-
break;
|
|
2504
|
-
}
|
|
2505
|
-
|
|
2506
|
-
// smart wallet method
|
|
2507
|
-
case 'sequence_getWalletContext':
|
|
2508
|
-
{
|
|
2509
|
-
response.result = account.contexts;
|
|
2510
|
-
break;
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
|
-
// smart wallet method
|
|
2514
|
-
case 'sequence_getWalletConfig':
|
|
2515
|
-
{
|
|
2516
|
-
const [_chainId2] = request.params;
|
|
2517
|
-
if (_chainId2) {
|
|
2518
|
-
response.result = [(await account.status(_chainId2)).onChain.config];
|
|
2519
|
-
} else {
|
|
2520
|
-
response.result = await Promise.all(account.networks.map(async function (network) {
|
|
2521
|
-
const status = await account.status(network.chainId);
|
|
2522
|
-
return status.onChain.config;
|
|
2523
|
-
}));
|
|
2524
|
-
}
|
|
2525
|
-
break;
|
|
2526
|
-
}
|
|
2527
|
-
|
|
2528
|
-
// smart wallet method
|
|
2529
|
-
case 'sequence_getWalletState':
|
|
2530
|
-
{
|
|
2531
|
-
const [_chainId3] = request.params;
|
|
2532
|
-
// TODO: Add getWalletState to the Signer interface
|
|
2533
|
-
if (_chainId3) {
|
|
2534
|
-
response.result = [getLegacyWalletState(_chainId3, await account.status(_chainId3))];
|
|
2535
|
-
} else {
|
|
2536
|
-
response.result = await Promise.all(account.networks.map(async function (network) {
|
|
2537
|
-
const status = await account.status(network.chainId);
|
|
2538
|
-
return getLegacyWalletState(network.chainId, status);
|
|
2539
|
-
}));
|
|
2540
|
-
}
|
|
2541
|
-
break;
|
|
2542
|
-
}
|
|
2543
|
-
|
|
2544
|
-
// smart wallet method
|
|
2545
|
-
case 'sequence_getNetworks':
|
|
2546
|
-
{
|
|
2547
|
-
// NOTE: must ensure that the response result below returns clean serialized data, which is to omit
|
|
2548
|
-
// the provider and relayer objects and only return the urls so can be reinstantiated on dapp side.
|
|
2549
|
-
// This is handled by this.getNetworks() but noted here for future readers.
|
|
2550
|
-
response.result = await _this.getNetworks(true);
|
|
2551
|
-
break;
|
|
2552
|
-
}
|
|
2553
|
-
case 'sequence_isSequence':
|
|
2554
|
-
{
|
|
2555
|
-
response.result = true;
|
|
2556
|
-
break;
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
// smart wallet method
|
|
2560
|
-
case 'sequence_updateConfig':
|
|
2561
|
-
{
|
|
2562
|
-
throw new Error('sequence_updateConfig method is not allowed from a dapp');
|
|
2563
|
-
// NOTE: method is disabled as we don't need a dapp to request to update a config.
|
|
2564
|
-
// However, if we ever want this, we can enable it but must also use the prompter
|
|
2565
|
-
// for confirmation.
|
|
2566
|
-
//
|
|
2567
|
-
// const [newConfig] = request.params
|
|
2568
|
-
// response.result = await signer.updateConfig(newConfig)
|
|
2569
|
-
break;
|
|
2570
|
-
}
|
|
2571
|
-
|
|
2572
|
-
// smart wallet method
|
|
2573
|
-
case 'sequence_publishConfig':
|
|
2574
|
-
{
|
|
2575
|
-
throw new Error('sequence_publishConfig method is not allowed from a dapp');
|
|
2576
|
-
break;
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
// relayer method
|
|
2580
|
-
case 'sequence_gasRefundOptions':
|
|
2581
|
-
{
|
|
2582
|
-
// TODO
|
|
2583
|
-
break;
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
// relayer method
|
|
2587
|
-
case 'sequence_getNonce':
|
|
2588
|
-
{
|
|
2589
|
-
// TODO
|
|
2590
|
-
break;
|
|
2591
|
-
}
|
|
2592
|
-
|
|
2593
|
-
// relayer method
|
|
2594
|
-
case 'sequence_relay':
|
|
2595
|
-
{
|
|
2596
|
-
// TODO
|
|
2597
|
-
break;
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2600
|
-
// set default network of wallet
|
|
2601
|
-
case 'sequence_setDefaultNetwork':
|
|
2602
|
-
{
|
|
2603
|
-
const [defaultChainId] = request.params;
|
|
2604
|
-
if (!defaultChainId) {
|
|
2605
|
-
throw new Error('invalid request, method argument defaultChainId cannot be empty');
|
|
2606
|
-
}
|
|
2607
|
-
_this.setDefaultChainId(defaultChainId);
|
|
2608
|
-
response.result = await _this.getNetworks(true);
|
|
2609
|
-
break;
|
|
2610
|
-
}
|
|
2611
|
-
default:
|
|
2612
|
-
{
|
|
2613
|
-
if (!jsonRpcProvider) {
|
|
2614
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
// NOTE: provider here will be chain-bound if chainId is provided
|
|
2618
|
-
const providerResponse = await jsonRpcProvider.send(request.method, request.params);
|
|
2619
|
-
response.result = providerResponse;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
} catch (err) {
|
|
2623
|
-
logger.error(err);
|
|
2624
|
-
|
|
2625
|
-
// See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md#rpc-errors
|
|
2626
|
-
response.result = null;
|
|
2627
|
-
response.error = _extends({}, new Error(err), {
|
|
2628
|
-
code: 4001
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
|
-
callback(undefined, response);
|
|
2632
|
-
};
|
|
2633
2226
|
this.isSignedIn = async function () {
|
|
2634
2227
|
await _this.signerReady();
|
|
2635
2228
|
return !!_this.account;
|
|
@@ -2641,7 +2234,7 @@ class WalletRequestHandler {
|
|
|
2641
2234
|
}
|
|
2642
2235
|
return _this.account;
|
|
2643
2236
|
};
|
|
2644
|
-
this.account =
|
|
2237
|
+
this.account = account;
|
|
2645
2238
|
this.prompter = prompter;
|
|
2646
2239
|
this.networks = networks;
|
|
2647
2240
|
}
|
|
@@ -2725,7 +2318,7 @@ class WalletRequestHandler {
|
|
|
2725
2318
|
const chainId = findSupportedNetwork(networkId).chainId;
|
|
2726
2319
|
const connectDetails = {
|
|
2727
2320
|
connected: true,
|
|
2728
|
-
chainId: ethers.
|
|
2321
|
+
chainId: ethers.toQuantity(chainId)
|
|
2729
2322
|
};
|
|
2730
2323
|
if (options && options.authorize) {
|
|
2731
2324
|
// Perform ethauth eip712 request and construct the ConnectDetails response
|
|
@@ -2760,20 +2353,415 @@ class WalletRequestHandler {
|
|
|
2760
2353
|
// sendMessageRequest will unwrap the ProviderMessageRequest and send it to the JsonRpcHandler
|
|
2761
2354
|
// (aka, the signer in this instance) and then responds with a wrapped response of
|
|
2762
2355
|
// ProviderMessageResponse to be sent over the transport
|
|
2763
|
-
sendMessageRequest(message) {
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2356
|
+
async sendMessageRequest(message) {
|
|
2357
|
+
var _message$clientVersio;
|
|
2358
|
+
// Older versions of the client require the response to be jsonrpc wrapped
|
|
2359
|
+
const majorVersion = Number(((_message$clientVersio = message.clientVersion) == null ? void 0 : _message$clientVersio.split('.')[0]) || '0');
|
|
2360
|
+
const isJsonRpcResponse = majorVersion < 2;
|
|
2361
|
+
const jsonRpcResponse = {
|
|
2362
|
+
id: message.data.id,
|
|
2363
|
+
jsonrpc: '2.0',
|
|
2364
|
+
result: null,
|
|
2365
|
+
error: undefined
|
|
2366
|
+
};
|
|
2367
|
+
try {
|
|
2368
|
+
const result = await this.request({
|
|
2369
|
+
method: message.data.method,
|
|
2370
|
+
params: message.data.params,
|
|
2371
|
+
chainId: message.chainId
|
|
2372
|
+
});
|
|
2373
|
+
return _extends({}, message, {
|
|
2374
|
+
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2375
|
+
result
|
|
2376
|
+
}) : result
|
|
2377
|
+
});
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
return _extends({}, message, {
|
|
2380
|
+
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2381
|
+
error
|
|
2382
|
+
}) : error
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
async request(request) {
|
|
2387
|
+
await this.getAccount();
|
|
2388
|
+
try {
|
|
2389
|
+
var _this$account, _request$chainId;
|
|
2390
|
+
// only allow public json rpc method to the provider when user is not logged in, aka signer is not set
|
|
2391
|
+
if ((!this.account || this.account === null) && !permittedJsonRpcMethods.includes(request.method)) {
|
|
2392
|
+
// throw new Error(`not logged in. ${request.method} is unavailable`)
|
|
2393
|
+
throw ErrSignedInRequired;
|
|
2394
|
+
}
|
|
2767
2395
|
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2396
|
+
// wallet account
|
|
2397
|
+
const account = this.account;
|
|
2398
|
+
if (!account) {
|
|
2399
|
+
throw new Error('WalletRequestHandler: wallet account is not configured');
|
|
2400
|
+
}
|
|
2771
2401
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2402
|
+
// fetch the provider for the specific chain, or undefined will select defaultChain
|
|
2403
|
+
const provider = (_this$account = this.account) == null ? void 0 : _this$account.providerFor((_request$chainId = request.chainId) != null ? _request$chainId : this.defaultChainId());
|
|
2404
|
+
if (!provider) {
|
|
2405
|
+
throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${request.chainId}`);
|
|
2406
|
+
}
|
|
2407
|
+
const jsonRpcProvider = provider instanceof ethers.JsonRpcProvider ? provider : undefined;
|
|
2408
|
+
switch (request.method) {
|
|
2409
|
+
case 'net_version':
|
|
2410
|
+
{
|
|
2411
|
+
if (!jsonRpcProvider) {
|
|
2412
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2413
|
+
}
|
|
2414
|
+
return await jsonRpcProvider.send('net_version', []);
|
|
2415
|
+
}
|
|
2416
|
+
case 'eth_chainId':
|
|
2417
|
+
{
|
|
2418
|
+
if (!jsonRpcProvider) {
|
|
2419
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2420
|
+
}
|
|
2421
|
+
return await jsonRpcProvider.send('eth_chainId', []);
|
|
2422
|
+
}
|
|
2423
|
+
case 'eth_accounts':
|
|
2424
|
+
{
|
|
2425
|
+
return [account.address];
|
|
2426
|
+
}
|
|
2427
|
+
case 'eth_getBalance':
|
|
2428
|
+
{
|
|
2429
|
+
const [accountAddress, blockTag] = request.params;
|
|
2430
|
+
const walletBalance = await provider.getBalance(accountAddress, blockTag);
|
|
2431
|
+
return toHexString(walletBalance);
|
|
2432
|
+
}
|
|
2433
|
+
case 'sequence_sign':
|
|
2434
|
+
case 'personal_sign':
|
|
2435
|
+
case 'eth_sign':
|
|
2436
|
+
{
|
|
2437
|
+
// note: message from json-rpc input is in hex format
|
|
2438
|
+
let message;
|
|
2439
|
+
|
|
2440
|
+
// there is a difference in the order of the params:
|
|
2441
|
+
// sequence_sign, personal_sign: [data, address]
|
|
2442
|
+
// eth_sign: [address, data]
|
|
2443
|
+
switch (request.method) {
|
|
2444
|
+
case 'sequence_sign':
|
|
2445
|
+
case 'personal_sign':
|
|
2446
|
+
{
|
|
2447
|
+
const [data, _address] = request.params;
|
|
2448
|
+
message = data;
|
|
2449
|
+
break;
|
|
2450
|
+
}
|
|
2451
|
+
case 'eth_sign':
|
|
2452
|
+
{
|
|
2453
|
+
const [_address, data] = request.params;
|
|
2454
|
+
message = data;
|
|
2455
|
+
break;
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
let sig = '';
|
|
2459
|
+
|
|
2460
|
+
// Message must be prefixed with "\x19Ethereum Signed Message:\n"
|
|
2461
|
+
// as defined by EIP-191
|
|
2462
|
+
const prefixedMessage = prefixEIP191Message(message);
|
|
2463
|
+
|
|
2464
|
+
// TODO:
|
|
2465
|
+
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
2466
|
+
const sequenceVerified = request.method === 'sequence_sign';
|
|
2467
|
+
if (this.prompter === null) {
|
|
2468
|
+
var _request$chainId2;
|
|
2469
|
+
// prompter is null, so we'll sign from here
|
|
2470
|
+
sig = await account.signMessage(prefixedMessage, (_request$chainId2 = request.chainId) != null ? _request$chainId2 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2471
|
+
} else {
|
|
2472
|
+
sig = await this.prompter.promptSignMessage({
|
|
2473
|
+
chainId: request.chainId,
|
|
2474
|
+
message: ethers.getBytes(prefixedMessage),
|
|
2475
|
+
eip6492: sequenceVerified
|
|
2476
|
+
}, this.connectOptions);
|
|
2477
|
+
}
|
|
2478
|
+
if (sig && sig.length > 0) {
|
|
2479
|
+
return sig;
|
|
2480
|
+
} else {
|
|
2481
|
+
// The user has declined the request when value is null
|
|
2482
|
+
throw new Error('declined by user');
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
case 'sequence_signTypedData_v4':
|
|
2486
|
+
case 'eth_signTypedData':
|
|
2487
|
+
case 'eth_signTypedData_v4':
|
|
2488
|
+
{
|
|
2489
|
+
// note: signingAddress from json-rpc input is in hex format, and typedDataObject
|
|
2490
|
+
// should be an object, but in some instances may be double string encoded
|
|
2491
|
+
const [signingAddress, typedDataObject] = request.params;
|
|
2492
|
+
let typedData = undefined;
|
|
2493
|
+
if (typeof typedDataObject === 'string') {
|
|
2494
|
+
try {
|
|
2495
|
+
typedData = JSON.parse(typedDataObject);
|
|
2496
|
+
} catch (e) {
|
|
2497
|
+
console.warn('walletRequestHandler: error parsing typedData', e);
|
|
2498
|
+
}
|
|
2499
|
+
} else {
|
|
2500
|
+
typedData = typedDataObject;
|
|
2501
|
+
}
|
|
2502
|
+
if (!typedData || !typedData.domain || !typedData.types || !typedData.message) {
|
|
2503
|
+
throw new Error('invalid typedData object');
|
|
2504
|
+
}
|
|
2505
|
+
let sig = '';
|
|
2506
|
+
const sequenceVerified = request.method === 'sequence_signTypedData_v4';
|
|
2507
|
+
if (this.prompter === null) {
|
|
2508
|
+
var _request$chainId3;
|
|
2509
|
+
// prompter is null, so we'll sign from here
|
|
2510
|
+
sig = await account.signTypedData(typedData.domain, typedData.types, typedData.message, (_request$chainId3 = request.chainId) != null ? _request$chainId3 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2511
|
+
} else {
|
|
2512
|
+
sig = await this.prompter.promptSignMessage({
|
|
2513
|
+
chainId: request.chainId,
|
|
2514
|
+
typedData: typedData,
|
|
2515
|
+
eip6492: sequenceVerified
|
|
2516
|
+
}, this.connectOptions);
|
|
2517
|
+
}
|
|
2518
|
+
if (sig && sig.length > 0) {
|
|
2519
|
+
return sig;
|
|
2520
|
+
} else {
|
|
2521
|
+
// The user has declined the request when value is null
|
|
2522
|
+
throw new Error('declined by user');
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
case 'eth_sendTransaction':
|
|
2526
|
+
{
|
|
2527
|
+
// https://eth.wiki/json-rpc/API#eth_sendtransaction
|
|
2528
|
+
const transactionParams = fromExtended(request.params[0]).map(tx => {
|
|
2529
|
+
// eth_sendTransaction uses 'gas'
|
|
2530
|
+
// ethers and sequence use 'gasLimit'
|
|
2531
|
+
if ('gas' in tx && tx.gasLimit === undefined) {
|
|
2532
|
+
tx.gasLimit = tx.gas;
|
|
2533
|
+
delete tx.gas;
|
|
2534
|
+
}
|
|
2535
|
+
return tx;
|
|
2536
|
+
});
|
|
2537
|
+
validateTransactionRequest(account.address, transactionParams);
|
|
2538
|
+
let txnHash = '';
|
|
2539
|
+
if (this.prompter === null) {
|
|
2540
|
+
var _request$chainId4, _txnResponse$hash;
|
|
2541
|
+
// prompter is null, so we'll send from here
|
|
2542
|
+
const txnResponse = await account.sendTransaction(transactionParams, (_request$chainId4 = request.chainId) != null ? _request$chainId4 : this.defaultChainId());
|
|
2543
|
+
txnHash = (_txnResponse$hash = txnResponse == null ? void 0 : txnResponse.hash) != null ? _txnResponse$hash : '';
|
|
2544
|
+
} else {
|
|
2545
|
+
// prompt user to provide the response
|
|
2546
|
+
txnHash = await this.prompter.promptSendTransaction(transactionParams, request.chainId, this.connectOptions);
|
|
2547
|
+
}
|
|
2548
|
+
if (txnHash) {
|
|
2549
|
+
return txnHash;
|
|
2550
|
+
} else {
|
|
2551
|
+
// The user has declined the request when value is null
|
|
2552
|
+
throw new Error('declined by user');
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
case 'eth_signTransaction':
|
|
2556
|
+
{
|
|
2557
|
+
// https://eth.wiki/json-rpc/API#eth_signTransaction
|
|
2558
|
+
const [transaction] = request.params;
|
|
2559
|
+
const sender = ethers.getAddress(transaction.from);
|
|
2560
|
+
if (sender !== account.address) {
|
|
2561
|
+
throw new Error('sender address does not match wallet');
|
|
2562
|
+
}
|
|
2563
|
+
validateTransactionRequest(account.address, transaction);
|
|
2564
|
+
if (this.prompter === null) {
|
|
2565
|
+
var _request$chainId5;
|
|
2566
|
+
// The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
|
|
2567
|
+
// this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
|
|
2568
|
+
//
|
|
2569
|
+
// TODO: verify serializing / transporting the SignedTransaction object works as expected, most likely however
|
|
2570
|
+
// we will want to resolveProperties the big number values to hex strings
|
|
2571
|
+
return await account.signTransactions(transaction, (_request$chainId5 = request.chainId) != null ? _request$chainId5 : this.defaultChainId());
|
|
2572
|
+
} else {
|
|
2573
|
+
return await this.prompter.promptSignTransaction(transaction, request.chainId, this.connectOptions);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
case 'eth_sendRawTransaction':
|
|
2577
|
+
{
|
|
2578
|
+
// NOTE: we're not using a prompter here as the transaction is already signed
|
|
2579
|
+
// and would have prompted the user upon signing.
|
|
2580
|
+
|
|
2581
|
+
// https://eth.wiki/json-rpc/API#eth_sendRawTransaction
|
|
2582
|
+
if (commons.transaction.isSignedTransactionBundle(request.params[0])) {
|
|
2583
|
+
const txChainId = Number(request.params[0].chainId);
|
|
2584
|
+
const tx = await account.relayer(txChainId).relay(request.params[0]);
|
|
2585
|
+
return tx.hash;
|
|
2586
|
+
} else {
|
|
2587
|
+
const tx = await provider.broadcastTransaction(request.params[0]);
|
|
2588
|
+
return tx.hash;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
case 'eth_getTransactionCount':
|
|
2592
|
+
{
|
|
2593
|
+
const address = ethers.getAddress(request.params[0]);
|
|
2594
|
+
const tag = request.params[1];
|
|
2595
|
+
|
|
2596
|
+
// TODO: Maybe we should fetch this data from the relayer or from the reader
|
|
2597
|
+
// but for now we keep it simple and just use the provider
|
|
2598
|
+
|
|
2599
|
+
const count = await provider.getTransactionCount(address, tag);
|
|
2600
|
+
return toHexString(BigInt(count));
|
|
2601
|
+
}
|
|
2602
|
+
case 'eth_blockNumber':
|
|
2603
|
+
{
|
|
2604
|
+
return await provider.getBlockNumber();
|
|
2605
|
+
}
|
|
2606
|
+
case 'eth_getBlockByNumber':
|
|
2607
|
+
{
|
|
2608
|
+
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2609
|
+
}
|
|
2610
|
+
case 'eth_getBlockByHash':
|
|
2611
|
+
{
|
|
2612
|
+
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2613
|
+
}
|
|
2614
|
+
case 'eth_getTransactionByHash':
|
|
2615
|
+
{
|
|
2616
|
+
return await provider.getTransaction(request.params[0]);
|
|
2617
|
+
}
|
|
2618
|
+
case 'eth_call':
|
|
2619
|
+
{
|
|
2620
|
+
const [transactionObject, blockTag] = request.params;
|
|
2621
|
+
return await provider.call(_extends({}, transactionObject, {
|
|
2622
|
+
blockTag
|
|
2623
|
+
}));
|
|
2624
|
+
}
|
|
2625
|
+
case 'eth_getCode':
|
|
2626
|
+
{
|
|
2627
|
+
const [contractAddress, blockTag] = request.params;
|
|
2628
|
+
return await provider.getCode(contractAddress, blockTag);
|
|
2629
|
+
}
|
|
2630
|
+
case 'eth_estimateGas':
|
|
2631
|
+
{
|
|
2632
|
+
const [transactionObject] = request.params;
|
|
2633
|
+
return await provider.estimateGas(transactionObject);
|
|
2634
|
+
}
|
|
2635
|
+
case 'eth_gasPrice':
|
|
2636
|
+
{
|
|
2637
|
+
const feeData = await provider.getFeeData();
|
|
2638
|
+
return feeData.gasPrice === null ? null : toHexString(feeData.gasPrice);
|
|
2639
|
+
}
|
|
2640
|
+
case 'wallet_switchEthereumChain':
|
|
2641
|
+
{
|
|
2642
|
+
const [switchParams] = request.params;
|
|
2643
|
+
if (!switchParams.chainId || switchParams.chainId.length === 0) {
|
|
2644
|
+
throw new Error('invalid chainId');
|
|
2645
|
+
}
|
|
2646
|
+
const chainId = BigInt(switchParams.chainId);
|
|
2647
|
+
this.setDefaultChainId(Number(chainId));
|
|
2648
|
+
return null; // success
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// smart wallet method
|
|
2652
|
+
case 'sequence_getWalletContext':
|
|
2653
|
+
{
|
|
2654
|
+
return account.contexts;
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
// smart wallet method
|
|
2658
|
+
case 'sequence_getWalletConfig':
|
|
2659
|
+
{
|
|
2660
|
+
const [chainId] = request.params;
|
|
2661
|
+
if (chainId) {
|
|
2662
|
+
return [(await account.status(chainId)).onChain.config];
|
|
2663
|
+
} else {
|
|
2664
|
+
return await Promise.all(account.networks.map(async function (network) {
|
|
2665
|
+
const status = await account.status(network.chainId);
|
|
2666
|
+
return status.onChain.config;
|
|
2667
|
+
}));
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// smart wallet method
|
|
2672
|
+
case 'sequence_getWalletState':
|
|
2673
|
+
{
|
|
2674
|
+
const [chainId] = request.params;
|
|
2675
|
+
// TODO: Add getWalletState to the Signer interface
|
|
2676
|
+
if (chainId) {
|
|
2677
|
+
return [getLegacyWalletState(chainId, await account.status(chainId))];
|
|
2678
|
+
} else {
|
|
2679
|
+
return await Promise.all(account.networks.map(async function (network) {
|
|
2680
|
+
const status = await account.status(network.chainId);
|
|
2681
|
+
return getLegacyWalletState(network.chainId, status);
|
|
2682
|
+
}));
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
// smart wallet method
|
|
2687
|
+
case 'sequence_getNetworks':
|
|
2688
|
+
{
|
|
2689
|
+
// NOTE: must ensure that the response result below returns clean serialized data, which is to omit
|
|
2690
|
+
// the provider and relayer objects and only return the urls so can be reinstantiated on dapp side.
|
|
2691
|
+
// This is handled by this.getNetworks() but noted here for future readers.
|
|
2692
|
+
return await this.getNetworks(true);
|
|
2693
|
+
}
|
|
2694
|
+
case 'sequence_isSequence':
|
|
2695
|
+
{
|
|
2696
|
+
return true;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
// smart wallet method
|
|
2700
|
+
case 'sequence_updateConfig':
|
|
2701
|
+
{
|
|
2702
|
+
throw new Error('sequence_updateConfig method is not allowed from a dapp');
|
|
2703
|
+
// NOTE: method is disabled as we don't need a dapp to request to update a config.
|
|
2704
|
+
// However, if we ever want this, we can enable it but must also use the prompter
|
|
2705
|
+
// for confirmation.
|
|
2706
|
+
//
|
|
2707
|
+
// const [newConfig] = request.params
|
|
2708
|
+
// return await signer.updateConfig(newConfig)
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
// smart wallet method
|
|
2712
|
+
case 'sequence_publishConfig':
|
|
2713
|
+
{
|
|
2714
|
+
throw new Error('sequence_publishConfig method is not allowed from a dapp');
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
// relayer method
|
|
2718
|
+
case 'sequence_gasRefundOptions':
|
|
2719
|
+
{
|
|
2720
|
+
// TODO
|
|
2721
|
+
break;
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// relayer method
|
|
2725
|
+
case 'sequence_getNonce':
|
|
2726
|
+
{
|
|
2727
|
+
// TODO
|
|
2728
|
+
break;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
// relayer method
|
|
2732
|
+
case 'sequence_relay':
|
|
2733
|
+
{
|
|
2734
|
+
// TODO
|
|
2735
|
+
break;
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
// set default network of wallet
|
|
2739
|
+
case 'sequence_setDefaultNetwork':
|
|
2740
|
+
{
|
|
2741
|
+
const [defaultChainId] = request.params;
|
|
2742
|
+
if (!defaultChainId) {
|
|
2743
|
+
throw new Error('invalid request, method argument defaultChainId cannot be empty');
|
|
2744
|
+
}
|
|
2745
|
+
this.setDefaultChainId(defaultChainId);
|
|
2746
|
+
return await this.getNetworks(true);
|
|
2747
|
+
}
|
|
2748
|
+
default:
|
|
2749
|
+
{
|
|
2750
|
+
if (!jsonRpcProvider) {
|
|
2751
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
// NOTE: provider here will be chain-bound if chainId is provided
|
|
2755
|
+
return await jsonRpcProvider.send(request.method, request.params);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
} catch (err) {
|
|
2759
|
+
logger.error(err);
|
|
2760
|
+
throw {
|
|
2761
|
+
message: err == null ? void 0 : err.message,
|
|
2762
|
+
code: 4001
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2777
2765
|
}
|
|
2778
2766
|
on(event, fn) {
|
|
2779
2767
|
this.events.on(event, fn);
|
|
@@ -2861,7 +2849,7 @@ class WalletRequestHandler {
|
|
|
2861
2849
|
this.events.emit('disconnect', undefined, origin);
|
|
2862
2850
|
}
|
|
2863
2851
|
notifyChainChanged(chainId, origin) {
|
|
2864
|
-
this.events.emit('chainChanged', ethers.
|
|
2852
|
+
this.events.emit('chainChanged', ethers.toQuantity(chainId), origin);
|
|
2865
2853
|
}
|
|
2866
2854
|
async notifyNetworks(networks) {
|
|
2867
2855
|
const n = networks || (await this.getNetworks(true));
|
|
@@ -2869,7 +2857,7 @@ class WalletRequestHandler {
|
|
|
2869
2857
|
if (n.length > 0) {
|
|
2870
2858
|
const defaultNetwork = n.find(network => network.chainId === this.defaultChainId());
|
|
2871
2859
|
if (defaultNetwork) {
|
|
2872
|
-
this.events.emit('chainChanged', ethers.
|
|
2860
|
+
this.events.emit('chainChanged', ethers.toQuantity(defaultNetwork.chainId));
|
|
2873
2861
|
}
|
|
2874
2862
|
} else {
|
|
2875
2863
|
this.events.emit('chainChanged', '0x0');
|
|
@@ -2938,6 +2926,19 @@ function getLegacyWalletState(chainId, status) {
|
|
|
2938
2926
|
}
|
|
2939
2927
|
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'];
|
|
2940
2928
|
|
|
2929
|
+
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
2930
|
+
if (source == null) return {};
|
|
2931
|
+
var target = {};
|
|
2932
|
+
var sourceKeys = Object.keys(source);
|
|
2933
|
+
var key, i;
|
|
2934
|
+
for (i = 0; i < sourceKeys.length; i++) {
|
|
2935
|
+
key = sourceKeys[i];
|
|
2936
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
2937
|
+
target[key] = source[key];
|
|
2938
|
+
}
|
|
2939
|
+
return target;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2941
2942
|
class SequenceSigner {
|
|
2942
2943
|
get utils() {
|
|
2943
2944
|
return this.provider.utils;
|
|
@@ -2946,7 +2947,6 @@ class SequenceSigner {
|
|
|
2946
2947
|
this.client = client;
|
|
2947
2948
|
this.provider = provider;
|
|
2948
2949
|
this.singleNetworkSigners = {};
|
|
2949
|
-
this._isSigner = true;
|
|
2950
2950
|
this._isSequenceSigner = true;
|
|
2951
2951
|
}
|
|
2952
2952
|
async getAddress() {
|
|
@@ -3016,12 +3016,17 @@ class SequenceSigner {
|
|
|
3016
3016
|
});
|
|
3017
3017
|
const provider = this.getProvider(chainId);
|
|
3018
3018
|
try {
|
|
3019
|
-
|
|
3020
|
-
const
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3019
|
+
const result = await new Promise(resolve => {
|
|
3020
|
+
const check = async function check() {
|
|
3021
|
+
const tx = await provider.getTransaction(txHash);
|
|
3022
|
+
if (tx !== null) {
|
|
3023
|
+
return resolve(tx);
|
|
3024
|
+
}
|
|
3025
|
+
await provider.once('block', check);
|
|
3026
|
+
};
|
|
3027
|
+
check();
|
|
3024
3028
|
});
|
|
3029
|
+
return result;
|
|
3025
3030
|
} catch (err) {
|
|
3026
3031
|
err.transactionHash = txHash;
|
|
3027
3032
|
throw err;
|
|
@@ -3043,15 +3048,12 @@ class SequenceSigner {
|
|
|
3043
3048
|
async estimateGas(transaction, optionals) {
|
|
3044
3049
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).estimateGas(transaction);
|
|
3045
3050
|
}
|
|
3046
|
-
async call(transaction,
|
|
3047
|
-
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction
|
|
3051
|
+
async call(transaction, optionals) {
|
|
3052
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction);
|
|
3048
3053
|
}
|
|
3049
3054
|
getChainId() {
|
|
3050
3055
|
return Promise.resolve(this.client.getChainId());
|
|
3051
3056
|
}
|
|
3052
|
-
async getGasPrice(optionals) {
|
|
3053
|
-
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getGasPrice();
|
|
3054
|
-
}
|
|
3055
3057
|
async getFeeData(optionals) {
|
|
3056
3058
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getFeeData();
|
|
3057
3059
|
}
|
|
@@ -3059,7 +3061,7 @@ class SequenceSigner {
|
|
|
3059
3061
|
const res = await this.provider.resolveName(name);
|
|
3060
3062
|
|
|
3061
3063
|
// For some reason ethers.Signer expects this to return `string`
|
|
3062
|
-
// but ethers.
|
|
3064
|
+
// but ethers.Provider expects this to return `string | null`.
|
|
3063
3065
|
// The signer doesn't have any other source of information, so we'll
|
|
3064
3066
|
// fail if the provider doesn't return a result.
|
|
3065
3067
|
if (res === null) {
|
|
@@ -3070,6 +3072,12 @@ class SequenceSigner {
|
|
|
3070
3072
|
_checkProvider(_operation) {
|
|
3071
3073
|
// We always have a provider, so this is a noop
|
|
3072
3074
|
}
|
|
3075
|
+
getNonce(_blockTag) {
|
|
3076
|
+
throw new Error('SequenceSigner does not support getNonce');
|
|
3077
|
+
}
|
|
3078
|
+
populateCall(_transaction) {
|
|
3079
|
+
throw new Error('SequenceSigner does not support populateCall');
|
|
3080
|
+
}
|
|
3073
3081
|
populateTransaction(_transaction) {
|
|
3074
3082
|
throw new Error('SequenceSigner does not support populateTransaction');
|
|
3075
3083
|
}
|
|
@@ -3207,31 +3215,43 @@ class WalletUtils {
|
|
|
3207
3215
|
// recoverAddress()
|
|
3208
3216
|
}
|
|
3209
3217
|
|
|
3210
|
-
|
|
3211
|
-
|
|
3218
|
+
const _excluded = ["method"];
|
|
3219
|
+
const EIP1193EventTypes = ['connect', 'disconnect', 'chainChanged', 'accountsChanged'];
|
|
3220
|
+
class SequenceProvider extends ethers.AbstractProvider {
|
|
3221
|
+
constructor(client, providerFor, networks = allNetworks, options) {
|
|
3212
3222
|
// We support a lot of networks
|
|
3213
3223
|
// but we start with the default one
|
|
3214
|
-
super(client.getChainId());
|
|
3224
|
+
super(client.getChainId(), options);
|
|
3215
3225
|
|
|
3216
3226
|
// Emit events as defined by EIP-1193
|
|
3217
3227
|
this.client = client;
|
|
3218
3228
|
this.providerFor = providerFor;
|
|
3219
3229
|
this.networks = networks;
|
|
3230
|
+
this.options = options;
|
|
3220
3231
|
this.singleNetworkProviders = {};
|
|
3221
3232
|
this._isSequenceProvider = true;
|
|
3222
3233
|
this.utils = void 0;
|
|
3223
3234
|
this.signer = void 0;
|
|
3235
|
+
this.eip1193EventListeners = new Map();
|
|
3224
3236
|
client.onConnect(details => {
|
|
3225
|
-
|
|
3237
|
+
var _this$eip1193EventLis;
|
|
3238
|
+
//this.emit('connect', details)
|
|
3239
|
+
(_this$eip1193EventLis = this.eip1193EventListeners.get('connect')) == null || _this$eip1193EventLis.forEach(listener => listener(details));
|
|
3226
3240
|
});
|
|
3227
3241
|
client.onDisconnect(error => {
|
|
3228
|
-
|
|
3242
|
+
var _this$eip1193EventLis2;
|
|
3243
|
+
//this.emit('disconnect', error)
|
|
3244
|
+
(_this$eip1193EventLis2 = this.eip1193EventListeners.get('disconnect')) == null || _this$eip1193EventLis2.forEach(listener => listener(error));
|
|
3229
3245
|
});
|
|
3230
3246
|
client.onDefaultChainIdChanged(chainId => {
|
|
3231
|
-
|
|
3247
|
+
var _this$eip1193EventLis3;
|
|
3248
|
+
//this.emit('chainChanged', chainId)
|
|
3249
|
+
(_this$eip1193EventLis3 = this.eip1193EventListeners.get('chainChanged')) == null || _this$eip1193EventLis3.forEach(listener => listener(chainId));
|
|
3232
3250
|
});
|
|
3233
3251
|
client.onAccountsChanged(accounts => {
|
|
3234
|
-
|
|
3252
|
+
var _this$eip1193EventLis4;
|
|
3253
|
+
//this.emit('accountsChanged', accounts)
|
|
3254
|
+
(_this$eip1193EventLis4 = this.eip1193EventListeners.get('accountsChanged')) == null || _this$eip1193EventLis4.forEach(listener => listener(accounts));
|
|
3235
3255
|
});
|
|
3236
3256
|
|
|
3237
3257
|
// NOTICE: We don't emit 'open' and 'close' events
|
|
@@ -3248,6 +3268,29 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3248
3268
|
// Create a utils instance
|
|
3249
3269
|
this.utils = new WalletUtils(this.signer);
|
|
3250
3270
|
}
|
|
3271
|
+
async on(event, listener) {
|
|
3272
|
+
if (EIP1193EventTypes.includes(event)) {
|
|
3273
|
+
const listeners = this.eip1193EventListeners.get(event) || new Set();
|
|
3274
|
+
listeners.add(listener);
|
|
3275
|
+
this.eip1193EventListeners.set(event, listeners);
|
|
3276
|
+
return this;
|
|
3277
|
+
}
|
|
3278
|
+
return super.on(event, listener);
|
|
3279
|
+
}
|
|
3280
|
+
async off(event, listener) {
|
|
3281
|
+
if (EIP1193EventTypes.includes(event)) {
|
|
3282
|
+
const listeners = this.eip1193EventListeners.get(event);
|
|
3283
|
+
if (listeners) {
|
|
3284
|
+
if (listener) {
|
|
3285
|
+
listeners.delete(listener);
|
|
3286
|
+
} else {
|
|
3287
|
+
listeners.clear();
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
return this;
|
|
3291
|
+
}
|
|
3292
|
+
return super.off(event, listener);
|
|
3293
|
+
}
|
|
3251
3294
|
getSigner(chainId) {
|
|
3252
3295
|
return this.signer.getSigner(chainId);
|
|
3253
3296
|
}
|
|
@@ -3340,7 +3383,7 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3340
3383
|
}
|
|
3341
3384
|
const useChainId = this.toChainId(chainId);
|
|
3342
3385
|
if (!this.singleNetworkProviders[useChainId]) {
|
|
3343
|
-
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId);
|
|
3386
|
+
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId, this.options);
|
|
3344
3387
|
}
|
|
3345
3388
|
return this.singleNetworkProviders[useChainId];
|
|
3346
3389
|
}
|
|
@@ -3360,11 +3403,26 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3360
3403
|
}
|
|
3361
3404
|
return provider;
|
|
3362
3405
|
}
|
|
3406
|
+
async _perform(req) {
|
|
3407
|
+
var _provider$getRpcReque;
|
|
3408
|
+
const {
|
|
3409
|
+
method
|
|
3410
|
+
} = req,
|
|
3411
|
+
args = _objectWithoutPropertiesLoose(req, _excluded);
|
|
3412
|
+
const provider = await this._getSubprovider();
|
|
3413
|
+
const prepared = (_provider$getRpcReque = provider.getRpcRequest(req)) != null ? _provider$getRpcReque : {
|
|
3414
|
+
method,
|
|
3415
|
+
args: Object.values(args)
|
|
3416
|
+
};
|
|
3417
|
+
if (!prepared) {
|
|
3418
|
+
throw new Error(`Unsupported method ${req.method}`);
|
|
3419
|
+
}
|
|
3420
|
+
return provider.send(prepared.method, prepared.args);
|
|
3421
|
+
}
|
|
3363
3422
|
async perform(method, params) {
|
|
3364
|
-
var _provider$prepareRequ;
|
|
3365
3423
|
// First we check if the method should be handled by the client
|
|
3366
3424
|
if (method === 'eth_chainId') {
|
|
3367
|
-
return ethers.
|
|
3425
|
+
return ethers.toQuantity(await this.useChainId());
|
|
3368
3426
|
}
|
|
3369
3427
|
if (method === 'eth_accounts') {
|
|
3370
3428
|
return [this.client.getAddress()];
|
|
@@ -3384,17 +3442,15 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3384
3442
|
method === 'sequence_sign' || method === 'sequence_signTypedData_v4') {
|
|
3385
3443
|
// We pass the chainId to the client, if we don't pass one
|
|
3386
3444
|
// the client will use its own default chainId
|
|
3387
|
-
return this.client.
|
|
3445
|
+
return this.client.request({
|
|
3388
3446
|
method,
|
|
3389
|
-
params
|
|
3390
|
-
|
|
3447
|
+
params,
|
|
3448
|
+
chainId: this.getChainId()
|
|
3449
|
+
});
|
|
3391
3450
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
const provider = await this._getSubprovider();
|
|
3396
|
-
const prepared = (_provider$prepareRequ = provider.prepareRequest(method, params)) != null ? _provider$prepareRequ : [method, params];
|
|
3397
|
-
return provider.send(prepared[0], prepared[1]);
|
|
3451
|
+
return this._perform(_extends({
|
|
3452
|
+
method
|
|
3453
|
+
}, params));
|
|
3398
3454
|
}
|
|
3399
3455
|
send(method, params) {
|
|
3400
3456
|
return this.perform(method, params);
|
|
@@ -3402,14 +3458,18 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3402
3458
|
request(request) {
|
|
3403
3459
|
return this.perform(request.method, request.params);
|
|
3404
3460
|
}
|
|
3405
|
-
async
|
|
3461
|
+
async _detectNetwork() {
|
|
3406
3462
|
const chainId = this.client.getChainId();
|
|
3407
|
-
const
|
|
3408
|
-
if (!
|
|
3463
|
+
const found = findNetworkConfig(this.networks, chainId);
|
|
3464
|
+
if (!found) {
|
|
3409
3465
|
throw new Error(`Unknown network ${chainId}`);
|
|
3410
3466
|
}
|
|
3467
|
+
const network = new ethers.Network(found.name, found.chainId);
|
|
3411
3468
|
return network;
|
|
3412
3469
|
}
|
|
3470
|
+
async detectNetwork() {
|
|
3471
|
+
return this._detectNetwork();
|
|
3472
|
+
}
|
|
3413
3473
|
|
|
3414
3474
|
// Override most of the methods, so we add support for an optional chainId
|
|
3415
3475
|
// argument, which is used to select the provider to use.
|
|
@@ -3426,9 +3486,9 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3426
3486
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3427
3487
|
return provider.getBlockNumber();
|
|
3428
3488
|
}
|
|
3429
|
-
async
|
|
3489
|
+
async getFeeData(optionals) {
|
|
3430
3490
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3431
|
-
return provider.
|
|
3491
|
+
return provider.getFeeData();
|
|
3432
3492
|
}
|
|
3433
3493
|
async getBalance(addressOrName, blockTag, optionals) {
|
|
3434
3494
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3442,21 +3502,21 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3442
3502
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3443
3503
|
return provider.getCode(addressOrName, blockTag);
|
|
3444
3504
|
}
|
|
3445
|
-
async
|
|
3505
|
+
async getStorage(addressOrName, position, blockTag, optionals) {
|
|
3446
3506
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3447
|
-
return provider.
|
|
3507
|
+
return provider.getStorage(addressOrName, position, blockTag);
|
|
3448
3508
|
}
|
|
3449
|
-
async call(transaction,
|
|
3509
|
+
async call(transaction, optionals) {
|
|
3450
3510
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3451
|
-
return provider.call(transaction
|
|
3511
|
+
return provider.call(transaction);
|
|
3452
3512
|
}
|
|
3453
3513
|
async estimateGas(transaction, optionals) {
|
|
3454
3514
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3455
3515
|
return provider.estimateGas(transaction);
|
|
3456
3516
|
}
|
|
3457
|
-
async getBlock(blockHashOrBlockTag, optionals) {
|
|
3517
|
+
async getBlock(blockHashOrBlockTag, prefetchTxs, optionals) {
|
|
3458
3518
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3459
|
-
return provider.getBlock(blockHashOrBlockTag);
|
|
3519
|
+
return provider.getBlock(blockHashOrBlockTag, prefetchTxs);
|
|
3460
3520
|
}
|
|
3461
3521
|
async getTransaction(transactionHash, optionals) {
|
|
3462
3522
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3483,7 +3543,7 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3483
3543
|
return provider.getResolver(name);
|
|
3484
3544
|
}
|
|
3485
3545
|
async resolveName(name) {
|
|
3486
|
-
if (ethers.
|
|
3546
|
+
if (ethers.isAddress(name)) {
|
|
3487
3547
|
return name;
|
|
3488
3548
|
}
|
|
3489
3549
|
if (!(await this.supportsENS())) {
|
|
@@ -3516,7 +3576,7 @@ SequenceProvider.is = provider => {
|
|
|
3516
3576
|
};
|
|
3517
3577
|
function normalizeChainId(chainId) {
|
|
3518
3578
|
if (typeof chainId === 'object') return normalizeChainId(chainId.chainId);
|
|
3519
|
-
return
|
|
3579
|
+
return Number(chainId);
|
|
3520
3580
|
}
|
|
3521
3581
|
|
|
3522
3582
|
/**
|
|
@@ -3529,8 +3589,8 @@ function normalizeChainId(chainId) {
|
|
|
3529
3589
|
* NOTICE: These networks won't support ENS unless they are the mainnet.
|
|
3530
3590
|
*/
|
|
3531
3591
|
class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
3532
|
-
constructor(client, providerFor, chainId) {
|
|
3533
|
-
super(client, providerFor);
|
|
3592
|
+
constructor(client, providerFor, chainId, options) {
|
|
3593
|
+
super(client, providerFor, undefined, options);
|
|
3534
3594
|
this.chainId = chainId;
|
|
3535
3595
|
this._isSingleNetworkSequenceProvider = true;
|
|
3536
3596
|
}
|
|
@@ -3549,11 +3609,11 @@ class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
|
3549
3609
|
}
|
|
3550
3610
|
async getNetwork() {
|
|
3551
3611
|
const networks = await this.client.getNetworks();
|
|
3552
|
-
const
|
|
3553
|
-
if (!
|
|
3612
|
+
const found = findNetworkConfig(networks, this.chainId);
|
|
3613
|
+
if (!found) {
|
|
3554
3614
|
throw new Error(`Unsupported network ${this.chainId}`);
|
|
3555
3615
|
}
|
|
3556
|
-
return
|
|
3616
|
+
return new ethers.Network(found.name, found.chainId);
|
|
3557
3617
|
}
|
|
3558
3618
|
|
|
3559
3619
|
/**
|
|
@@ -3616,55 +3676,6 @@ const setupAnalytics = (projectAccessKey, server) => {
|
|
|
3616
3676
|
});
|
|
3617
3677
|
};
|
|
3618
3678
|
|
|
3619
|
-
var packageJson = {
|
|
3620
|
-
name: "@0xsequence/provider",
|
|
3621
|
-
version: "1.10.15",
|
|
3622
|
-
description: "provider sub-package for Sequence",
|
|
3623
|
-
repository: "https://github.com/0xsequence/sequence.js/tree/master/packages/provider",
|
|
3624
|
-
source: "src/index.ts",
|
|
3625
|
-
main: "dist/0xsequence-provider.cjs.js",
|
|
3626
|
-
module: "dist/0xsequence-provider.esm.js",
|
|
3627
|
-
author: "Horizon Blockchain Games",
|
|
3628
|
-
license: "Apache-2.0",
|
|
3629
|
-
scripts: {
|
|
3630
|
-
test: "pnpm test:concurrently 'pnpm test:run'",
|
|
3631
|
-
"test:run": "pnpm test:file tests/**/*.spec.ts",
|
|
3632
|
-
"test:file": "NODE_OPTIONS='--import tsx' mocha --timeout 30000",
|
|
3633
|
-
typecheck: "tsc --noEmit",
|
|
3634
|
-
"test:concurrently": "concurrently -k --success first 'pnpm start:hardhat1' 'pnpm start:hardhat2'",
|
|
3635
|
-
"start:hardhat1": "pnpm start:hardhat1:verbose > /dev/null 2>&1",
|
|
3636
|
-
"start:hardhat2": "pnpm start:hardhat2:verbose > /dev/null 2>&1",
|
|
3637
|
-
"start:hardhat1:verbose": "hardhat node --config hardhat1.config.js --hostname 0.0.0.0 --port 9595",
|
|
3638
|
-
"start:hardhat2:verbose": "hardhat node --config hardhat2.config.js --hostname 0.0.0.0 --port 8595"
|
|
3639
|
-
},
|
|
3640
|
-
dependencies: {
|
|
3641
|
-
"@0xsequence/abi": "workspace:*",
|
|
3642
|
-
"@0xsequence/account": "workspace:*",
|
|
3643
|
-
"@0xsequence/auth": "workspace:*",
|
|
3644
|
-
"@0xsequence/core": "workspace:*",
|
|
3645
|
-
"@0xsequence/migration": "workspace:*",
|
|
3646
|
-
"@0xsequence/network": "workspace:*",
|
|
3647
|
-
"@0xsequence/relayer": "workspace:*",
|
|
3648
|
-
"@0xsequence/utils": "workspace:*",
|
|
3649
|
-
"@0xsequence/wallet": "workspace:*",
|
|
3650
|
-
"@databeat/tracker": "^0.9.1",
|
|
3651
|
-
eventemitter2: "^6.4.5",
|
|
3652
|
-
"webextension-polyfill": "^0.10.0"
|
|
3653
|
-
},
|
|
3654
|
-
peerDependencies: {
|
|
3655
|
-
ethers: ">=5.5 < 6"
|
|
3656
|
-
},
|
|
3657
|
-
devDependencies: {
|
|
3658
|
-
"@types/webextension-polyfill": "^0.10.0",
|
|
3659
|
-
ethers: "^5.7.2",
|
|
3660
|
-
hardhat: "^2.20.1"
|
|
3661
|
-
},
|
|
3662
|
-
files: [
|
|
3663
|
-
"src",
|
|
3664
|
-
"dist"
|
|
3665
|
-
]
|
|
3666
|
-
};
|
|
3667
|
-
|
|
3668
3679
|
/**
|
|
3669
3680
|
* This session class is meant to persist the state of the wallet connection
|
|
3670
3681
|
* whitin the dapp. This enables the client to retain the wallet address (and some more)
|
|
@@ -3780,7 +3791,7 @@ class SequenceClient {
|
|
|
3780
3791
|
});
|
|
3781
3792
|
this.transport.on('connect', response => {
|
|
3782
3793
|
var _this$callbacks$conne;
|
|
3783
|
-
const chainIdHex = ethers.
|
|
3794
|
+
const chainIdHex = ethers.toQuantity(this.getChainId());
|
|
3784
3795
|
(_this$callbacks$conne = this.callbacks.connect) == null || _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
|
|
3785
3796
|
// Ignore the full connect response
|
|
3786
3797
|
// use the chainId defined locally
|
|
@@ -3816,7 +3827,7 @@ class SequenceClient {
|
|
|
3816
3827
|
// instead we handle it locally, so we listen for changes in the store
|
|
3817
3828
|
this.defaultChainId.onDefaultChainIdChanged(chainId => {
|
|
3818
3829
|
var _this$callbacks$chain2;
|
|
3819
|
-
const chainIdHex = ethers.
|
|
3830
|
+
const chainIdHex = ethers.toQuantity(chainId);
|
|
3820
3831
|
(_this$callbacks$chain2 = this.callbacks.chainChanged) == null || _this$callbacks$chain2.forEach(cb => cb(chainIdHex));
|
|
3821
3832
|
});
|
|
3822
3833
|
if (options != null && options.projectAccessKey) {
|
|
@@ -3929,7 +3940,7 @@ class SequenceClient {
|
|
|
3929
3940
|
type: 'connect',
|
|
3930
3941
|
options: _extends({}, options, {
|
|
3931
3942
|
networkId: this.getChainId(),
|
|
3932
|
-
clientVersion:
|
|
3943
|
+
clientVersion: VERSION
|
|
3933
3944
|
})
|
|
3934
3945
|
});
|
|
3935
3946
|
const connectDetails = await this.transport.waitUntilConnected().catch(error => {
|
|
@@ -3949,7 +3960,7 @@ class SequenceClient {
|
|
|
3949
3960
|
// Normalize chainId into a decimal string
|
|
3950
3961
|
// TODO: Remove this once wallet-webapp returns chainId as a string
|
|
3951
3962
|
if (connectDetails.chainId) {
|
|
3952
|
-
connectDetails.chainId =
|
|
3963
|
+
connectDetails.chainId = BigInt(connectDetails.chainId).toString();
|
|
3953
3964
|
}
|
|
3954
3965
|
if (connectDetails.connected) {
|
|
3955
3966
|
var _connectDetails$sessi;
|
|
@@ -3975,33 +3986,20 @@ class SequenceClient {
|
|
|
3975
3986
|
|
|
3976
3987
|
// Higher level API
|
|
3977
3988
|
|
|
3978
|
-
|
|
3979
|
-
// but transport uses it instead of send, so we wrap it
|
|
3980
|
-
send(request, chainId) {
|
|
3989
|
+
async request(request) {
|
|
3981
3990
|
// Internally when sending requests we use `legacy_sign`
|
|
3982
3991
|
// to avoid the default EIP6492 behavior overriding an explicit
|
|
3983
3992
|
// "legacy sign" request, so we map the method here.
|
|
3984
3993
|
request.method = this.mapSignMethod(request.method);
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
} else if (response === undefined) {
|
|
3990
|
-
reject(new Error(`Got undefined response for request: ${request}`));
|
|
3991
|
-
} else if (typeof response === 'object' && response.error) {
|
|
3992
|
-
reject(response.error);
|
|
3993
|
-
} else if (typeof response === 'object' && response.result) {
|
|
3994
|
-
resolve(response.result);
|
|
3995
|
-
} else {
|
|
3996
|
-
reject(new Error(`Got invalid response for request: ${request}`));
|
|
3997
|
-
}
|
|
3998
|
-
}, chainId || this.getChainId());
|
|
3999
|
-
});
|
|
3994
|
+
const result = await this.transport.request(request);
|
|
3995
|
+
|
|
3996
|
+
// We may need to unwrap the response if it's a JSON-RPC response. ie. older universal wallet versions
|
|
3997
|
+
return unwrapJsonRpcResponse(result);
|
|
4000
3998
|
}
|
|
4001
3999
|
async getNetworks(pull) {
|
|
4002
4000
|
const connectedSession = this.session.connectedSession();
|
|
4003
4001
|
if (pull) {
|
|
4004
|
-
connectedSession.networks = await this.
|
|
4002
|
+
connectedSession.networks = await this.request({
|
|
4005
4003
|
method: 'sequence_getNetworks'
|
|
4006
4004
|
});
|
|
4007
4005
|
this.session.setSession(connectedSession);
|
|
@@ -4057,15 +4055,14 @@ class SequenceClient {
|
|
|
4057
4055
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4058
4056
|
}
|
|
4059
4057
|
});
|
|
4060
|
-
|
|
4061
|
-
// Serialize a BytesLike or string message into a hex string before sending
|
|
4062
|
-
message = ethers.utils.hexlify(messageToBytes(message));
|
|
4058
|
+
message = ethers.hexlify(messageToBytes(message));
|
|
4063
4059
|
|
|
4064
4060
|
// Address is ignored by the wallet webapp
|
|
4065
|
-
return this.
|
|
4061
|
+
return this.request({
|
|
4066
4062
|
method,
|
|
4067
|
-
params: [message, this.getAddress()]
|
|
4068
|
-
|
|
4063
|
+
params: [message, this.getAddress()],
|
|
4064
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4065
|
+
});
|
|
4069
4066
|
}
|
|
4070
4067
|
async signTypedData(typedData, options) {
|
|
4071
4068
|
var _this$analytics5;
|
|
@@ -4073,7 +4070,7 @@ class SequenceClient {
|
|
|
4073
4070
|
|
|
4074
4071
|
// TODO: Stop using ethers for this, this is the only place where we use it
|
|
4075
4072
|
// and it makes the client depend on ethers.
|
|
4076
|
-
const encoded = ethers.
|
|
4073
|
+
const encoded = ethers.TypedDataEncoder.getPayload(typedData.domain, typedData.types, typedData.message);
|
|
4077
4074
|
|
|
4078
4075
|
// The sign typed data will use one of the following chainIds, in order:
|
|
4079
4076
|
// - The one provided in the options
|
|
@@ -4086,10 +4083,11 @@ class SequenceClient {
|
|
|
4086
4083
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4087
4084
|
}
|
|
4088
4085
|
});
|
|
4089
|
-
return this.
|
|
4086
|
+
return this.request({
|
|
4090
4087
|
method,
|
|
4091
|
-
params: [this.getAddress(), encoded]
|
|
4092
|
-
|
|
4088
|
+
params: [this.getAddress(), encoded],
|
|
4089
|
+
chainId: (options == null ? void 0 : options.chainId) || typedData.domain.chainId && Number(typedData.domain.chainId) || this.getChainId()
|
|
4090
|
+
});
|
|
4093
4091
|
}
|
|
4094
4092
|
async sendTransaction(tx, options) {
|
|
4095
4093
|
var _this$analytics6;
|
|
@@ -4101,22 +4099,24 @@ class SequenceClient {
|
|
|
4101
4099
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4102
4100
|
}
|
|
4103
4101
|
});
|
|
4104
|
-
return this.
|
|
4102
|
+
return this.request({
|
|
4105
4103
|
method: 'eth_sendTransaction',
|
|
4106
|
-
params: [extendedTxs]
|
|
4107
|
-
|
|
4104
|
+
params: [extendedTxs],
|
|
4105
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4106
|
+
});
|
|
4108
4107
|
}
|
|
4109
4108
|
async getWalletContext() {
|
|
4110
|
-
return this.
|
|
4109
|
+
return this.request({
|
|
4111
4110
|
method: 'sequence_getWalletContext'
|
|
4112
4111
|
});
|
|
4113
4112
|
}
|
|
4114
4113
|
async getOnchainWalletConfig(options) {
|
|
4115
4114
|
// NOTICE: sequence_getWalletConfig sends the chainId as a param
|
|
4116
|
-
const res = await this.
|
|
4115
|
+
const res = await this.request({
|
|
4117
4116
|
method: 'sequence_getWalletConfig',
|
|
4118
|
-
params: [(options == null ? void 0 : options.chainId) || this.getChainId()]
|
|
4119
|
-
|
|
4117
|
+
params: [(options == null ? void 0 : options.chainId) || this.getChainId()],
|
|
4118
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4119
|
+
});
|
|
4120
4120
|
return Array.isArray(res) ? res[0] : res;
|
|
4121
4121
|
}
|
|
4122
4122
|
|
|
@@ -4126,6 +4126,14 @@ class SequenceClient {
|
|
|
4126
4126
|
// exclusively used for Sequence specific methods
|
|
4127
4127
|
}
|
|
4128
4128
|
|
|
4129
|
+
// Unwrap a JsonRpcResponse result
|
|
4130
|
+
const unwrapJsonRpcResponse = response => {
|
|
4131
|
+
if (response && typeof response === 'object' && 'jsonrpc' in response && 'result' in response) {
|
|
4132
|
+
return response.result;
|
|
4133
|
+
}
|
|
4134
|
+
return response;
|
|
4135
|
+
};
|
|
4136
|
+
|
|
4129
4137
|
const DefaultProviderConfig = {
|
|
4130
4138
|
transports: {
|
|
4131
4139
|
walletAppURL: 'https://sequence.app',
|
|
@@ -4195,9 +4203,11 @@ const initWallet = (projectAccessKey, partialConfig) => {
|
|
|
4195
4203
|
if (!rpcUrl) {
|
|
4196
4204
|
throw new Error(`no rpcUrl found for chainId: ${chainId}`);
|
|
4197
4205
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4206
|
+
rpcProviders[chainId] = new JsonRpcProvider(rpcUrl, {
|
|
4207
|
+
middlewares: [loggingProviderMiddleware, exceptionProviderMiddleware, new CachedProvider()]
|
|
4208
|
+
}, {
|
|
4209
|
+
cacheTimeout: -1
|
|
4210
|
+
});
|
|
4201
4211
|
}
|
|
4202
4212
|
return rpcProviders[chainId];
|
|
4203
4213
|
};
|