@0xsequence/provider 0.0.0-20240408185635 → 0.0.0-20240428001038
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 +685 -692
- package/dist/0xsequence-provider.cjs.prod.js +685 -692
- package/dist/0xsequence-provider.esm.js +687 -695
- package/dist/declarations/src/client.d.ts +3 -7
- package/dist/declarations/src/index.d.ts +1 -0
- package/dist/declarations/src/provider.d.ts +22 -31
- package/dist/declarations/src/signer.d.ts +14 -15
- package/dist/declarations/src/transactions.d.ts +2 -0
- package/dist/declarations/src/transports/base-provider-transport.d.ts +2 -6
- package/dist/declarations/src/transports/base-wallet-transport.d.ts +2 -6
- package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +2 -5
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +6 -7
- package/dist/declarations/src/types.d.ts +11 -6
- 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 +53 -32
- package/src/eip191exceptions.ts +2 -2
- package/src/extended.ts +5 -5
- package/src/index.ts +1 -0
- package/src/init.ts +10 -9
- package/src/provider.ts +66 -114
- package/src/signer.ts +43 -46
- package/src/transactions.ts +25 -2
- package/src/transports/base-provider-transport.ts +23 -19
- package/src/transports/base-wallet-transport.ts +13 -22
- package/src/transports/mux-transport/mux-message-provider.ts +6 -5
- package/src/transports/proxy-transport/proxy-message-provider.ts +2 -5
- package/src/transports/wallet-request-handler.ts +131 -91
- package/src/transports/window-transport/window-message-handler.ts +3 -17
- package/src/transports/window-transport/window-message-provider.ts +1 -1
- package/src/types.ts +11 -8
- package/src/utils/index.ts +4 -4
- package/src/utils.ts +18 -16
|
@@ -2,15 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var abi = require('@0xsequence/abi');
|
|
6
|
+
var core = require('@0xsequence/core');
|
|
7
|
+
var ethers = require('ethers');
|
|
5
8
|
var eventemitter2 = require('eventemitter2');
|
|
6
9
|
var utils = require('@0xsequence/utils');
|
|
7
|
-
var ethers = require('ethers');
|
|
8
|
-
var core = require('@0xsequence/core');
|
|
9
10
|
var network = require('@0xsequence/network');
|
|
10
11
|
var auth = require('@0xsequence/auth');
|
|
11
|
-
var abi = require('@0xsequence/abi');
|
|
12
12
|
var tracker = require('@databeat/tracker');
|
|
13
13
|
|
|
14
|
+
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.ethers.utils.keccak256(ethers.ethers.utils.toUtf8Bytes(signature)).slice(0, 10), signature]));
|
|
15
|
+
function validateTransactionRequest(wallet, transaction) {
|
|
16
|
+
const transactions = core.commons.transaction.fromTransactionish(wallet, transaction);
|
|
17
|
+
const unwound = core.commons.transaction.unwind(wallet, transactions);
|
|
18
|
+
unwound.forEach(transaction => validateTransaction(wallet, transaction));
|
|
19
|
+
}
|
|
20
|
+
function validateTransaction(wallet, transaction) {
|
|
21
|
+
if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
|
|
22
|
+
if (transaction.data) {
|
|
23
|
+
const data = ethers.ethers.utils.arrayify(transaction.data);
|
|
24
|
+
if (data.length >= 4 && !isCreateContractCall(data)) {
|
|
25
|
+
throw new Error('self calls are forbidden');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (transaction.delegateCall) {
|
|
30
|
+
throw new Error('delegate calls are forbidden');
|
|
31
|
+
}
|
|
32
|
+
if (transaction.data) {
|
|
33
|
+
const data = ethers.ethers.utils.hexlify(transaction.data);
|
|
34
|
+
const selector = data.slice(0, 10);
|
|
35
|
+
const signature = PROHIBITED_FUNCTIONS.get(selector);
|
|
36
|
+
if (signature) {
|
|
37
|
+
const name = signature.slice(0, signature.indexOf('('));
|
|
38
|
+
throw new Error(`${name} calls are forbidden`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isCreateContractCall(data) {
|
|
43
|
+
const walletInterface = new ethers.ethers.utils.Interface(abi.walletContracts.mainModule.abi);
|
|
44
|
+
try {
|
|
45
|
+
walletInterface.decodeFunctionData('createContract', data);
|
|
46
|
+
return true;
|
|
47
|
+
} catch (_unused) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
14
52
|
function _extends() {
|
|
15
53
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
16
54
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -30,8 +68,6 @@ function isProviderTransport(transport) {
|
|
|
30
68
|
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';
|
|
31
69
|
}
|
|
32
70
|
|
|
33
|
-
// Older versions of sequence.js will require a JsonRpcResponse result type, but newer versions use raw EIP1193 results
|
|
34
|
-
|
|
35
71
|
// ProviderMessageCallback is used to respond to ProviderMessage requests. The error
|
|
36
72
|
// argument is for exceptions during the execution, and response is the response payload
|
|
37
73
|
// which may contain the result or an error payload from the wallet.
|
|
@@ -89,6 +125,8 @@ const ErrSignedInRequired = new ProviderError('Wallet is not signed in. Connect
|
|
|
89
125
|
|
|
90
126
|
// TODO: lets build some nice error handling tools, prob in /utils ...
|
|
91
127
|
|
|
128
|
+
// This is required by viem, it expects a provider to have an EIP-1193 compliant `request` attribute.
|
|
129
|
+
|
|
92
130
|
const PROVIDER_OPEN_TIMEOUT = 30000; // in ms
|
|
93
131
|
|
|
94
132
|
let _messageIdx = 0;
|
|
@@ -109,6 +147,42 @@ class BaseProviderTransport {
|
|
|
109
147
|
this._sessionId = void 0;
|
|
110
148
|
this._init = void 0;
|
|
111
149
|
this._registered = void 0;
|
|
150
|
+
this.sendAsync = async function (request, callback, chainId) {
|
|
151
|
+
// here, we receive the message from the dapp provider call
|
|
152
|
+
|
|
153
|
+
if (_this.state === OpenState.CLOSED) {
|
|
154
|
+
// flag the wallet to auto-close once user submits input. ie.
|
|
155
|
+
// prompting to sign a message or transaction
|
|
156
|
+
_this.confirmationOnly = true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// open/focus the wallet.
|
|
160
|
+
// automatically open the wallet when a provider request makes it here.
|
|
161
|
+
//
|
|
162
|
+
// NOTE: if we're not signed in, then the provider will fail, users must first connect+sign in.
|
|
163
|
+
//
|
|
164
|
+
// TODO: how does this behave with a session has expired?
|
|
165
|
+
_this.openWallet(undefined, {
|
|
166
|
+
type: 'jsonRpcRequest',
|
|
167
|
+
method: request.method
|
|
168
|
+
}, chainId);
|
|
169
|
+
|
|
170
|
+
// send message request, await, and then execute callback after receiving the response
|
|
171
|
+
try {
|
|
172
|
+
if (!_this.isOpened()) {
|
|
173
|
+
await _this.waitUntilOpened(); // will throw on timeout
|
|
174
|
+
}
|
|
175
|
+
const response = await _this.sendMessageRequest({
|
|
176
|
+
idx: nextMessageIdx(),
|
|
177
|
+
type: EventType.MESSAGE,
|
|
178
|
+
data: request,
|
|
179
|
+
chainId: chainId
|
|
180
|
+
});
|
|
181
|
+
callback(undefined, response.data);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
callback(err);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
112
186
|
// sendMessageRequest sends a ProviderMessageRequest over the wire to the wallet
|
|
113
187
|
this.sendMessageRequest = async function (message) {
|
|
114
188
|
return new Promise((resolve, reject) => {
|
|
@@ -218,36 +292,6 @@ class BaseProviderTransport {
|
|
|
218
292
|
const session = (_this$openPayload2 = this.openPayload) == null ? void 0 : _this$openPayload2.session;
|
|
219
293
|
return this.registered && session !== undefined && !!session.accountAddress && session.accountAddress.length === 42 && !!session.networks && session.networks.length > 0;
|
|
220
294
|
}
|
|
221
|
-
async request(request) {
|
|
222
|
-
if (this.state === OpenState.CLOSED) {
|
|
223
|
-
// flag the wallet to auto-close once user submits input. ie.
|
|
224
|
-
// prompting to sign a message or transaction
|
|
225
|
-
this.confirmationOnly = true;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// open/focus the wallet.
|
|
229
|
-
// automatically open the wallet when a provider request makes it here.
|
|
230
|
-
//
|
|
231
|
-
// NOTE: if we're not signed in, then the provider will fail, users must first connect+sign in.
|
|
232
|
-
//
|
|
233
|
-
// TODO: how does this behave with a session has expired?
|
|
234
|
-
this.openWallet(undefined, {
|
|
235
|
-
type: 'jsonRpcRequest',
|
|
236
|
-
method: request.method
|
|
237
|
-
}, request.chainId);
|
|
238
|
-
if (!this.isOpened()) {
|
|
239
|
-
await this.waitUntilOpened(); // will throw on timeout
|
|
240
|
-
}
|
|
241
|
-
const response = await this.sendMessageRequest({
|
|
242
|
-
idx: nextMessageIdx(),
|
|
243
|
-
type: EventType.MESSAGE,
|
|
244
|
-
data: request,
|
|
245
|
-
chainId: request.chainId,
|
|
246
|
-
clientVersion: core.VERSION
|
|
247
|
-
});
|
|
248
|
-
return response.data;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
295
|
// handleMessage will handle message received from the remote wallet
|
|
252
296
|
handleMessage(message) {
|
|
253
297
|
var _this2 = this;
|
|
@@ -269,8 +313,7 @@ class BaseProviderTransport {
|
|
|
269
313
|
data: {
|
|
270
314
|
sessionId: this._sessionId,
|
|
271
315
|
nonce: nonce
|
|
272
|
-
}
|
|
273
|
-
clientVersion: core.VERSION
|
|
316
|
+
}
|
|
274
317
|
});
|
|
275
318
|
}
|
|
276
319
|
if (this._init !== InitState.OK) {
|
|
@@ -355,7 +398,7 @@ class BaseProviderTransport {
|
|
|
355
398
|
};
|
|
356
399
|
if (message.data && message.data.length > 0) {
|
|
357
400
|
this.accountsChangedPayload = {
|
|
358
|
-
accounts: [ethers.ethers.getAddress(message.data[0])],
|
|
401
|
+
accounts: [ethers.ethers.utils.getAddress(message.data[0])],
|
|
359
402
|
origin: message.origin
|
|
360
403
|
};
|
|
361
404
|
this.events.emit('accountsChanged', this.accountsChangedPayload.accounts, this.accountsChangedPayload.origin);
|
|
@@ -460,7 +503,7 @@ const EIP_191_PREFIX_EXCEPTIONS = [
|
|
|
460
503
|
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)?)$/;
|
|
461
504
|
function isDecentralandLoginMessage(bytes) {
|
|
462
505
|
try {
|
|
463
|
-
const stringified = ethers.ethers.toUtf8String(bytes);
|
|
506
|
+
const stringified = ethers.ethers.utils.toUtf8String(bytes);
|
|
464
507
|
return DCL_REGEX.test(stringified);
|
|
465
508
|
} catch (_unused) {
|
|
466
509
|
return false;
|
|
@@ -470,7 +513,7 @@ function isDecentralandLoginMessage(bytes) {
|
|
|
470
513
|
// try to interpret bytes as abi-encoded 0x v3 OrderWithHash -
|
|
471
514
|
// see https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md
|
|
472
515
|
function isZeroExV3Order(bytes) {
|
|
473
|
-
const abi = new ethers.ethers.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
516
|
+
const abi = new ethers.ethers.utils.Interface(ZeroXV3EIP1271OrderWithHashAbi);
|
|
474
517
|
try {
|
|
475
518
|
abi.decodeFunctionData('OrderWithHash', bytes);
|
|
476
519
|
return true;
|
|
@@ -552,19 +595,19 @@ const ZeroXV3EIP1271OrderWithHashAbi = [{
|
|
|
552
595
|
type: 'function'
|
|
553
596
|
}];
|
|
554
597
|
|
|
555
|
-
const eip191prefix = ethers.ethers.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
598
|
+
const eip191prefix = ethers.ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n');
|
|
556
599
|
const messageToBytes = message => {
|
|
557
|
-
if (ethers.ethers.isBytesLike(message)) {
|
|
558
|
-
return ethers.ethers.
|
|
600
|
+
if (ethers.ethers.utils.isBytesLike(message)) {
|
|
601
|
+
return ethers.ethers.utils.arrayify(message);
|
|
559
602
|
}
|
|
560
|
-
return ethers.ethers.toUtf8Bytes(message);
|
|
603
|
+
return ethers.ethers.utils.toUtf8Bytes(message);
|
|
561
604
|
};
|
|
562
605
|
const prefixEIP191Message = message => {
|
|
563
606
|
const messageBytes = messageToBytes(message);
|
|
564
607
|
if (messageIsExemptFromEIP191Prefix(messageBytes)) {
|
|
565
608
|
return messageBytes;
|
|
566
609
|
} else {
|
|
567
|
-
return ethers.ethers.
|
|
610
|
+
return ethers.ethers.utils.concat([eip191prefix, ethers.ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes]);
|
|
568
611
|
}
|
|
569
612
|
};
|
|
570
613
|
const trimEIP191Prefix = prefixedMessage => {
|
|
@@ -589,9 +632,9 @@ const trimEIP191Prefix = prefixedMessage => {
|
|
|
589
632
|
let prefixCharLenght;
|
|
590
633
|
let prefixAsNumber;
|
|
591
634
|
try {
|
|
592
|
-
prefixAsNumber = Number(ethers.ethers.toUtf8String(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
635
|
+
prefixAsNumber = Number(ethers.ethers.utils.toUtf8String(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
593
636
|
} catch (_unused) {
|
|
594
|
-
prefixAsNumber = Number(ethers.ethers.hexlify(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
637
|
+
prefixAsNumber = Number(ethers.ethers.utils.hexlify(ethereumSignedMessagePartSlicedArray.slice(0, maxPrefixCharLength)));
|
|
595
638
|
}
|
|
596
639
|
if (prefixAsNumber > ethereumSignedMessagePartSlicedArray.length || !Number.isInteger(prefixAsNumber)) {
|
|
597
640
|
prefixCharLenght = maxPrefixCharLength - 1;
|
|
@@ -706,9 +749,9 @@ function useBestStore() {
|
|
|
706
749
|
async function resolveArrayProperties(object) {
|
|
707
750
|
if (Array.isArray(object)) {
|
|
708
751
|
// T must include array type
|
|
709
|
-
return Promise.all(object.map(o => ethers.ethers.resolveProperties(o)));
|
|
752
|
+
return Promise.all(object.map(o => ethers.ethers.utils.resolveProperties(o)));
|
|
710
753
|
}
|
|
711
|
-
return ethers.ethers.resolveProperties(object);
|
|
754
|
+
return ethers.ethers.utils.resolveProperties(object);
|
|
712
755
|
}
|
|
713
756
|
|
|
714
757
|
const TRANSPORT_SESSION_LS_KEY = '@sequence.transportSession';
|
|
@@ -725,6 +768,9 @@ class BaseWalletTransport {
|
|
|
725
768
|
// will auto-detect and set this value if it can. This is determined
|
|
726
769
|
// as the parent app/window which opened the wallet.
|
|
727
770
|
this.appOrigin = void 0;
|
|
771
|
+
this.sendAsync = async function (request, callback, chainId) {
|
|
772
|
+
throw new Error('abstract method');
|
|
773
|
+
};
|
|
728
774
|
this.handleMessage = async function (message) {
|
|
729
775
|
const request = message;
|
|
730
776
|
|
|
@@ -960,7 +1006,7 @@ class BaseWalletTransport {
|
|
|
960
1006
|
if (!networks || networks.length === 0) {
|
|
961
1007
|
this.notifyChainChanged('0x0');
|
|
962
1008
|
} else {
|
|
963
|
-
this.notifyChainChanged(ethers.ethers.
|
|
1009
|
+
this.notifyChainChanged(ethers.ethers.utils.hexValue(networks.find(network => network.isDefaultChain).chainId));
|
|
964
1010
|
}
|
|
965
1011
|
});
|
|
966
1012
|
this.walletRequestHandler.on('chainChanged', (chainIdHex, origin) => {
|
|
@@ -984,9 +1030,6 @@ class BaseWalletTransport {
|
|
|
984
1030
|
unregister() {
|
|
985
1031
|
throw new Error('abstract method');
|
|
986
1032
|
}
|
|
987
|
-
request(request) {
|
|
988
|
-
throw new Error('abstract method');
|
|
989
|
-
}
|
|
990
1033
|
sendMessage(message) {
|
|
991
1034
|
throw new Error('abstract method');
|
|
992
1035
|
}
|
|
@@ -1005,8 +1048,7 @@ class BaseWalletTransport {
|
|
|
1005
1048
|
sessionId,
|
|
1006
1049
|
session,
|
|
1007
1050
|
error
|
|
1008
|
-
}
|
|
1009
|
-
clientVersion: core.VERSION
|
|
1051
|
+
}
|
|
1010
1052
|
});
|
|
1011
1053
|
}
|
|
1012
1054
|
notifyClose(error) {
|
|
@@ -1015,16 +1057,14 @@ class BaseWalletTransport {
|
|
|
1015
1057
|
type: EventType.CLOSE,
|
|
1016
1058
|
data: error ? {
|
|
1017
1059
|
error
|
|
1018
|
-
} : null
|
|
1019
|
-
clientVersion: core.VERSION
|
|
1060
|
+
} : null
|
|
1020
1061
|
});
|
|
1021
1062
|
}
|
|
1022
1063
|
notifyConnect(connectDetails) {
|
|
1023
1064
|
this.sendMessage({
|
|
1024
1065
|
idx: -1,
|
|
1025
1066
|
type: EventType.CONNECT,
|
|
1026
|
-
data: connectDetails
|
|
1027
|
-
clientVersion: core.VERSION
|
|
1067
|
+
data: connectDetails
|
|
1028
1068
|
});
|
|
1029
1069
|
}
|
|
1030
1070
|
notifyDisconnect(error, origin) {
|
|
@@ -1034,8 +1074,7 @@ class BaseWalletTransport {
|
|
|
1034
1074
|
data: error ? {
|
|
1035
1075
|
error
|
|
1036
1076
|
} : null,
|
|
1037
|
-
origin
|
|
1038
|
-
clientVersion: core.VERSION
|
|
1077
|
+
origin
|
|
1039
1078
|
});
|
|
1040
1079
|
}
|
|
1041
1080
|
notifyAccountsChanged(accounts, origin) {
|
|
@@ -1043,8 +1082,7 @@ class BaseWalletTransport {
|
|
|
1043
1082
|
idx: -1,
|
|
1044
1083
|
type: EventType.ACCOUNTS_CHANGED,
|
|
1045
1084
|
data: accounts,
|
|
1046
|
-
origin
|
|
1047
|
-
clientVersion: core.VERSION
|
|
1085
|
+
origin
|
|
1048
1086
|
});
|
|
1049
1087
|
}
|
|
1050
1088
|
notifyChainChanged(chainIdHex, origin) {
|
|
@@ -1052,24 +1090,21 @@ class BaseWalletTransport {
|
|
|
1052
1090
|
idx: -1,
|
|
1053
1091
|
type: EventType.CHAIN_CHANGED,
|
|
1054
1092
|
data: chainIdHex,
|
|
1055
|
-
origin
|
|
1056
|
-
clientVersion: core.VERSION
|
|
1093
|
+
origin
|
|
1057
1094
|
});
|
|
1058
1095
|
}
|
|
1059
1096
|
notifyNetworks(networks) {
|
|
1060
1097
|
this.sendMessage({
|
|
1061
1098
|
idx: -1,
|
|
1062
1099
|
type: EventType.NETWORKS,
|
|
1063
|
-
data: networks
|
|
1064
|
-
clientVersion: core.VERSION
|
|
1100
|
+
data: networks
|
|
1065
1101
|
});
|
|
1066
1102
|
}
|
|
1067
1103
|
notifyWalletContext(walletContext) {
|
|
1068
1104
|
this.sendMessage({
|
|
1069
1105
|
idx: -1,
|
|
1070
1106
|
type: EventType.WALLET_CONTEXT,
|
|
1071
|
-
data: walletContext
|
|
1072
|
-
clientVersion: core.VERSION
|
|
1107
|
+
data: walletContext
|
|
1073
1108
|
});
|
|
1074
1109
|
}
|
|
1075
1110
|
isValidInitAck(message) {
|
|
@@ -1140,8 +1175,7 @@ class BaseWalletTransport {
|
|
|
1140
1175
|
type: EventType.INIT,
|
|
1141
1176
|
data: {
|
|
1142
1177
|
nonce: this._initNonce
|
|
1143
|
-
}
|
|
1144
|
-
clientVersion: core.VERSION
|
|
1178
|
+
}
|
|
1145
1179
|
});
|
|
1146
1180
|
this._init = InitState.SENT_NONCE;
|
|
1147
1181
|
|
|
@@ -1240,8 +1274,7 @@ class ProxyMessageProvider extends BaseProviderTransport {
|
|
|
1240
1274
|
intent,
|
|
1241
1275
|
networkId,
|
|
1242
1276
|
sessionId
|
|
1243
|
-
}
|
|
1244
|
-
clientVersion: core.VERSION
|
|
1277
|
+
}
|
|
1245
1278
|
});
|
|
1246
1279
|
}
|
|
1247
1280
|
};
|
|
@@ -1259,8 +1292,7 @@ class ProxyMessageProvider extends BaseProviderTransport {
|
|
|
1259
1292
|
this.sendMessage({
|
|
1260
1293
|
idx: -1,
|
|
1261
1294
|
type: EventType.CLOSE,
|
|
1262
|
-
data: null
|
|
1263
|
-
clientVersion: core.VERSION
|
|
1295
|
+
data: null
|
|
1264
1296
|
});
|
|
1265
1297
|
this.close();
|
|
1266
1298
|
}
|
|
@@ -1848,13 +1880,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1848
1880
|
// Wallet always expects json-rpc request messages from a dapp
|
|
1849
1881
|
let request;
|
|
1850
1882
|
try {
|
|
1851
|
-
request = JSON.parse(event.data
|
|
1852
|
-
// BigNumber compatibility with older versions of sequence.js
|
|
1853
|
-
if (isBigNumberSerialized(value)) {
|
|
1854
|
-
return BigInt(value.hex);
|
|
1855
|
-
}
|
|
1856
|
-
return value;
|
|
1857
|
-
});
|
|
1883
|
+
request = JSON.parse(event.data);
|
|
1858
1884
|
} catch (err) {
|
|
1859
1885
|
// event is not a ProviderMessage JSON object, skip
|
|
1860
1886
|
return;
|
|
@@ -1893,6 +1919,7 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1893
1919
|
|
|
1894
1920
|
// record open details (sessionId + default network) from the window url
|
|
1895
1921
|
const {
|
|
1922
|
+
pathname,
|
|
1896
1923
|
search: rawParams
|
|
1897
1924
|
} = new URL(windowHref || window.location.href);
|
|
1898
1925
|
let session = this.getWindowTransportSession(rawParams);
|
|
@@ -1976,9 +2003,6 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1976
2003
|
}
|
|
1977
2004
|
}
|
|
1978
2005
|
}
|
|
1979
|
-
const isBigNumberSerialized = value => {
|
|
1980
|
-
return typeof value === 'object' && 'type' in value && value.type === 'BigNumber' && 'hex' in value && ethers.ethers.isHexString(value.hex);
|
|
1981
|
-
};
|
|
1982
2006
|
|
|
1983
2007
|
function isMuxTransportTemplate(obj) {
|
|
1984
2008
|
return obj && typeof obj === 'object' && (obj.windowTransport && typeof obj.windowTransport === 'object' || obj.proxyTransport && typeof obj.proxyTransport === 'object' || obj.extensionTransport && typeof obj.extensionTransport === 'object' || obj.unrealTransport && typeof obj.unrealTransport === 'object') && (
|
|
@@ -2029,6 +2053,13 @@ class MuxMessageProvider {
|
|
|
2029
2053
|
}
|
|
2030
2054
|
this.messageProviders.forEach(m => m.openWallet(path, intent, networkId));
|
|
2031
2055
|
};
|
|
2056
|
+
this.sendAsync = async function (request, callback, chainId) {
|
|
2057
|
+
if (_this.provider) {
|
|
2058
|
+
_this.provider.sendAsync(request, callback, chainId);
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
2061
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
2062
|
+
};
|
|
2032
2063
|
this.sendMessageRequest = async function (message) {
|
|
2033
2064
|
if (_this.provider) {
|
|
2034
2065
|
return _this.provider.sendMessageRequest(message);
|
|
@@ -2125,12 +2156,6 @@ class MuxMessageProvider {
|
|
|
2125
2156
|
}
|
|
2126
2157
|
return true;
|
|
2127
2158
|
}
|
|
2128
|
-
request(request) {
|
|
2129
|
-
if (!this.provider) {
|
|
2130
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
2131
|
-
}
|
|
2132
|
-
return this.provider.request(request);
|
|
2133
|
-
}
|
|
2134
2159
|
sendMessage(message) {
|
|
2135
2160
|
if (!message.idx || message.idx <= 0) {
|
|
2136
2161
|
throw new Error('message idx is empty');
|
|
@@ -2163,37 +2188,9 @@ function fromExtended(transaction) {
|
|
|
2163
2188
|
return [transaction, ...(transaction.auxiliary || [])];
|
|
2164
2189
|
}
|
|
2165
2190
|
|
|
2166
|
-
function validateTransactionRequest(wallet, transaction) {
|
|
2167
|
-
const transactions = core.commons.transaction.fromTransactionish(wallet, transaction);
|
|
2168
|
-
const unwound = core.commons.transaction.unwind(wallet, transactions);
|
|
2169
|
-
unwound.forEach(transaction => validateTransaction(wallet, transaction));
|
|
2170
|
-
}
|
|
2171
|
-
function validateTransaction(wallet, transaction) {
|
|
2172
|
-
if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
|
|
2173
|
-
if (transaction.data) {
|
|
2174
|
-
const data = ethers.ethers.getBytes(transaction.data);
|
|
2175
|
-
if (data.length >= 4 && !isCreateContractCall(data)) {
|
|
2176
|
-
throw new Error('self calls are forbidden');
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
}
|
|
2180
|
-
if (transaction.delegateCall) {
|
|
2181
|
-
throw new Error('delegate calls are forbidden');
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
function isCreateContractCall(data) {
|
|
2185
|
-
const walletInterface = new ethers.ethers.Interface(abi.walletContracts.mainModule.abi);
|
|
2186
|
-
try {
|
|
2187
|
-
walletInterface.decodeFunctionData('createContract', data);
|
|
2188
|
-
return true;
|
|
2189
|
-
} catch (_unused) {
|
|
2190
|
-
return false;
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2193
|
-
|
|
2194
2191
|
const SIGNER_READY_TIMEOUT = 10000;
|
|
2195
2192
|
class WalletRequestHandler {
|
|
2196
|
-
constructor(
|
|
2193
|
+
constructor(_account, prompter, networks) {
|
|
2197
2194
|
var _this = this;
|
|
2198
2195
|
// signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
|
|
2199
2196
|
// value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
|
|
@@ -2226,6 +2223,417 @@ class WalletRequestHandler {
|
|
|
2226
2223
|
}
|
|
2227
2224
|
return promptConnectDetails;
|
|
2228
2225
|
};
|
|
2226
|
+
// sendAsync implements the JsonRpcHandler interface for sending JsonRpcRequests to the wallet
|
|
2227
|
+
this.sendAsync = async function (request, callback, chainId) {
|
|
2228
|
+
const response = {
|
|
2229
|
+
jsonrpc: '2.0',
|
|
2230
|
+
id: request.id,
|
|
2231
|
+
result: null
|
|
2232
|
+
};
|
|
2233
|
+
await _this.getAccount();
|
|
2234
|
+
try {
|
|
2235
|
+
var _this$account;
|
|
2236
|
+
// only allow public json rpc method to the provider when user is not logged in, aka signer is not set
|
|
2237
|
+
if ((!_this.account || _this.account === null) && !permittedJsonRpcMethods.includes(request.method)) {
|
|
2238
|
+
// throw new Error(`not logged in. ${request.method} is unavailable`)
|
|
2239
|
+
throw ErrSignedInRequired;
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
// wallet account
|
|
2243
|
+
const account = _this.account;
|
|
2244
|
+
if (!account) throw new Error('WalletRequestHandler: wallet account is not configured');
|
|
2245
|
+
|
|
2246
|
+
// fetch the provider for the specific chain, or undefined will select defaultChain
|
|
2247
|
+
const provider = (_this$account = _this.account) == null ? void 0 : _this$account.providerFor(chainId != null ? chainId : _this.defaultChainId());
|
|
2248
|
+
if (!provider) throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${chainId}`);
|
|
2249
|
+
const jsonRpcProvider = provider instanceof ethers.ethers.providers.JsonRpcProvider ? provider : undefined;
|
|
2250
|
+
switch (request.method) {
|
|
2251
|
+
case 'net_version':
|
|
2252
|
+
{
|
|
2253
|
+
if (!jsonRpcProvider) {
|
|
2254
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2255
|
+
}
|
|
2256
|
+
const result = await jsonRpcProvider.send('net_version', []);
|
|
2257
|
+
response.result = result;
|
|
2258
|
+
break;
|
|
2259
|
+
}
|
|
2260
|
+
case 'eth_chainId':
|
|
2261
|
+
{
|
|
2262
|
+
if (!jsonRpcProvider) {
|
|
2263
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2264
|
+
}
|
|
2265
|
+
const result = await jsonRpcProvider.send('eth_chainId', []);
|
|
2266
|
+
response.result = result;
|
|
2267
|
+
break;
|
|
2268
|
+
}
|
|
2269
|
+
case 'eth_accounts':
|
|
2270
|
+
{
|
|
2271
|
+
const walletAddress = account.address;
|
|
2272
|
+
response.result = [walletAddress];
|
|
2273
|
+
break;
|
|
2274
|
+
}
|
|
2275
|
+
case 'eth_getBalance':
|
|
2276
|
+
{
|
|
2277
|
+
const [accountAddress, blockTag] = request.params;
|
|
2278
|
+
const walletBalance = await provider.getBalance(accountAddress, blockTag);
|
|
2279
|
+
response.result = walletBalance.toHexString();
|
|
2280
|
+
break;
|
|
2281
|
+
}
|
|
2282
|
+
case 'sequence_sign':
|
|
2283
|
+
case 'personal_sign':
|
|
2284
|
+
case 'eth_sign':
|
|
2285
|
+
{
|
|
2286
|
+
// note: message from json-rpc input is in hex format
|
|
2287
|
+
let message;
|
|
2288
|
+
|
|
2289
|
+
// there is a difference in the order of the params:
|
|
2290
|
+
// sequence_sign, personal_sign: [data, address]
|
|
2291
|
+
// eth_sign: [address, data]
|
|
2292
|
+
switch (request.method) {
|
|
2293
|
+
case 'sequence_sign':
|
|
2294
|
+
case 'personal_sign':
|
|
2295
|
+
{
|
|
2296
|
+
const [data, _address] = request.params;
|
|
2297
|
+
message = data;
|
|
2298
|
+
break;
|
|
2299
|
+
}
|
|
2300
|
+
case 'eth_sign':
|
|
2301
|
+
{
|
|
2302
|
+
const [_address, data] = request.params;
|
|
2303
|
+
message = data;
|
|
2304
|
+
break;
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
let sig = '';
|
|
2308
|
+
|
|
2309
|
+
// Message must be prefixed with "\x19Ethereum Signed Message:\n"
|
|
2310
|
+
// as defined by EIP-191
|
|
2311
|
+
const prefixedMessage = prefixEIP191Message(message);
|
|
2312
|
+
|
|
2313
|
+
// TODO:
|
|
2314
|
+
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
2315
|
+
const sequenceVerified = request.method === 'sequence_sign';
|
|
2316
|
+
if (_this.prompter === null) {
|
|
2317
|
+
// prompter is null, so we'll sign from here
|
|
2318
|
+
sig = await account.signMessage(prefixedMessage, chainId != null ? chainId : _this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2319
|
+
} else {
|
|
2320
|
+
sig = await _this.prompter.promptSignMessage({
|
|
2321
|
+
chainId: chainId,
|
|
2322
|
+
message: prefixedMessage,
|
|
2323
|
+
eip6492: sequenceVerified
|
|
2324
|
+
}, _this.connectOptions);
|
|
2325
|
+
}
|
|
2326
|
+
if (sig && sig.length > 0) {
|
|
2327
|
+
response.result = sig;
|
|
2328
|
+
} else {
|
|
2329
|
+
// The user has declined the request when value is null
|
|
2330
|
+
throw new Error('declined by user');
|
|
2331
|
+
}
|
|
2332
|
+
break;
|
|
2333
|
+
}
|
|
2334
|
+
case 'sequence_signTypedData_v4':
|
|
2335
|
+
case 'eth_signTypedData':
|
|
2336
|
+
case 'eth_signTypedData_v4':
|
|
2337
|
+
{
|
|
2338
|
+
// note: signingAddress from json-rpc input is in hex format, and typedDataObject
|
|
2339
|
+
// should be an object, but in some instances may be double string encoded
|
|
2340
|
+
const [signingAddress, typedDataObject] = request.params;
|
|
2341
|
+
let typedData = undefined;
|
|
2342
|
+
if (typeof typedDataObject === 'string') {
|
|
2343
|
+
try {
|
|
2344
|
+
typedData = JSON.parse(typedDataObject);
|
|
2345
|
+
} catch (e) {
|
|
2346
|
+
console.warn('walletRequestHandler: error parsing typedData', e);
|
|
2347
|
+
}
|
|
2348
|
+
} else {
|
|
2349
|
+
typedData = typedDataObject;
|
|
2350
|
+
}
|
|
2351
|
+
if (!typedData || !typedData.domain || !typedData.types || !typedData.message) {
|
|
2352
|
+
throw new Error('invalid typedData object');
|
|
2353
|
+
}
|
|
2354
|
+
let sig = '';
|
|
2355
|
+
const sequenceVerified = request.method === 'sequence_signTypedData_v4';
|
|
2356
|
+
if (_this.prompter === null) {
|
|
2357
|
+
// prompter is null, so we'll sign from here
|
|
2358
|
+
sig = await account.signTypedData(typedData.domain, typedData.types, typedData.message, chainId != null ? chainId : _this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2359
|
+
} else {
|
|
2360
|
+
sig = await _this.prompter.promptSignMessage({
|
|
2361
|
+
chainId: chainId,
|
|
2362
|
+
typedData: typedData,
|
|
2363
|
+
eip6492: sequenceVerified
|
|
2364
|
+
}, _this.connectOptions);
|
|
2365
|
+
}
|
|
2366
|
+
if (sig && sig.length > 0) {
|
|
2367
|
+
response.result = sig;
|
|
2368
|
+
} else {
|
|
2369
|
+
// The user has declined the request when value is null
|
|
2370
|
+
throw new Error('declined by user');
|
|
2371
|
+
}
|
|
2372
|
+
break;
|
|
2373
|
+
}
|
|
2374
|
+
case 'eth_sendTransaction':
|
|
2375
|
+
{
|
|
2376
|
+
// https://eth.wiki/json-rpc/API#eth_sendtransaction
|
|
2377
|
+
const transactionParams = fromExtended(request.params[0]).map(tx => {
|
|
2378
|
+
// eth_sendTransaction uses 'gas'
|
|
2379
|
+
// ethers and sequence use 'gasLimit'
|
|
2380
|
+
if ('gas' in tx && tx.gasLimit === undefined) {
|
|
2381
|
+
tx.gasLimit = tx.gas;
|
|
2382
|
+
delete tx.gas;
|
|
2383
|
+
}
|
|
2384
|
+
return tx;
|
|
2385
|
+
});
|
|
2386
|
+
validateTransactionRequest(account.address, transactionParams);
|
|
2387
|
+
let txnHash = '';
|
|
2388
|
+
if (_this.prompter === null) {
|
|
2389
|
+
var _txnResponse$hash;
|
|
2390
|
+
// prompter is null, so we'll send from here
|
|
2391
|
+
const txnResponse = await account.sendTransaction(transactionParams, chainId != null ? chainId : _this.defaultChainId());
|
|
2392
|
+
txnHash = (_txnResponse$hash = txnResponse == null ? void 0 : txnResponse.hash) != null ? _txnResponse$hash : '';
|
|
2393
|
+
} else {
|
|
2394
|
+
// prompt user to provide the response
|
|
2395
|
+
txnHash = await _this.prompter.promptSendTransaction(transactionParams, chainId, _this.connectOptions);
|
|
2396
|
+
}
|
|
2397
|
+
if (txnHash) {
|
|
2398
|
+
response.result = txnHash;
|
|
2399
|
+
} else {
|
|
2400
|
+
// The user has declined the request when value is null
|
|
2401
|
+
throw new Error('declined by user');
|
|
2402
|
+
}
|
|
2403
|
+
break;
|
|
2404
|
+
}
|
|
2405
|
+
case 'eth_signTransaction':
|
|
2406
|
+
{
|
|
2407
|
+
// https://eth.wiki/json-rpc/API#eth_signTransaction
|
|
2408
|
+
const [transaction] = request.params;
|
|
2409
|
+
const sender = ethers.ethers.utils.getAddress(transaction.from);
|
|
2410
|
+
if (sender !== account.address) {
|
|
2411
|
+
throw new Error('sender address does not match wallet');
|
|
2412
|
+
}
|
|
2413
|
+
validateTransactionRequest(account.address, transaction);
|
|
2414
|
+
if (_this.prompter === null) {
|
|
2415
|
+
// The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
|
|
2416
|
+
// this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
|
|
2417
|
+
//
|
|
2418
|
+
// TODO: verify serializing / transporting the SignedTransaction object works as expected, most likely however
|
|
2419
|
+
// we will want to resolveProperties the big number values to hex strings
|
|
2420
|
+
response.result = await account.signTransactions(transaction, chainId != null ? chainId : _this.defaultChainId());
|
|
2421
|
+
} else {
|
|
2422
|
+
response.result = await _this.prompter.promptSignTransaction(transaction, chainId, _this.connectOptions);
|
|
2423
|
+
}
|
|
2424
|
+
break;
|
|
2425
|
+
}
|
|
2426
|
+
case 'eth_sendRawTransaction':
|
|
2427
|
+
{
|
|
2428
|
+
// NOTE: we're not using a prompter here as the transaction is already signed
|
|
2429
|
+
// and would have prompted the user upon signing.
|
|
2430
|
+
|
|
2431
|
+
// https://eth.wiki/json-rpc/API#eth_sendRawTransaction
|
|
2432
|
+
if (core.commons.transaction.isSignedTransactionBundle(request.params[0])) {
|
|
2433
|
+
const txChainId = ethers.BigNumber.from(request.params[0].chainId).toNumber();
|
|
2434
|
+
const tx = await account.relayer(txChainId).relay(request.params[0]);
|
|
2435
|
+
response.result = tx.hash;
|
|
2436
|
+
} else {
|
|
2437
|
+
const tx = await provider.sendTransaction(request.params[0]);
|
|
2438
|
+
response.result = tx.hash;
|
|
2439
|
+
}
|
|
2440
|
+
break;
|
|
2441
|
+
}
|
|
2442
|
+
case 'eth_getTransactionCount':
|
|
2443
|
+
{
|
|
2444
|
+
const address = ethers.ethers.utils.getAddress(request.params[0]);
|
|
2445
|
+
const tag = request.params[1];
|
|
2446
|
+
|
|
2447
|
+
// TODO: Maybe we should fetch this data from the relayer or from the reader
|
|
2448
|
+
// but for now we keep it simple and just use the provider
|
|
2449
|
+
|
|
2450
|
+
const count = await provider.getTransactionCount(address, tag);
|
|
2451
|
+
response.result = ethers.ethers.BigNumber.from(count).toHexString();
|
|
2452
|
+
break;
|
|
2453
|
+
}
|
|
2454
|
+
case 'eth_blockNumber':
|
|
2455
|
+
{
|
|
2456
|
+
response.result = await provider.getBlockNumber();
|
|
2457
|
+
break;
|
|
2458
|
+
}
|
|
2459
|
+
case 'eth_getBlockByNumber':
|
|
2460
|
+
{
|
|
2461
|
+
response.result = await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2462
|
+
break;
|
|
2463
|
+
}
|
|
2464
|
+
case 'eth_getBlockByHash':
|
|
2465
|
+
{
|
|
2466
|
+
response.result = await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2467
|
+
break;
|
|
2468
|
+
}
|
|
2469
|
+
case 'eth_getTransactionByHash':
|
|
2470
|
+
{
|
|
2471
|
+
response.result = await provider.getTransaction(request.params[0]);
|
|
2472
|
+
break;
|
|
2473
|
+
}
|
|
2474
|
+
case 'eth_call':
|
|
2475
|
+
{
|
|
2476
|
+
const [transactionObject, blockTag] = request.params;
|
|
2477
|
+
response.result = await provider.call(transactionObject, blockTag);
|
|
2478
|
+
break;
|
|
2479
|
+
}
|
|
2480
|
+
case 'eth_getCode':
|
|
2481
|
+
{
|
|
2482
|
+
const [contractAddress, blockTag] = request.params;
|
|
2483
|
+
response.result = await provider.getCode(contractAddress, blockTag);
|
|
2484
|
+
break;
|
|
2485
|
+
}
|
|
2486
|
+
case 'eth_estimateGas':
|
|
2487
|
+
{
|
|
2488
|
+
const [transactionObject] = request.params;
|
|
2489
|
+
response.result = await provider.estimateGas(transactionObject);
|
|
2490
|
+
break;
|
|
2491
|
+
}
|
|
2492
|
+
case 'eth_gasPrice':
|
|
2493
|
+
{
|
|
2494
|
+
const gasPrice = await provider.getGasPrice();
|
|
2495
|
+
response.result = gasPrice.toHexString();
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
case 'wallet_switchEthereumChain':
|
|
2499
|
+
{
|
|
2500
|
+
const [switchParams] = request.params;
|
|
2501
|
+
if (!switchParams.chainId || switchParams.chainId.length === 0) {
|
|
2502
|
+
throw new Error('invalid chainId');
|
|
2503
|
+
}
|
|
2504
|
+
const _chainId = ethers.ethers.BigNumber.from(switchParams.chainId);
|
|
2505
|
+
_this.setDefaultChainId(_chainId.toNumber());
|
|
2506
|
+
response.result = null; // success
|
|
2507
|
+
break;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
// smart wallet method
|
|
2511
|
+
case 'sequence_getWalletContext':
|
|
2512
|
+
{
|
|
2513
|
+
response.result = account.contexts;
|
|
2514
|
+
break;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// smart wallet method
|
|
2518
|
+
case 'sequence_getWalletConfig':
|
|
2519
|
+
{
|
|
2520
|
+
const [_chainId2] = request.params;
|
|
2521
|
+
if (_chainId2) {
|
|
2522
|
+
response.result = [(await account.status(_chainId2)).onChain.config];
|
|
2523
|
+
} else {
|
|
2524
|
+
response.result = await Promise.all(account.networks.map(async function (network) {
|
|
2525
|
+
const status = await account.status(network.chainId);
|
|
2526
|
+
return status.onChain.config;
|
|
2527
|
+
}));
|
|
2528
|
+
}
|
|
2529
|
+
break;
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
// smart wallet method
|
|
2533
|
+
case 'sequence_getWalletState':
|
|
2534
|
+
{
|
|
2535
|
+
const [_chainId3] = request.params;
|
|
2536
|
+
// TODO: Add getWalletState to the Signer interface
|
|
2537
|
+
if (_chainId3) {
|
|
2538
|
+
response.result = [getLegacyWalletState(_chainId3, await account.status(_chainId3))];
|
|
2539
|
+
} else {
|
|
2540
|
+
response.result = await Promise.all(account.networks.map(async function (network) {
|
|
2541
|
+
const status = await account.status(network.chainId);
|
|
2542
|
+
return getLegacyWalletState(network.chainId, status);
|
|
2543
|
+
}));
|
|
2544
|
+
}
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
// smart wallet method
|
|
2549
|
+
case 'sequence_getNetworks':
|
|
2550
|
+
{
|
|
2551
|
+
// NOTE: must ensure that the response result below returns clean serialized data, which is to omit
|
|
2552
|
+
// the provider and relayer objects and only return the urls so can be reinstantiated on dapp side.
|
|
2553
|
+
// This is handled by this.getNetworks() but noted here for future readers.
|
|
2554
|
+
response.result = await _this.getNetworks(true);
|
|
2555
|
+
break;
|
|
2556
|
+
}
|
|
2557
|
+
case 'sequence_isSequence':
|
|
2558
|
+
{
|
|
2559
|
+
response.result = true;
|
|
2560
|
+
break;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
// smart wallet method
|
|
2564
|
+
case 'sequence_updateConfig':
|
|
2565
|
+
{
|
|
2566
|
+
throw new Error('sequence_updateConfig method is not allowed from a dapp');
|
|
2567
|
+
// NOTE: method is disabled as we don't need a dapp to request to update a config.
|
|
2568
|
+
// However, if we ever want this, we can enable it but must also use the prompter
|
|
2569
|
+
// for confirmation.
|
|
2570
|
+
//
|
|
2571
|
+
// const [newConfig] = request.params
|
|
2572
|
+
// response.result = await signer.updateConfig(newConfig)
|
|
2573
|
+
break;
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
// smart wallet method
|
|
2577
|
+
case 'sequence_publishConfig':
|
|
2578
|
+
{
|
|
2579
|
+
throw new Error('sequence_publishConfig method is not allowed from a dapp');
|
|
2580
|
+
break;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
// relayer method
|
|
2584
|
+
case 'sequence_gasRefundOptions':
|
|
2585
|
+
{
|
|
2586
|
+
// TODO
|
|
2587
|
+
break;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// relayer method
|
|
2591
|
+
case 'sequence_getNonce':
|
|
2592
|
+
{
|
|
2593
|
+
// TODO
|
|
2594
|
+
break;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
// relayer method
|
|
2598
|
+
case 'sequence_relay':
|
|
2599
|
+
{
|
|
2600
|
+
// TODO
|
|
2601
|
+
break;
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// set default network of wallet
|
|
2605
|
+
case 'sequence_setDefaultNetwork':
|
|
2606
|
+
{
|
|
2607
|
+
const [defaultChainId] = request.params;
|
|
2608
|
+
if (!defaultChainId) {
|
|
2609
|
+
throw new Error('invalid request, method argument defaultChainId cannot be empty');
|
|
2610
|
+
}
|
|
2611
|
+
_this.setDefaultChainId(defaultChainId);
|
|
2612
|
+
response.result = await _this.getNetworks(true);
|
|
2613
|
+
break;
|
|
2614
|
+
}
|
|
2615
|
+
default:
|
|
2616
|
+
{
|
|
2617
|
+
if (!jsonRpcProvider) {
|
|
2618
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
// NOTE: provider here will be chain-bound if chainId is provided
|
|
2622
|
+
const providerResponse = await jsonRpcProvider.send(request.method, request.params);
|
|
2623
|
+
response.result = providerResponse;
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
} catch (err) {
|
|
2627
|
+
utils.logger.error(err);
|
|
2628
|
+
|
|
2629
|
+
// See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md#rpc-errors
|
|
2630
|
+
response.result = null;
|
|
2631
|
+
response.error = _extends({}, new Error(err), {
|
|
2632
|
+
code: 4001
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
callback(undefined, response);
|
|
2636
|
+
};
|
|
2229
2637
|
this.isSignedIn = async function () {
|
|
2230
2638
|
await _this.signerReady();
|
|
2231
2639
|
return !!_this.account;
|
|
@@ -2237,7 +2645,7 @@ class WalletRequestHandler {
|
|
|
2237
2645
|
}
|
|
2238
2646
|
return _this.account;
|
|
2239
2647
|
};
|
|
2240
|
-
this.account =
|
|
2648
|
+
this.account = _account;
|
|
2241
2649
|
this.prompter = prompter;
|
|
2242
2650
|
this.networks = networks;
|
|
2243
2651
|
}
|
|
@@ -2321,7 +2729,7 @@ class WalletRequestHandler {
|
|
|
2321
2729
|
const chainId = network.findSupportedNetwork(networkId).chainId;
|
|
2322
2730
|
const connectDetails = {
|
|
2323
2731
|
connected: true,
|
|
2324
|
-
chainId: ethers.ethers.
|
|
2732
|
+
chainId: ethers.ethers.utils.hexValue(chainId)
|
|
2325
2733
|
};
|
|
2326
2734
|
if (options && options.authorize) {
|
|
2327
2735
|
// Perform ethauth eip712 request and construct the ConnectDetails response
|
|
@@ -2356,414 +2764,20 @@ class WalletRequestHandler {
|
|
|
2356
2764
|
// sendMessageRequest will unwrap the ProviderMessageRequest and send it to the JsonRpcHandler
|
|
2357
2765
|
// (aka, the signer in this instance) and then responds with a wrapped response of
|
|
2358
2766
|
// ProviderMessageResponse to be sent over the transport
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
const isJsonRpcResponse = majorVersion < 2;
|
|
2364
|
-
const jsonRpcResponse = {
|
|
2365
|
-
id: message.data.id,
|
|
2366
|
-
jsonrpc: '2.0',
|
|
2367
|
-
result: null,
|
|
2368
|
-
error: undefined
|
|
2369
|
-
};
|
|
2370
|
-
try {
|
|
2371
|
-
const result = await this.request({
|
|
2372
|
-
method: message.data.method,
|
|
2373
|
-
params: message.data.params,
|
|
2374
|
-
chainId: message.chainId
|
|
2375
|
-
});
|
|
2376
|
-
return _extends({}, message, {
|
|
2377
|
-
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2378
|
-
result
|
|
2379
|
-
}) : result
|
|
2380
|
-
});
|
|
2381
|
-
} catch (error) {
|
|
2382
|
-
return _extends({}, message, {
|
|
2383
|
-
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2384
|
-
error
|
|
2385
|
-
}) : error
|
|
2386
|
-
});
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
async request(request) {
|
|
2390
|
-
await this.getAccount();
|
|
2391
|
-
try {
|
|
2392
|
-
var _this$account, _request$chainId;
|
|
2393
|
-
// only allow public json rpc method to the provider when user is not logged in, aka signer is not set
|
|
2394
|
-
if ((!this.account || this.account === null) && !permittedJsonRpcMethods.includes(request.method)) {
|
|
2395
|
-
// throw new Error(`not logged in. ${request.method} is unavailable`)
|
|
2396
|
-
throw ErrSignedInRequired;
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2399
|
-
// wallet account
|
|
2400
|
-
const account = this.account;
|
|
2401
|
-
if (!account) {
|
|
2402
|
-
throw new Error('WalletRequestHandler: wallet account is not configured');
|
|
2403
|
-
}
|
|
2404
|
-
|
|
2405
|
-
// fetch the provider for the specific chain, or undefined will select defaultChain
|
|
2406
|
-
const provider = (_this$account = this.account) == null ? void 0 : _this$account.providerFor((_request$chainId = request.chainId) != null ? _request$chainId : this.defaultChainId());
|
|
2407
|
-
if (!provider) {
|
|
2408
|
-
throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${request.chainId}`);
|
|
2409
|
-
}
|
|
2410
|
-
const jsonRpcProvider = provider instanceof ethers.ethers.JsonRpcProvider ? provider : undefined;
|
|
2411
|
-
switch (request.method) {
|
|
2412
|
-
case 'net_version':
|
|
2413
|
-
{
|
|
2414
|
-
if (!jsonRpcProvider) {
|
|
2415
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2416
|
-
}
|
|
2417
|
-
return await jsonRpcProvider.send('net_version', []);
|
|
2418
|
-
}
|
|
2419
|
-
case 'eth_chainId':
|
|
2420
|
-
{
|
|
2421
|
-
if (!jsonRpcProvider) {
|
|
2422
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2423
|
-
}
|
|
2424
|
-
return await jsonRpcProvider.send('eth_chainId', []);
|
|
2425
|
-
}
|
|
2426
|
-
case 'eth_accounts':
|
|
2427
|
-
{
|
|
2428
|
-
return [account.address];
|
|
2429
|
-
}
|
|
2430
|
-
case 'eth_getBalance':
|
|
2431
|
-
{
|
|
2432
|
-
const [accountAddress, blockTag] = request.params;
|
|
2433
|
-
const walletBalance = await provider.getBalance(accountAddress, blockTag);
|
|
2434
|
-
return utils.toHexString(walletBalance);
|
|
2435
|
-
}
|
|
2436
|
-
case 'sequence_sign':
|
|
2437
|
-
case 'personal_sign':
|
|
2438
|
-
case 'eth_sign':
|
|
2439
|
-
{
|
|
2440
|
-
// note: message from json-rpc input is in hex format
|
|
2441
|
-
let message;
|
|
2442
|
-
|
|
2443
|
-
// there is a difference in the order of the params:
|
|
2444
|
-
// sequence_sign, personal_sign: [data, address]
|
|
2445
|
-
// eth_sign: [address, data]
|
|
2446
|
-
switch (request.method) {
|
|
2447
|
-
case 'sequence_sign':
|
|
2448
|
-
case 'personal_sign':
|
|
2449
|
-
{
|
|
2450
|
-
const [data, _address] = request.params;
|
|
2451
|
-
message = data;
|
|
2452
|
-
break;
|
|
2453
|
-
}
|
|
2454
|
-
case 'eth_sign':
|
|
2455
|
-
{
|
|
2456
|
-
const [_address, data] = request.params;
|
|
2457
|
-
message = data;
|
|
2458
|
-
break;
|
|
2459
|
-
}
|
|
2460
|
-
}
|
|
2461
|
-
let sig = '';
|
|
2462
|
-
|
|
2463
|
-
// Message must be prefixed with "\x19Ethereum Signed Message:\n"
|
|
2464
|
-
// as defined by EIP-191
|
|
2465
|
-
const prefixedMessage = prefixEIP191Message(message);
|
|
2466
|
-
|
|
2467
|
-
// TODO:
|
|
2468
|
-
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
2469
|
-
const sequenceVerified = request.method === 'sequence_sign';
|
|
2470
|
-
if (this.prompter === null) {
|
|
2471
|
-
var _request$chainId2;
|
|
2472
|
-
// prompter is null, so we'll sign from here
|
|
2473
|
-
sig = await account.signMessage(prefixedMessage, (_request$chainId2 = request.chainId) != null ? _request$chainId2 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2474
|
-
} else {
|
|
2475
|
-
sig = await this.prompter.promptSignMessage({
|
|
2476
|
-
chainId: request.chainId,
|
|
2477
|
-
message: ethers.ethers.getBytes(prefixedMessage),
|
|
2478
|
-
eip6492: sequenceVerified
|
|
2479
|
-
}, this.connectOptions);
|
|
2480
|
-
}
|
|
2481
|
-
if (sig && sig.length > 0) {
|
|
2482
|
-
return sig;
|
|
2483
|
-
} else {
|
|
2484
|
-
// The user has declined the request when value is null
|
|
2485
|
-
throw new Error('declined by user');
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
case 'sequence_signTypedData_v4':
|
|
2489
|
-
case 'eth_signTypedData':
|
|
2490
|
-
case 'eth_signTypedData_v4':
|
|
2491
|
-
{
|
|
2492
|
-
// note: signingAddress from json-rpc input is in hex format, and typedDataObject
|
|
2493
|
-
// should be an object, but in some instances may be double string encoded
|
|
2494
|
-
const [signingAddress, typedDataObject] = request.params;
|
|
2495
|
-
let typedData = undefined;
|
|
2496
|
-
if (typeof typedDataObject === 'string') {
|
|
2497
|
-
try {
|
|
2498
|
-
typedData = JSON.parse(typedDataObject);
|
|
2499
|
-
} catch (e) {
|
|
2500
|
-
console.warn('walletRequestHandler: error parsing typedData', e);
|
|
2501
|
-
}
|
|
2502
|
-
} else {
|
|
2503
|
-
typedData = typedDataObject;
|
|
2504
|
-
}
|
|
2505
|
-
if (!typedData || !typedData.domain || !typedData.types || !typedData.message) {
|
|
2506
|
-
throw new Error('invalid typedData object');
|
|
2507
|
-
}
|
|
2508
|
-
let sig = '';
|
|
2509
|
-
const sequenceVerified = request.method === 'sequence_signTypedData_v4';
|
|
2510
|
-
if (this.prompter === null) {
|
|
2511
|
-
var _request$chainId3;
|
|
2512
|
-
// prompter is null, so we'll sign from here
|
|
2513
|
-
sig = await account.signTypedData(typedData.domain, typedData.types, typedData.message, (_request$chainId3 = request.chainId) != null ? _request$chainId3 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2514
|
-
} else {
|
|
2515
|
-
sig = await this.prompter.promptSignMessage({
|
|
2516
|
-
chainId: request.chainId,
|
|
2517
|
-
typedData: typedData,
|
|
2518
|
-
eip6492: sequenceVerified
|
|
2519
|
-
}, this.connectOptions);
|
|
2520
|
-
}
|
|
2521
|
-
if (sig && sig.length > 0) {
|
|
2522
|
-
return sig;
|
|
2523
|
-
} else {
|
|
2524
|
-
// The user has declined the request when value is null
|
|
2525
|
-
throw new Error('declined by user');
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
case 'eth_sendTransaction':
|
|
2529
|
-
{
|
|
2530
|
-
// https://eth.wiki/json-rpc/API#eth_sendtransaction
|
|
2531
|
-
const transactionParams = fromExtended(request.params[0]).map(tx => {
|
|
2532
|
-
// eth_sendTransaction uses 'gas'
|
|
2533
|
-
// ethers and sequence use 'gasLimit'
|
|
2534
|
-
if ('gas' in tx && tx.gasLimit === undefined) {
|
|
2535
|
-
tx.gasLimit = tx.gas;
|
|
2536
|
-
delete tx.gas;
|
|
2537
|
-
}
|
|
2538
|
-
return tx;
|
|
2539
|
-
});
|
|
2540
|
-
validateTransactionRequest(account.address, transactionParams);
|
|
2541
|
-
let txnHash = '';
|
|
2542
|
-
if (this.prompter === null) {
|
|
2543
|
-
var _request$chainId4, _txnResponse$hash;
|
|
2544
|
-
// prompter is null, so we'll send from here
|
|
2545
|
-
const txnResponse = await account.sendTransaction(transactionParams, (_request$chainId4 = request.chainId) != null ? _request$chainId4 : this.defaultChainId());
|
|
2546
|
-
txnHash = (_txnResponse$hash = txnResponse == null ? void 0 : txnResponse.hash) != null ? _txnResponse$hash : '';
|
|
2547
|
-
} else {
|
|
2548
|
-
// prompt user to provide the response
|
|
2549
|
-
txnHash = await this.prompter.promptSendTransaction(transactionParams, request.chainId, this.connectOptions);
|
|
2550
|
-
}
|
|
2551
|
-
if (txnHash) {
|
|
2552
|
-
return txnHash;
|
|
2553
|
-
} else {
|
|
2554
|
-
// The user has declined the request when value is null
|
|
2555
|
-
throw new Error('declined by user');
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
case 'eth_signTransaction':
|
|
2559
|
-
{
|
|
2560
|
-
// https://eth.wiki/json-rpc/API#eth_signTransaction
|
|
2561
|
-
const [transaction] = request.params;
|
|
2562
|
-
const sender = ethers.ethers.getAddress(transaction.from);
|
|
2563
|
-
if (sender !== account.address) {
|
|
2564
|
-
throw new Error('sender address does not match wallet');
|
|
2565
|
-
}
|
|
2566
|
-
validateTransactionRequest(account.address, transaction);
|
|
2567
|
-
if (this.prompter === null) {
|
|
2568
|
-
var _request$chainId5;
|
|
2569
|
-
// The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
|
|
2570
|
-
// this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
|
|
2571
|
-
//
|
|
2572
|
-
// TODO: verify serializing / transporting the SignedTransaction object works as expected, most likely however
|
|
2573
|
-
// we will want to resolveProperties the big number values to hex strings
|
|
2574
|
-
return await account.signTransactions(transaction, (_request$chainId5 = request.chainId) != null ? _request$chainId5 : this.defaultChainId());
|
|
2575
|
-
} else {
|
|
2576
|
-
return await this.prompter.promptSignTransaction(transaction, request.chainId, this.connectOptions);
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
case 'eth_sendRawTransaction':
|
|
2580
|
-
{
|
|
2581
|
-
// NOTE: we're not using a prompter here as the transaction is already signed
|
|
2582
|
-
// and would have prompted the user upon signing.
|
|
2583
|
-
|
|
2584
|
-
// https://eth.wiki/json-rpc/API#eth_sendRawTransaction
|
|
2585
|
-
if (core.commons.transaction.isSignedTransactionBundle(request.params[0])) {
|
|
2586
|
-
const txChainId = Number(BigInt(request.params[0].chainId));
|
|
2587
|
-
const tx = await account.relayer(txChainId).relay(request.params[0]);
|
|
2588
|
-
return tx.hash;
|
|
2589
|
-
} else {
|
|
2590
|
-
const tx = await provider.broadcastTransaction(request.params[0]);
|
|
2591
|
-
return tx.hash;
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
case 'eth_getTransactionCount':
|
|
2595
|
-
{
|
|
2596
|
-
const address = ethers.ethers.getAddress(request.params[0]);
|
|
2597
|
-
const tag = request.params[1];
|
|
2598
|
-
|
|
2599
|
-
// TODO: Maybe we should fetch this data from the relayer or from the reader
|
|
2600
|
-
// but for now we keep it simple and just use the provider
|
|
2601
|
-
|
|
2602
|
-
const count = await provider.getTransactionCount(address, tag);
|
|
2603
|
-
return utils.toHexString(BigInt(count));
|
|
2604
|
-
}
|
|
2605
|
-
case 'eth_blockNumber':
|
|
2606
|
-
{
|
|
2607
|
-
return await provider.getBlockNumber();
|
|
2608
|
-
}
|
|
2609
|
-
case 'eth_getBlockByNumber':
|
|
2610
|
-
{
|
|
2611
|
-
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2612
|
-
}
|
|
2613
|
-
case 'eth_getBlockByHash':
|
|
2614
|
-
{
|
|
2615
|
-
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2616
|
-
}
|
|
2617
|
-
case 'eth_getTransactionByHash':
|
|
2618
|
-
{
|
|
2619
|
-
return await provider.getTransaction(request.params[0]);
|
|
2620
|
-
}
|
|
2621
|
-
case 'eth_call':
|
|
2622
|
-
{
|
|
2623
|
-
const [transactionObject, blockTag] = request.params;
|
|
2624
|
-
return await provider.call(_extends({}, transactionObject, {
|
|
2625
|
-
blockTag
|
|
2626
|
-
}));
|
|
2627
|
-
}
|
|
2628
|
-
case 'eth_getCode':
|
|
2629
|
-
{
|
|
2630
|
-
const [contractAddress, blockTag] = request.params;
|
|
2631
|
-
return await provider.getCode(contractAddress, blockTag);
|
|
2632
|
-
}
|
|
2633
|
-
case 'eth_estimateGas':
|
|
2634
|
-
{
|
|
2635
|
-
const [transactionObject] = request.params;
|
|
2636
|
-
return await provider.estimateGas(transactionObject);
|
|
2637
|
-
}
|
|
2638
|
-
case 'eth_gasPrice':
|
|
2639
|
-
{
|
|
2640
|
-
const feeData = await provider.getFeeData();
|
|
2641
|
-
return feeData.gasPrice && utils.toHexString(feeData.gasPrice);
|
|
2642
|
-
}
|
|
2643
|
-
case 'wallet_switchEthereumChain':
|
|
2644
|
-
{
|
|
2645
|
-
const [switchParams] = request.params;
|
|
2646
|
-
if (!switchParams.chainId || switchParams.chainId.length === 0) {
|
|
2647
|
-
throw new Error('invalid chainId');
|
|
2648
|
-
}
|
|
2649
|
-
const chainId = BigInt(switchParams.chainId);
|
|
2650
|
-
this.setDefaultChainId(Number(chainId));
|
|
2651
|
-
return null; // success
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
|
-
// smart wallet method
|
|
2655
|
-
case 'sequence_getWalletContext':
|
|
2656
|
-
{
|
|
2657
|
-
return account.contexts;
|
|
2658
|
-
}
|
|
2659
|
-
|
|
2660
|
-
// smart wallet method
|
|
2661
|
-
case 'sequence_getWalletConfig':
|
|
2662
|
-
{
|
|
2663
|
-
const [chainId] = request.params;
|
|
2664
|
-
if (chainId) {
|
|
2665
|
-
return [(await account.status(chainId)).onChain.config];
|
|
2666
|
-
} else {
|
|
2667
|
-
return await Promise.all(account.networks.map(async function (network) {
|
|
2668
|
-
const status = await account.status(network.chainId);
|
|
2669
|
-
return status.onChain.config;
|
|
2670
|
-
}));
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
|
|
2674
|
-
// smart wallet method
|
|
2675
|
-
case 'sequence_getWalletState':
|
|
2676
|
-
{
|
|
2677
|
-
const [chainId] = request.params;
|
|
2678
|
-
// TODO: Add getWalletState to the Signer interface
|
|
2679
|
-
if (chainId) {
|
|
2680
|
-
return [getLegacyWalletState(chainId, await account.status(chainId))];
|
|
2681
|
-
} else {
|
|
2682
|
-
return await Promise.all(account.networks.map(async function (network) {
|
|
2683
|
-
const status = await account.status(network.chainId);
|
|
2684
|
-
return getLegacyWalletState(network.chainId, status);
|
|
2685
|
-
}));
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
|
|
2689
|
-
// smart wallet method
|
|
2690
|
-
case 'sequence_getNetworks':
|
|
2691
|
-
{
|
|
2692
|
-
// NOTE: must ensure that the response result below returns clean serialized data, which is to omit
|
|
2693
|
-
// the provider and relayer objects and only return the urls so can be reinstantiated on dapp side.
|
|
2694
|
-
// This is handled by this.getNetworks() but noted here for future readers.
|
|
2695
|
-
return await this.getNetworks(true);
|
|
2696
|
-
}
|
|
2697
|
-
case 'sequence_isSequence':
|
|
2698
|
-
{
|
|
2699
|
-
return true;
|
|
2700
|
-
}
|
|
2701
|
-
|
|
2702
|
-
// smart wallet method
|
|
2703
|
-
case 'sequence_updateConfig':
|
|
2704
|
-
{
|
|
2705
|
-
throw new Error('sequence_updateConfig method is not allowed from a dapp');
|
|
2706
|
-
// NOTE: method is disabled as we don't need a dapp to request to update a config.
|
|
2707
|
-
// However, if we ever want this, we can enable it but must also use the prompter
|
|
2708
|
-
// for confirmation.
|
|
2709
|
-
//
|
|
2710
|
-
// const [newConfig] = request.params
|
|
2711
|
-
// return await signer.updateConfig(newConfig)
|
|
2712
|
-
}
|
|
2713
|
-
|
|
2714
|
-
// smart wallet method
|
|
2715
|
-
case 'sequence_publishConfig':
|
|
2716
|
-
{
|
|
2717
|
-
throw new Error('sequence_publishConfig method is not allowed from a dapp');
|
|
2718
|
-
}
|
|
2719
|
-
|
|
2720
|
-
// relayer method
|
|
2721
|
-
case 'sequence_gasRefundOptions':
|
|
2722
|
-
{
|
|
2723
|
-
// TODO
|
|
2724
|
-
break;
|
|
2725
|
-
}
|
|
2726
|
-
|
|
2727
|
-
// relayer method
|
|
2728
|
-
case 'sequence_getNonce':
|
|
2729
|
-
{
|
|
2730
|
-
// TODO
|
|
2731
|
-
break;
|
|
2732
|
-
}
|
|
2733
|
-
|
|
2734
|
-
// relayer method
|
|
2735
|
-
case 'sequence_relay':
|
|
2736
|
-
{
|
|
2737
|
-
// TODO
|
|
2738
|
-
break;
|
|
2739
|
-
}
|
|
2767
|
+
sendMessageRequest(message) {
|
|
2768
|
+
return new Promise(resolve => {
|
|
2769
|
+
this.sendAsync(message.data, (error, response) => {
|
|
2770
|
+
// TODO: if response includes data.error, why do we need a separate error argument here?
|
|
2740
2771
|
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
const [defaultChainId] = request.params;
|
|
2745
|
-
if (!defaultChainId) {
|
|
2746
|
-
throw new Error('invalid request, method argument defaultChainId cannot be empty');
|
|
2747
|
-
}
|
|
2748
|
-
this.setDefaultChainId(defaultChainId);
|
|
2749
|
-
return await this.getNetworks(true);
|
|
2750
|
-
}
|
|
2751
|
-
default:
|
|
2752
|
-
{
|
|
2753
|
-
if (!jsonRpcProvider) {
|
|
2754
|
-
throw new Error(`Account provider doesn't support send method`);
|
|
2755
|
-
}
|
|
2772
|
+
const responseMessage = _extends({}, message, {
|
|
2773
|
+
data: response
|
|
2774
|
+
});
|
|
2756
2775
|
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
throw {
|
|
2763
|
-
message: err == null ? void 0 : err.message,
|
|
2764
|
-
code: 4001
|
|
2765
|
-
};
|
|
2766
|
-
}
|
|
2776
|
+
// NOTE: we always resolve here, are the sendAsync call will wrap any exceptions
|
|
2777
|
+
// in the error field of the response to ensure we send back to the user
|
|
2778
|
+
resolve(responseMessage);
|
|
2779
|
+
}, message.chainId);
|
|
2780
|
+
});
|
|
2767
2781
|
}
|
|
2768
2782
|
on(event, fn) {
|
|
2769
2783
|
this.events.on(event, fn);
|
|
@@ -2851,7 +2865,7 @@ class WalletRequestHandler {
|
|
|
2851
2865
|
this.events.emit('disconnect', undefined, origin);
|
|
2852
2866
|
}
|
|
2853
2867
|
notifyChainChanged(chainId, origin) {
|
|
2854
|
-
this.events.emit('chainChanged', ethers.ethers.
|
|
2868
|
+
this.events.emit('chainChanged', ethers.ethers.utils.hexValue(chainId), origin);
|
|
2855
2869
|
}
|
|
2856
2870
|
async notifyNetworks(networks) {
|
|
2857
2871
|
const n = networks || (await this.getNetworks(true));
|
|
@@ -2859,7 +2873,7 @@ class WalletRequestHandler {
|
|
|
2859
2873
|
if (n.length > 0) {
|
|
2860
2874
|
const defaultNetwork = n.find(network => network.chainId === this.defaultChainId());
|
|
2861
2875
|
if (defaultNetwork) {
|
|
2862
|
-
this.events.emit('chainChanged', ethers.ethers.
|
|
2876
|
+
this.events.emit('chainChanged', ethers.ethers.utils.hexValue(defaultNetwork.chainId));
|
|
2863
2877
|
}
|
|
2864
2878
|
} else {
|
|
2865
2879
|
this.events.emit('chainChanged', '0x0');
|
|
@@ -2928,19 +2942,6 @@ function getLegacyWalletState(chainId, status) {
|
|
|
2928
2942
|
}
|
|
2929
2943
|
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'];
|
|
2930
2944
|
|
|
2931
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
2932
|
-
if (source == null) return {};
|
|
2933
|
-
var target = {};
|
|
2934
|
-
var sourceKeys = Object.keys(source);
|
|
2935
|
-
var key, i;
|
|
2936
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
2937
|
-
key = sourceKeys[i];
|
|
2938
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
2939
|
-
target[key] = source[key];
|
|
2940
|
-
}
|
|
2941
|
-
return target;
|
|
2942
|
-
}
|
|
2943
|
-
|
|
2944
2945
|
class SequenceSigner {
|
|
2945
2946
|
get utils() {
|
|
2946
2947
|
return this.provider.utils;
|
|
@@ -2949,6 +2950,7 @@ class SequenceSigner {
|
|
|
2949
2950
|
this.client = client;
|
|
2950
2951
|
this.provider = provider;
|
|
2951
2952
|
this.singleNetworkSigners = {};
|
|
2953
|
+
this._isSigner = true;
|
|
2952
2954
|
this._isSequenceSigner = true;
|
|
2953
2955
|
}
|
|
2954
2956
|
async getAddress() {
|
|
@@ -3018,19 +3020,12 @@ class SequenceSigner {
|
|
|
3018
3020
|
});
|
|
3019
3021
|
const provider = this.getProvider(chainId);
|
|
3020
3022
|
try {
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
if (tx !== null) {
|
|
3027
|
-
return resolve(tx);
|
|
3028
|
-
}
|
|
3029
|
-
await provider.once('block', check);
|
|
3030
|
-
};
|
|
3031
|
-
check();
|
|
3023
|
+
return await ethers.ethers.utils.poll(async function () {
|
|
3024
|
+
const tx = await provider.getTransaction(txHash);
|
|
3025
|
+
return tx ? provider._wrapTransaction(tx, txHash) : undefined;
|
|
3026
|
+
}, {
|
|
3027
|
+
onceBlock: provider
|
|
3032
3028
|
});
|
|
3033
|
-
return result;
|
|
3034
3029
|
} catch (err) {
|
|
3035
3030
|
err.transactionHash = txHash;
|
|
3036
3031
|
throw err;
|
|
@@ -3052,12 +3047,15 @@ class SequenceSigner {
|
|
|
3052
3047
|
async estimateGas(transaction, optionals) {
|
|
3053
3048
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).estimateGas(transaction);
|
|
3054
3049
|
}
|
|
3055
|
-
async call(transaction, optionals) {
|
|
3056
|
-
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction);
|
|
3050
|
+
async call(transaction, blockTag, optionals) {
|
|
3051
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction, blockTag);
|
|
3057
3052
|
}
|
|
3058
3053
|
getChainId() {
|
|
3059
3054
|
return Promise.resolve(this.client.getChainId());
|
|
3060
3055
|
}
|
|
3056
|
+
async getGasPrice(optionals) {
|
|
3057
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getGasPrice();
|
|
3058
|
+
}
|
|
3061
3059
|
async getFeeData(optionals) {
|
|
3062
3060
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getFeeData();
|
|
3063
3061
|
}
|
|
@@ -3065,7 +3063,7 @@ class SequenceSigner {
|
|
|
3065
3063
|
const res = await this.provider.resolveName(name);
|
|
3066
3064
|
|
|
3067
3065
|
// For some reason ethers.Signer expects this to return `string`
|
|
3068
|
-
// but ethers.Provider expects this to return `string | null`.
|
|
3066
|
+
// but ethers.providers.Provider expects this to return `string | null`.
|
|
3069
3067
|
// The signer doesn't have any other source of information, so we'll
|
|
3070
3068
|
// fail if the provider doesn't return a result.
|
|
3071
3069
|
if (res === null) {
|
|
@@ -3076,17 +3074,6 @@ class SequenceSigner {
|
|
|
3076
3074
|
_checkProvider(_operation) {
|
|
3077
3075
|
// We always have a provider, so this is a noop
|
|
3078
3076
|
}
|
|
3079
|
-
|
|
3080
|
-
// populateCall(transaction: ethers.PopulatedTransaction): Promise<ethers.PopulatedTransaction> {
|
|
3081
|
-
// return this.provider.populateCall(transaction)
|
|
3082
|
-
// }
|
|
3083
|
-
|
|
3084
|
-
getNonce(_blockTag) {
|
|
3085
|
-
throw new Error('SequenceSigner does not support getNonce');
|
|
3086
|
-
}
|
|
3087
|
-
populateCall(_transaction) {
|
|
3088
|
-
throw new Error('SequenceSigner does not support populateCall');
|
|
3089
|
-
}
|
|
3090
3077
|
populateTransaction(_transaction) {
|
|
3091
3078
|
throw new Error('SequenceSigner does not support populateTransaction');
|
|
3092
3079
|
}
|
|
@@ -3224,43 +3211,31 @@ class WalletUtils {
|
|
|
3224
3211
|
// recoverAddress()
|
|
3225
3212
|
}
|
|
3226
3213
|
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
3230
|
-
constructor(client, providerFor, networks = network.allNetworks, options) {
|
|
3214
|
+
class SequenceProvider extends ethers.ethers.providers.BaseProvider {
|
|
3215
|
+
constructor(client, providerFor, networks = network.allNetworks) {
|
|
3231
3216
|
// We support a lot of networks
|
|
3232
3217
|
// but we start with the default one
|
|
3233
|
-
super(client.getChainId()
|
|
3218
|
+
super(client.getChainId());
|
|
3234
3219
|
|
|
3235
3220
|
// Emit events as defined by EIP-1193
|
|
3236
3221
|
this.client = client;
|
|
3237
3222
|
this.providerFor = providerFor;
|
|
3238
3223
|
this.networks = networks;
|
|
3239
|
-
this.options = options;
|
|
3240
3224
|
this.singleNetworkProviders = {};
|
|
3241
3225
|
this._isSequenceProvider = true;
|
|
3242
3226
|
this.utils = void 0;
|
|
3243
3227
|
this.signer = void 0;
|
|
3244
|
-
this.eip1193EventListeners = new Map();
|
|
3245
3228
|
client.onConnect(details => {
|
|
3246
|
-
|
|
3247
|
-
//this.emit('connect', details)
|
|
3248
|
-
(_this$eip1193EventLis = this.eip1193EventListeners.get('connect')) == null || _this$eip1193EventLis.forEach(listener => listener(details));
|
|
3229
|
+
this.emit('connect', details);
|
|
3249
3230
|
});
|
|
3250
3231
|
client.onDisconnect(error => {
|
|
3251
|
-
|
|
3252
|
-
//this.emit('disconnect', error)
|
|
3253
|
-
(_this$eip1193EventLis2 = this.eip1193EventListeners.get('disconnect')) == null || _this$eip1193EventLis2.forEach(listener => listener(error));
|
|
3232
|
+
this.emit('disconnect', error);
|
|
3254
3233
|
});
|
|
3255
3234
|
client.onDefaultChainIdChanged(chainId => {
|
|
3256
|
-
|
|
3257
|
-
//this.emit('chainChanged', chainId)
|
|
3258
|
-
(_this$eip1193EventLis3 = this.eip1193EventListeners.get('chainChanged')) == null || _this$eip1193EventLis3.forEach(listener => listener(chainId));
|
|
3235
|
+
this.emit('chainChanged', chainId);
|
|
3259
3236
|
});
|
|
3260
3237
|
client.onAccountsChanged(accounts => {
|
|
3261
|
-
|
|
3262
|
-
//this.emit('accountsChanged', accounts)
|
|
3263
|
-
(_this$eip1193EventLis4 = this.eip1193EventListeners.get('accountsChanged')) == null || _this$eip1193EventLis4.forEach(listener => listener(accounts));
|
|
3238
|
+
this.emit('accountsChanged', accounts);
|
|
3264
3239
|
});
|
|
3265
3240
|
|
|
3266
3241
|
// NOTICE: We don't emit 'open' and 'close' events
|
|
@@ -3277,29 +3252,6 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3277
3252
|
// Create a utils instance
|
|
3278
3253
|
this.utils = new WalletUtils(this.signer);
|
|
3279
3254
|
}
|
|
3280
|
-
async on(event, listener) {
|
|
3281
|
-
if (EIP1193EventTypes.includes(event)) {
|
|
3282
|
-
const listeners = this.eip1193EventListeners.get(event) || new Set();
|
|
3283
|
-
listeners.add(listener);
|
|
3284
|
-
this.eip1193EventListeners.set(event, listeners);
|
|
3285
|
-
return this;
|
|
3286
|
-
}
|
|
3287
|
-
return super.on(event, listener);
|
|
3288
|
-
}
|
|
3289
|
-
async off(event, listener) {
|
|
3290
|
-
if (EIP1193EventTypes.includes(event)) {
|
|
3291
|
-
const listeners = this.eip1193EventListeners.get(event);
|
|
3292
|
-
if (listeners) {
|
|
3293
|
-
if (listener) {
|
|
3294
|
-
listeners.delete(listener);
|
|
3295
|
-
} else {
|
|
3296
|
-
listeners.clear();
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
return this;
|
|
3300
|
-
}
|
|
3301
|
-
return super.off(event, listener);
|
|
3302
|
-
}
|
|
3303
3255
|
getSigner(chainId) {
|
|
3304
3256
|
return this.signer.getSigner(chainId);
|
|
3305
3257
|
}
|
|
@@ -3392,7 +3344,7 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3392
3344
|
}
|
|
3393
3345
|
const useChainId = this.toChainId(chainId);
|
|
3394
3346
|
if (!this.singleNetworkProviders[useChainId]) {
|
|
3395
|
-
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId
|
|
3347
|
+
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId);
|
|
3396
3348
|
}
|
|
3397
3349
|
return this.singleNetworkProviders[useChainId];
|
|
3398
3350
|
}
|
|
@@ -3412,26 +3364,11 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3412
3364
|
}
|
|
3413
3365
|
return provider;
|
|
3414
3366
|
}
|
|
3415
|
-
async _perform(req) {
|
|
3416
|
-
var _provider$getRpcReque;
|
|
3417
|
-
const {
|
|
3418
|
-
method
|
|
3419
|
-
} = req,
|
|
3420
|
-
args = _objectWithoutPropertiesLoose(req, _excluded);
|
|
3421
|
-
const provider = await this._getSubprovider();
|
|
3422
|
-
const prepared = (_provider$getRpcReque = provider.getRpcRequest(req)) != null ? _provider$getRpcReque : {
|
|
3423
|
-
method,
|
|
3424
|
-
args: Object.values(args)
|
|
3425
|
-
};
|
|
3426
|
-
if (!prepared) {
|
|
3427
|
-
throw new Error(`Unsupported method ${req.method}`);
|
|
3428
|
-
}
|
|
3429
|
-
return provider.send(prepared.method, prepared.args);
|
|
3430
|
-
}
|
|
3431
3367
|
async perform(method, params) {
|
|
3368
|
+
var _provider$prepareRequ;
|
|
3432
3369
|
// First we check if the method should be handled by the client
|
|
3433
3370
|
if (method === 'eth_chainId') {
|
|
3434
|
-
return ethers.ethers.
|
|
3371
|
+
return ethers.ethers.utils.hexValue(await this.useChainId());
|
|
3435
3372
|
}
|
|
3436
3373
|
if (method === 'eth_accounts') {
|
|
3437
3374
|
return [this.client.getAddress()];
|
|
@@ -3451,15 +3388,17 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3451
3388
|
method === 'sequence_sign' || method === 'sequence_signTypedData_v4') {
|
|
3452
3389
|
// We pass the chainId to the client, if we don't pass one
|
|
3453
3390
|
// the client will use its own default chainId
|
|
3454
|
-
return this.client.
|
|
3391
|
+
return this.client.send({
|
|
3455
3392
|
method,
|
|
3456
|
-
params
|
|
3457
|
-
|
|
3458
|
-
});
|
|
3393
|
+
params
|
|
3394
|
+
}, this.getChainId());
|
|
3459
3395
|
}
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3396
|
+
|
|
3397
|
+
// Forward call to the corresponding provider
|
|
3398
|
+
// we use the provided chainId, or the default one provided by the client
|
|
3399
|
+
const provider = await this._getSubprovider();
|
|
3400
|
+
const prepared = (_provider$prepareRequ = provider.prepareRequest(method, params)) != null ? _provider$prepareRequ : [method, params];
|
|
3401
|
+
return provider.send(prepared[0], prepared[1]);
|
|
3463
3402
|
}
|
|
3464
3403
|
send(method, params) {
|
|
3465
3404
|
return this.perform(method, params);
|
|
@@ -3467,18 +3406,14 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3467
3406
|
request(request) {
|
|
3468
3407
|
return this.perform(request.method, request.params);
|
|
3469
3408
|
}
|
|
3470
|
-
async
|
|
3409
|
+
async detectNetwork() {
|
|
3471
3410
|
const chainId = this.client.getChainId();
|
|
3472
|
-
const
|
|
3473
|
-
if (!
|
|
3411
|
+
const network$1 = network.findNetworkConfig(this.networks, chainId);
|
|
3412
|
+
if (!network$1) {
|
|
3474
3413
|
throw new Error(`Unknown network ${chainId}`);
|
|
3475
3414
|
}
|
|
3476
|
-
const network$1 = new ethers.ethers.Network(found.name, found.chainId);
|
|
3477
3415
|
return network$1;
|
|
3478
3416
|
}
|
|
3479
|
-
async detectNetwork() {
|
|
3480
|
-
return this._detectNetwork();
|
|
3481
|
-
}
|
|
3482
3417
|
|
|
3483
3418
|
// Override most of the methods, so we add support for an optional chainId
|
|
3484
3419
|
// argument, which is used to select the provider to use.
|
|
@@ -3495,9 +3430,9 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3495
3430
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3496
3431
|
return provider.getBlockNumber();
|
|
3497
3432
|
}
|
|
3498
|
-
async
|
|
3433
|
+
async getGasPrice(optionals) {
|
|
3499
3434
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3500
|
-
return
|
|
3435
|
+
return provider.getGasPrice();
|
|
3501
3436
|
}
|
|
3502
3437
|
async getBalance(addressOrName, blockTag, optionals) {
|
|
3503
3438
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3511,21 +3446,21 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3511
3446
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3512
3447
|
return provider.getCode(addressOrName, blockTag);
|
|
3513
3448
|
}
|
|
3514
|
-
async
|
|
3449
|
+
async getStorageAt(addressOrName, position, blockTag, optionals) {
|
|
3515
3450
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3516
|
-
return provider.
|
|
3451
|
+
return provider.getStorageAt(addressOrName, position, blockTag);
|
|
3517
3452
|
}
|
|
3518
|
-
async call(transaction, optionals) {
|
|
3453
|
+
async call(transaction, blockTag, optionals) {
|
|
3519
3454
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3520
|
-
return provider.call(transaction);
|
|
3455
|
+
return provider.call(transaction, blockTag);
|
|
3521
3456
|
}
|
|
3522
3457
|
async estimateGas(transaction, optionals) {
|
|
3523
3458
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3524
3459
|
return provider.estimateGas(transaction);
|
|
3525
3460
|
}
|
|
3526
|
-
async getBlock(blockHashOrBlockTag,
|
|
3461
|
+
async getBlock(blockHashOrBlockTag, optionals) {
|
|
3527
3462
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3528
|
-
return provider.getBlock(blockHashOrBlockTag
|
|
3463
|
+
return provider.getBlock(blockHashOrBlockTag);
|
|
3529
3464
|
}
|
|
3530
3465
|
async getTransaction(transactionHash, optionals) {
|
|
3531
3466
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3552,7 +3487,7 @@ class SequenceProvider extends ethers.ethers.AbstractProvider {
|
|
|
3552
3487
|
return provider.getResolver(name);
|
|
3553
3488
|
}
|
|
3554
3489
|
async resolveName(name) {
|
|
3555
|
-
if (ethers.ethers.isAddress(await name)) {
|
|
3490
|
+
if (ethers.ethers.utils.isAddress(await name)) {
|
|
3556
3491
|
return name;
|
|
3557
3492
|
}
|
|
3558
3493
|
if (!(await this.supportsENS())) {
|
|
@@ -3585,7 +3520,7 @@ SequenceProvider.is = provider => {
|
|
|
3585
3520
|
};
|
|
3586
3521
|
function normalizeChainId(chainId) {
|
|
3587
3522
|
if (typeof chainId === 'object') return normalizeChainId(chainId.chainId);
|
|
3588
|
-
return
|
|
3523
|
+
return ethers.ethers.BigNumber.from(chainId).toNumber();
|
|
3589
3524
|
}
|
|
3590
3525
|
|
|
3591
3526
|
/**
|
|
@@ -3598,8 +3533,8 @@ function normalizeChainId(chainId) {
|
|
|
3598
3533
|
* NOTICE: These networks won't support ENS unless they are the mainnet.
|
|
3599
3534
|
*/
|
|
3600
3535
|
class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
3601
|
-
constructor(client, providerFor, chainId
|
|
3602
|
-
super(client, providerFor
|
|
3536
|
+
constructor(client, providerFor, chainId) {
|
|
3537
|
+
super(client, providerFor);
|
|
3603
3538
|
this.chainId = chainId;
|
|
3604
3539
|
this._isSingleNetworkSequenceProvider = true;
|
|
3605
3540
|
}
|
|
@@ -3618,12 +3553,11 @@ class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
|
3618
3553
|
}
|
|
3619
3554
|
async getNetwork() {
|
|
3620
3555
|
const networks = await this.client.getNetworks();
|
|
3621
|
-
const
|
|
3622
|
-
if (!
|
|
3556
|
+
const res = network.findNetworkConfig(networks, this.chainId);
|
|
3557
|
+
if (!res) {
|
|
3623
3558
|
throw new Error(`Unsupported network ${this.chainId}`);
|
|
3624
3559
|
}
|
|
3625
|
-
|
|
3626
|
-
return network$1;
|
|
3560
|
+
return res;
|
|
3627
3561
|
}
|
|
3628
3562
|
|
|
3629
3563
|
/**
|
|
@@ -3686,6 +3620,55 @@ const setupAnalytics = (projectAccessKey, server) => {
|
|
|
3686
3620
|
});
|
|
3687
3621
|
};
|
|
3688
3622
|
|
|
3623
|
+
var packageJson = {
|
|
3624
|
+
name: "@0xsequence/provider",
|
|
3625
|
+
version: "0.0.0-20240428001038",
|
|
3626
|
+
description: "provider sub-package for Sequence",
|
|
3627
|
+
repository: "https://github.com/0xsequence/sequence.js/tree/master/packages/provider",
|
|
3628
|
+
source: "src/index.ts",
|
|
3629
|
+
main: "dist/0xsequence-provider.cjs.js",
|
|
3630
|
+
module: "dist/0xsequence-provider.esm.js",
|
|
3631
|
+
author: "Horizon Blockchain Games",
|
|
3632
|
+
license: "Apache-2.0",
|
|
3633
|
+
scripts: {
|
|
3634
|
+
test: "pnpm test:concurrently 'pnpm test:run'",
|
|
3635
|
+
"test:run": "pnpm test:file tests/**/*.spec.ts",
|
|
3636
|
+
"test:file": "NODE_OPTIONS='--import tsx' mocha --timeout 30000",
|
|
3637
|
+
typecheck: "tsc --noEmit",
|
|
3638
|
+
"test:concurrently": "concurrently -k --success first 'pnpm start:hardhat1' 'pnpm start:hardhat2'",
|
|
3639
|
+
"start:hardhat1": "pnpm start:hardhat1:verbose > /dev/null 2>&1",
|
|
3640
|
+
"start:hardhat2": "pnpm start:hardhat2:verbose > /dev/null 2>&1",
|
|
3641
|
+
"start:hardhat1:verbose": "hardhat node --config hardhat1.config.js --hostname 0.0.0.0 --port 9595",
|
|
3642
|
+
"start:hardhat2:verbose": "hardhat node --config hardhat2.config.js --hostname 0.0.0.0 --port 8595"
|
|
3643
|
+
},
|
|
3644
|
+
dependencies: {
|
|
3645
|
+
"@0xsequence/abi": "workspace:*",
|
|
3646
|
+
"@0xsequence/account": "workspace:*",
|
|
3647
|
+
"@0xsequence/auth": "workspace:*",
|
|
3648
|
+
"@0xsequence/core": "workspace:*",
|
|
3649
|
+
"@0xsequence/migration": "workspace:*",
|
|
3650
|
+
"@0xsequence/network": "workspace:*",
|
|
3651
|
+
"@0xsequence/relayer": "workspace:*",
|
|
3652
|
+
"@0xsequence/utils": "workspace:*",
|
|
3653
|
+
"@0xsequence/wallet": "workspace:*",
|
|
3654
|
+
"@databeat/tracker": "^0.9.1",
|
|
3655
|
+
eventemitter2: "^6.4.5",
|
|
3656
|
+
"webextension-polyfill": "^0.10.0"
|
|
3657
|
+
},
|
|
3658
|
+
peerDependencies: {
|
|
3659
|
+
ethers: ">=5.5 < 6"
|
|
3660
|
+
},
|
|
3661
|
+
devDependencies: {
|
|
3662
|
+
"@types/webextension-polyfill": "^0.10.0",
|
|
3663
|
+
ethers: "^5.7.2",
|
|
3664
|
+
hardhat: "^2.20.1"
|
|
3665
|
+
},
|
|
3666
|
+
files: [
|
|
3667
|
+
"src",
|
|
3668
|
+
"dist"
|
|
3669
|
+
]
|
|
3670
|
+
};
|
|
3671
|
+
|
|
3689
3672
|
/**
|
|
3690
3673
|
* This session class is meant to persist the state of the wallet connection
|
|
3691
3674
|
* whitin the dapp. This enables the client to retain the wallet address (and some more)
|
|
@@ -3801,7 +3784,7 @@ class SequenceClient {
|
|
|
3801
3784
|
});
|
|
3802
3785
|
this.transport.on('connect', response => {
|
|
3803
3786
|
var _this$callbacks$conne;
|
|
3804
|
-
const chainIdHex = ethers.ethers.
|
|
3787
|
+
const chainIdHex = ethers.ethers.utils.hexValue(this.getChainId());
|
|
3805
3788
|
(_this$callbacks$conne = this.callbacks.connect) == null || _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
|
|
3806
3789
|
// Ignore the full connect response
|
|
3807
3790
|
// use the chainId defined locally
|
|
@@ -3837,7 +3820,7 @@ class SequenceClient {
|
|
|
3837
3820
|
// instead we handle it locally, so we listen for changes in the store
|
|
3838
3821
|
this.defaultChainId.onDefaultChainIdChanged(chainId => {
|
|
3839
3822
|
var _this$callbacks$chain2;
|
|
3840
|
-
const chainIdHex = ethers.ethers.
|
|
3823
|
+
const chainIdHex = ethers.ethers.utils.hexValue(chainId);
|
|
3841
3824
|
(_this$callbacks$chain2 = this.callbacks.chainChanged) == null || _this$callbacks$chain2.forEach(cb => cb(chainIdHex));
|
|
3842
3825
|
});
|
|
3843
3826
|
if (options != null && options.projectAccessKey) {
|
|
@@ -3950,7 +3933,7 @@ class SequenceClient {
|
|
|
3950
3933
|
type: 'connect',
|
|
3951
3934
|
options: _extends({}, options, {
|
|
3952
3935
|
networkId: this.getChainId(),
|
|
3953
|
-
clientVersion:
|
|
3936
|
+
clientVersion: packageJson.version
|
|
3954
3937
|
})
|
|
3955
3938
|
});
|
|
3956
3939
|
const connectDetails = await this.transport.waitUntilConnected().catch(error => {
|
|
@@ -3970,7 +3953,7 @@ class SequenceClient {
|
|
|
3970
3953
|
// Normalize chainId into a decimal string
|
|
3971
3954
|
// TODO: Remove this once wallet-webapp returns chainId as a string
|
|
3972
3955
|
if (connectDetails.chainId) {
|
|
3973
|
-
connectDetails.chainId =
|
|
3956
|
+
connectDetails.chainId = ethers.ethers.BigNumber.from(connectDetails.chainId).toString();
|
|
3974
3957
|
}
|
|
3975
3958
|
if (connectDetails.connected) {
|
|
3976
3959
|
var _connectDetails$sessi;
|
|
@@ -3996,17 +3979,33 @@ class SequenceClient {
|
|
|
3996
3979
|
|
|
3997
3980
|
// Higher level API
|
|
3998
3981
|
|
|
3999
|
-
|
|
3982
|
+
// Working with sendAsync is less idiomatic
|
|
3983
|
+
// but transport uses it instead of send, so we wrap it
|
|
3984
|
+
send(request, chainId) {
|
|
4000
3985
|
// Internally when sending requests we use `legacy_sign`
|
|
4001
3986
|
// to avoid the default EIP6492 behavior overriding an explicit
|
|
4002
3987
|
// "legacy sign" request, so we map the method here.
|
|
4003
3988
|
request.method = this.mapSignMethod(request.method);
|
|
4004
|
-
return
|
|
3989
|
+
return new Promise((resolve, reject) => {
|
|
3990
|
+
this.transport.sendAsync(request, (error, response) => {
|
|
3991
|
+
if (error) {
|
|
3992
|
+
reject(error);
|
|
3993
|
+
} else if (response === undefined) {
|
|
3994
|
+
reject(new Error(`Got undefined response for request: ${request}`));
|
|
3995
|
+
} else if (typeof response === 'object' && response.error) {
|
|
3996
|
+
reject(response.error);
|
|
3997
|
+
} else if (typeof response === 'object' && response.result) {
|
|
3998
|
+
resolve(response.result);
|
|
3999
|
+
} else {
|
|
4000
|
+
reject(new Error(`Got invalid response for request: ${request}`));
|
|
4001
|
+
}
|
|
4002
|
+
}, chainId || this.getChainId());
|
|
4003
|
+
});
|
|
4005
4004
|
}
|
|
4006
4005
|
async getNetworks(pull) {
|
|
4007
4006
|
const connectedSession = this.session.connectedSession();
|
|
4008
4007
|
if (pull) {
|
|
4009
|
-
connectedSession.networks = await this.
|
|
4008
|
+
connectedSession.networks = await this.send({
|
|
4010
4009
|
method: 'sequence_getNetworks'
|
|
4011
4010
|
});
|
|
4012
4011
|
this.session.setSession(connectedSession);
|
|
@@ -4063,16 +4062,14 @@ class SequenceClient {
|
|
|
4063
4062
|
}
|
|
4064
4063
|
});
|
|
4065
4064
|
|
|
4066
|
-
//
|
|
4067
|
-
|
|
4068
|
-
message = ethers.ethers.hexlify(typeof message === 'string' ? ethers.ethers.toUtf8Bytes(message) : message);
|
|
4065
|
+
// Serialize a BytesLike or string message into a hex string before sending
|
|
4066
|
+
message = ethers.ethers.utils.hexlify(messageToBytes(message));
|
|
4069
4067
|
|
|
4070
4068
|
// Address is ignored by the wallet webapp
|
|
4071
|
-
return this.
|
|
4069
|
+
return this.send({
|
|
4072
4070
|
method,
|
|
4073
|
-
params: [message, this.getAddress()]
|
|
4074
|
-
|
|
4075
|
-
});
|
|
4071
|
+
params: [message, this.getAddress()]
|
|
4072
|
+
}, options == null ? void 0 : options.chainId);
|
|
4076
4073
|
}
|
|
4077
4074
|
async signTypedData(typedData, options) {
|
|
4078
4075
|
var _this$analytics5;
|
|
@@ -4080,7 +4077,7 @@ class SequenceClient {
|
|
|
4080
4077
|
|
|
4081
4078
|
// TODO: Stop using ethers for this, this is the only place where we use it
|
|
4082
4079
|
// and it makes the client depend on ethers.
|
|
4083
|
-
const encoded = ethers.ethers.
|
|
4080
|
+
const encoded = ethers.ethers.utils._TypedDataEncoder.getPayload(typedData.domain, typedData.types, typedData.message);
|
|
4084
4081
|
|
|
4085
4082
|
// The sign typed data will use one of the following chainIds, in order:
|
|
4086
4083
|
// - The one provided in the options
|
|
@@ -4093,11 +4090,10 @@ class SequenceClient {
|
|
|
4093
4090
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4094
4091
|
}
|
|
4095
4092
|
});
|
|
4096
|
-
return this.
|
|
4093
|
+
return this.send({
|
|
4097
4094
|
method,
|
|
4098
|
-
params: [this.getAddress(), encoded]
|
|
4099
|
-
|
|
4100
|
-
});
|
|
4095
|
+
params: [this.getAddress(), encoded]
|
|
4096
|
+
}, (options == null ? void 0 : options.chainId) || typedData.domain.chainId && ethers.ethers.BigNumber.from(typedData.domain.chainId).toNumber() || this.getChainId());
|
|
4101
4097
|
}
|
|
4102
4098
|
async sendTransaction(tx, options) {
|
|
4103
4099
|
var _this$analytics6;
|
|
@@ -4109,24 +4105,22 @@ class SequenceClient {
|
|
|
4109
4105
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4110
4106
|
}
|
|
4111
4107
|
});
|
|
4112
|
-
return this.
|
|
4108
|
+
return this.send({
|
|
4113
4109
|
method: 'eth_sendTransaction',
|
|
4114
|
-
params: [extendedTxs]
|
|
4115
|
-
|
|
4116
|
-
});
|
|
4110
|
+
params: [extendedTxs]
|
|
4111
|
+
}, options == null ? void 0 : options.chainId);
|
|
4117
4112
|
}
|
|
4118
4113
|
async getWalletContext() {
|
|
4119
|
-
return this.
|
|
4114
|
+
return this.send({
|
|
4120
4115
|
method: 'sequence_getWalletContext'
|
|
4121
4116
|
});
|
|
4122
4117
|
}
|
|
4123
4118
|
async getOnchainWalletConfig(options) {
|
|
4124
4119
|
// NOTICE: sequence_getWalletConfig sends the chainId as a param
|
|
4125
|
-
const res = await this.
|
|
4120
|
+
const res = await this.send({
|
|
4126
4121
|
method: 'sequence_getWalletConfig',
|
|
4127
|
-
params: [(options == null ? void 0 : options.chainId) || this.getChainId()]
|
|
4128
|
-
|
|
4129
|
-
});
|
|
4122
|
+
params: [(options == null ? void 0 : options.chainId) || this.getChainId()]
|
|
4123
|
+
}, options == null ? void 0 : options.chainId);
|
|
4130
4124
|
return Array.isArray(res) ? res[0] : res;
|
|
4131
4125
|
}
|
|
4132
4126
|
|
|
@@ -4205,11 +4199,9 @@ const initWallet = (projectAccessKey, partialConfig) => {
|
|
|
4205
4199
|
if (!rpcUrl) {
|
|
4206
4200
|
throw new Error(`no rpcUrl found for chainId: ${chainId}`);
|
|
4207
4201
|
}
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
cacheTimeout: -1
|
|
4212
|
-
});
|
|
4202
|
+
const baseProvider = new ethers.ethers.providers.JsonRpcProvider(rpcUrl);
|
|
4203
|
+
const router = new network.JsonRpcRouter([network.loggingProviderMiddleware, network.exceptionProviderMiddleware, new network.CachedProvider()], new network.JsonRpcSender(baseProvider));
|
|
4204
|
+
rpcProviders[chainId] = new ethers.ethers.providers.Web3Provider(router, chainId);
|
|
4213
4205
|
}
|
|
4214
4206
|
return rpcProviders[chainId];
|
|
4215
4207
|
};
|
|
@@ -4298,3 +4290,4 @@ exports.resolveArrayProperties = resolveArrayProperties;
|
|
|
4298
4290
|
exports.trimEIP191Prefix = trimEIP191Prefix;
|
|
4299
4291
|
exports.unregisterWallet = unregisterWallet;
|
|
4300
4292
|
exports.useBestStore = useBestStore;
|
|
4293
|
+
exports.validateTransactionRequest = validateTransactionRequest;
|