@0xsequence/provider 1.10.15 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/0xsequence-provider.cjs.dev.js +656 -648
- package/dist/0xsequence-provider.cjs.prod.js +656 -648
- package/dist/0xsequence-provider.esm.js +660 -652
- 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 +29 -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/wallet-request-handler.ts +91 -130
- package/src/transports/window-transport/window-message-handler.ts +15 -3
- package/src/transports/window-transport/window-message-provider.ts +1 -1
- 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, base64DecodeObject, 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
|
}
|
|
@@ -1876,7 +1882,13 @@ 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, (key, value) => {
|
|
1886
|
+
// BigNumber compatibility with older versions of sequence.js
|
|
1887
|
+
if (isBigNumberSerialized(value)) {
|
|
1888
|
+
return BigInt(value.hex);
|
|
1889
|
+
}
|
|
1890
|
+
return value;
|
|
1891
|
+
});
|
|
1880
1892
|
} catch (err) {
|
|
1881
1893
|
// event is not a ProviderMessage JSON object, skip
|
|
1882
1894
|
return;
|
|
@@ -1915,7 +1927,6 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1915
1927
|
|
|
1916
1928
|
// record open details (sessionId + default network) from the window url
|
|
1917
1929
|
const {
|
|
1918
|
-
pathname,
|
|
1919
1930
|
search: rawParams
|
|
1920
1931
|
} = new URL(windowHref || window.location.href);
|
|
1921
1932
|
let session = this.getWindowTransportSession(rawParams);
|
|
@@ -1999,6 +2010,9 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1999
2010
|
}
|
|
2000
2011
|
}
|
|
2001
2012
|
}
|
|
2013
|
+
const isBigNumberSerialized = value => {
|
|
2014
|
+
return typeof value === 'object' && value.type === 'BigNumber' && ethers.isHexString(value.hex);
|
|
2015
|
+
};
|
|
2002
2016
|
|
|
2003
2017
|
function isMuxTransportTemplate(obj) {
|
|
2004
2018
|
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') && (
|
|
@@ -2049,13 +2063,6 @@ class MuxMessageProvider {
|
|
|
2049
2063
|
}
|
|
2050
2064
|
this.messageProviders.forEach(m => m.openWallet(path, intent, networkId));
|
|
2051
2065
|
};
|
|
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
2066
|
this.sendMessageRequest = async function (message) {
|
|
2060
2067
|
if (_this.provider) {
|
|
2061
2068
|
return _this.provider.sendMessageRequest(message);
|
|
@@ -2152,6 +2159,12 @@ class MuxMessageProvider {
|
|
|
2152
2159
|
}
|
|
2153
2160
|
return true;
|
|
2154
2161
|
}
|
|
2162
|
+
request(request) {
|
|
2163
|
+
if (!this.provider) {
|
|
2164
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
2165
|
+
}
|
|
2166
|
+
return this.provider.request(request);
|
|
2167
|
+
}
|
|
2155
2168
|
sendMessage(message) {
|
|
2156
2169
|
if (!message.idx || message.idx <= 0) {
|
|
2157
2170
|
throw new Error('message idx is empty');
|
|
@@ -2186,7 +2199,7 @@ function fromExtended(transaction) {
|
|
|
2186
2199
|
|
|
2187
2200
|
const SIGNER_READY_TIMEOUT = 10000;
|
|
2188
2201
|
class WalletRequestHandler {
|
|
2189
|
-
constructor(
|
|
2202
|
+
constructor(account, prompter, networks) {
|
|
2190
2203
|
var _this = this;
|
|
2191
2204
|
// signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
|
|
2192
2205
|
// value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
|
|
@@ -2219,417 +2232,6 @@ class WalletRequestHandler {
|
|
|
2219
2232
|
}
|
|
2220
2233
|
return promptConnectDetails;
|
|
2221
2234
|
};
|
|
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
2235
|
this.isSignedIn = async function () {
|
|
2634
2236
|
await _this.signerReady();
|
|
2635
2237
|
return !!_this.account;
|
|
@@ -2641,7 +2243,7 @@ class WalletRequestHandler {
|
|
|
2641
2243
|
}
|
|
2642
2244
|
return _this.account;
|
|
2643
2245
|
};
|
|
2644
|
-
this.account =
|
|
2246
|
+
this.account = account;
|
|
2645
2247
|
this.prompter = prompter;
|
|
2646
2248
|
this.networks = networks;
|
|
2647
2249
|
}
|
|
@@ -2725,7 +2327,7 @@ class WalletRequestHandler {
|
|
|
2725
2327
|
const chainId = findSupportedNetwork(networkId).chainId;
|
|
2726
2328
|
const connectDetails = {
|
|
2727
2329
|
connected: true,
|
|
2728
|
-
chainId: ethers.
|
|
2330
|
+
chainId: ethers.toQuantity(chainId)
|
|
2729
2331
|
};
|
|
2730
2332
|
if (options && options.authorize) {
|
|
2731
2333
|
// Perform ethauth eip712 request and construct the ConnectDetails response
|
|
@@ -2760,20 +2362,415 @@ class WalletRequestHandler {
|
|
|
2760
2362
|
// sendMessageRequest will unwrap the ProviderMessageRequest and send it to the JsonRpcHandler
|
|
2761
2363
|
// (aka, the signer in this instance) and then responds with a wrapped response of
|
|
2762
2364
|
// ProviderMessageResponse to be sent over the transport
|
|
2763
|
-
sendMessageRequest(message) {
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2365
|
+
async sendMessageRequest(message) {
|
|
2366
|
+
var _message$clientVersio;
|
|
2367
|
+
// Older versions of the client require the response to be jsonrpc wrapped
|
|
2368
|
+
const majorVersion = Number(((_message$clientVersio = message.clientVersion) == null ? void 0 : _message$clientVersio.split('.')[0]) || '0');
|
|
2369
|
+
const isJsonRpcResponse = majorVersion < 2;
|
|
2370
|
+
const jsonRpcResponse = {
|
|
2371
|
+
id: message.data.id,
|
|
2372
|
+
jsonrpc: '2.0',
|
|
2373
|
+
result: null,
|
|
2374
|
+
error: undefined
|
|
2375
|
+
};
|
|
2376
|
+
try {
|
|
2377
|
+
const result = await this.request({
|
|
2378
|
+
method: message.data.method,
|
|
2379
|
+
params: message.data.params,
|
|
2380
|
+
chainId: message.chainId
|
|
2381
|
+
});
|
|
2382
|
+
return _extends({}, message, {
|
|
2383
|
+
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2384
|
+
result
|
|
2385
|
+
}) : result
|
|
2386
|
+
});
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
return _extends({}, message, {
|
|
2389
|
+
data: isJsonRpcResponse ? _extends({}, jsonRpcResponse, {
|
|
2390
|
+
error
|
|
2391
|
+
}) : error
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
async request(request) {
|
|
2396
|
+
await this.getAccount();
|
|
2397
|
+
try {
|
|
2398
|
+
var _this$account, _request$chainId;
|
|
2399
|
+
// only allow public json rpc method to the provider when user is not logged in, aka signer is not set
|
|
2400
|
+
if ((!this.account || this.account === null) && !permittedJsonRpcMethods.includes(request.method)) {
|
|
2401
|
+
// throw new Error(`not logged in. ${request.method} is unavailable`)
|
|
2402
|
+
throw ErrSignedInRequired;
|
|
2403
|
+
}
|
|
2767
2404
|
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2405
|
+
// wallet account
|
|
2406
|
+
const account = this.account;
|
|
2407
|
+
if (!account) {
|
|
2408
|
+
throw new Error('WalletRequestHandler: wallet account is not configured');
|
|
2409
|
+
}
|
|
2771
2410
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2411
|
+
// fetch the provider for the specific chain, or undefined will select defaultChain
|
|
2412
|
+
const provider = (_this$account = this.account) == null ? void 0 : _this$account.providerFor((_request$chainId = request.chainId) != null ? _request$chainId : this.defaultChainId());
|
|
2413
|
+
if (!provider) {
|
|
2414
|
+
throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${request.chainId}`);
|
|
2415
|
+
}
|
|
2416
|
+
const jsonRpcProvider = provider instanceof ethers.JsonRpcProvider ? provider : undefined;
|
|
2417
|
+
switch (request.method) {
|
|
2418
|
+
case 'net_version':
|
|
2419
|
+
{
|
|
2420
|
+
if (!jsonRpcProvider) {
|
|
2421
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2422
|
+
}
|
|
2423
|
+
return await jsonRpcProvider.send('net_version', []);
|
|
2424
|
+
}
|
|
2425
|
+
case 'eth_chainId':
|
|
2426
|
+
{
|
|
2427
|
+
if (!jsonRpcProvider) {
|
|
2428
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2429
|
+
}
|
|
2430
|
+
return await jsonRpcProvider.send('eth_chainId', []);
|
|
2431
|
+
}
|
|
2432
|
+
case 'eth_accounts':
|
|
2433
|
+
{
|
|
2434
|
+
return [account.address];
|
|
2435
|
+
}
|
|
2436
|
+
case 'eth_getBalance':
|
|
2437
|
+
{
|
|
2438
|
+
const [accountAddress, blockTag] = request.params;
|
|
2439
|
+
const walletBalance = await provider.getBalance(accountAddress, blockTag);
|
|
2440
|
+
return toHexString(walletBalance);
|
|
2441
|
+
}
|
|
2442
|
+
case 'sequence_sign':
|
|
2443
|
+
case 'personal_sign':
|
|
2444
|
+
case 'eth_sign':
|
|
2445
|
+
{
|
|
2446
|
+
// note: message from json-rpc input is in hex format
|
|
2447
|
+
let message;
|
|
2448
|
+
|
|
2449
|
+
// there is a difference in the order of the params:
|
|
2450
|
+
// sequence_sign, personal_sign: [data, address]
|
|
2451
|
+
// eth_sign: [address, data]
|
|
2452
|
+
switch (request.method) {
|
|
2453
|
+
case 'sequence_sign':
|
|
2454
|
+
case 'personal_sign':
|
|
2455
|
+
{
|
|
2456
|
+
const [data, _address] = request.params;
|
|
2457
|
+
message = data;
|
|
2458
|
+
break;
|
|
2459
|
+
}
|
|
2460
|
+
case 'eth_sign':
|
|
2461
|
+
{
|
|
2462
|
+
const [_address, data] = request.params;
|
|
2463
|
+
message = data;
|
|
2464
|
+
break;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
let sig = '';
|
|
2468
|
+
|
|
2469
|
+
// Message must be prefixed with "\x19Ethereum Signed Message:\n"
|
|
2470
|
+
// as defined by EIP-191
|
|
2471
|
+
const prefixedMessage = prefixEIP191Message(message);
|
|
2472
|
+
|
|
2473
|
+
// TODO:
|
|
2474
|
+
// if (process.env.TEST_MODE === 'true' && this.prompter === null) {
|
|
2475
|
+
const sequenceVerified = request.method === 'sequence_sign';
|
|
2476
|
+
if (this.prompter === null) {
|
|
2477
|
+
var _request$chainId2;
|
|
2478
|
+
// prompter is null, so we'll sign from here
|
|
2479
|
+
sig = await account.signMessage(prefixedMessage, (_request$chainId2 = request.chainId) != null ? _request$chainId2 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2480
|
+
} else {
|
|
2481
|
+
sig = await this.prompter.promptSignMessage({
|
|
2482
|
+
chainId: request.chainId,
|
|
2483
|
+
message: ethers.getBytes(prefixedMessage),
|
|
2484
|
+
eip6492: sequenceVerified
|
|
2485
|
+
}, this.connectOptions);
|
|
2486
|
+
}
|
|
2487
|
+
if (sig && sig.length > 0) {
|
|
2488
|
+
return sig;
|
|
2489
|
+
} else {
|
|
2490
|
+
// The user has declined the request when value is null
|
|
2491
|
+
throw new Error('declined by user');
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
case 'sequence_signTypedData_v4':
|
|
2495
|
+
case 'eth_signTypedData':
|
|
2496
|
+
case 'eth_signTypedData_v4':
|
|
2497
|
+
{
|
|
2498
|
+
// note: signingAddress from json-rpc input is in hex format, and typedDataObject
|
|
2499
|
+
// should be an object, but in some instances may be double string encoded
|
|
2500
|
+
const [signingAddress, typedDataObject] = request.params;
|
|
2501
|
+
let typedData = undefined;
|
|
2502
|
+
if (typeof typedDataObject === 'string') {
|
|
2503
|
+
try {
|
|
2504
|
+
typedData = JSON.parse(typedDataObject);
|
|
2505
|
+
} catch (e) {
|
|
2506
|
+
console.warn('walletRequestHandler: error parsing typedData', e);
|
|
2507
|
+
}
|
|
2508
|
+
} else {
|
|
2509
|
+
typedData = typedDataObject;
|
|
2510
|
+
}
|
|
2511
|
+
if (!typedData || !typedData.domain || !typedData.types || !typedData.message) {
|
|
2512
|
+
throw new Error('invalid typedData object');
|
|
2513
|
+
}
|
|
2514
|
+
let sig = '';
|
|
2515
|
+
const sequenceVerified = request.method === 'sequence_signTypedData_v4';
|
|
2516
|
+
if (this.prompter === null) {
|
|
2517
|
+
var _request$chainId3;
|
|
2518
|
+
// prompter is null, so we'll sign from here
|
|
2519
|
+
sig = await account.signTypedData(typedData.domain, typedData.types, typedData.message, (_request$chainId3 = request.chainId) != null ? _request$chainId3 : this.defaultChainId(), sequenceVerified ? 'eip6492' : 'ignore');
|
|
2520
|
+
} else {
|
|
2521
|
+
sig = await this.prompter.promptSignMessage({
|
|
2522
|
+
chainId: request.chainId,
|
|
2523
|
+
typedData: typedData,
|
|
2524
|
+
eip6492: sequenceVerified
|
|
2525
|
+
}, this.connectOptions);
|
|
2526
|
+
}
|
|
2527
|
+
if (sig && sig.length > 0) {
|
|
2528
|
+
return sig;
|
|
2529
|
+
} else {
|
|
2530
|
+
// The user has declined the request when value is null
|
|
2531
|
+
throw new Error('declined by user');
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
case 'eth_sendTransaction':
|
|
2535
|
+
{
|
|
2536
|
+
// https://eth.wiki/json-rpc/API#eth_sendtransaction
|
|
2537
|
+
const transactionParams = fromExtended(request.params[0]).map(tx => {
|
|
2538
|
+
// eth_sendTransaction uses 'gas'
|
|
2539
|
+
// ethers and sequence use 'gasLimit'
|
|
2540
|
+
if ('gas' in tx && tx.gasLimit === undefined) {
|
|
2541
|
+
tx.gasLimit = tx.gas;
|
|
2542
|
+
delete tx.gas;
|
|
2543
|
+
}
|
|
2544
|
+
return tx;
|
|
2545
|
+
});
|
|
2546
|
+
validateTransactionRequest(account.address, transactionParams);
|
|
2547
|
+
let txnHash = '';
|
|
2548
|
+
if (this.prompter === null) {
|
|
2549
|
+
var _request$chainId4, _txnResponse$hash;
|
|
2550
|
+
// prompter is null, so we'll send from here
|
|
2551
|
+
const txnResponse = await account.sendTransaction(transactionParams, (_request$chainId4 = request.chainId) != null ? _request$chainId4 : this.defaultChainId());
|
|
2552
|
+
txnHash = (_txnResponse$hash = txnResponse == null ? void 0 : txnResponse.hash) != null ? _txnResponse$hash : '';
|
|
2553
|
+
} else {
|
|
2554
|
+
// prompt user to provide the response
|
|
2555
|
+
txnHash = await this.prompter.promptSendTransaction(transactionParams, request.chainId, this.connectOptions);
|
|
2556
|
+
}
|
|
2557
|
+
if (txnHash) {
|
|
2558
|
+
return txnHash;
|
|
2559
|
+
} else {
|
|
2560
|
+
// The user has declined the request when value is null
|
|
2561
|
+
throw new Error('declined by user');
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
case 'eth_signTransaction':
|
|
2565
|
+
{
|
|
2566
|
+
// https://eth.wiki/json-rpc/API#eth_signTransaction
|
|
2567
|
+
const [transaction] = request.params;
|
|
2568
|
+
const sender = ethers.getAddress(transaction.from);
|
|
2569
|
+
if (sender !== account.address) {
|
|
2570
|
+
throw new Error('sender address does not match wallet');
|
|
2571
|
+
}
|
|
2572
|
+
validateTransactionRequest(account.address, transaction);
|
|
2573
|
+
if (this.prompter === null) {
|
|
2574
|
+
var _request$chainId5;
|
|
2575
|
+
// The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
|
|
2576
|
+
// this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
|
|
2577
|
+
//
|
|
2578
|
+
// TODO: verify serializing / transporting the SignedTransaction object works as expected, most likely however
|
|
2579
|
+
// we will want to resolveProperties the big number values to hex strings
|
|
2580
|
+
return await account.signTransactions(transaction, (_request$chainId5 = request.chainId) != null ? _request$chainId5 : this.defaultChainId());
|
|
2581
|
+
} else {
|
|
2582
|
+
return await this.prompter.promptSignTransaction(transaction, request.chainId, this.connectOptions);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
case 'eth_sendRawTransaction':
|
|
2586
|
+
{
|
|
2587
|
+
// NOTE: we're not using a prompter here as the transaction is already signed
|
|
2588
|
+
// and would have prompted the user upon signing.
|
|
2589
|
+
|
|
2590
|
+
// https://eth.wiki/json-rpc/API#eth_sendRawTransaction
|
|
2591
|
+
if (commons.transaction.isSignedTransactionBundle(request.params[0])) {
|
|
2592
|
+
const txChainId = Number(request.params[0].chainId);
|
|
2593
|
+
const tx = await account.relayer(txChainId).relay(request.params[0]);
|
|
2594
|
+
return tx.hash;
|
|
2595
|
+
} else {
|
|
2596
|
+
const tx = await provider.broadcastTransaction(request.params[0]);
|
|
2597
|
+
return tx.hash;
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
case 'eth_getTransactionCount':
|
|
2601
|
+
{
|
|
2602
|
+
const address = ethers.getAddress(request.params[0]);
|
|
2603
|
+
const tag = request.params[1];
|
|
2604
|
+
|
|
2605
|
+
// TODO: Maybe we should fetch this data from the relayer or from the reader
|
|
2606
|
+
// but for now we keep it simple and just use the provider
|
|
2607
|
+
|
|
2608
|
+
const count = await provider.getTransactionCount(address, tag);
|
|
2609
|
+
return toHexString(BigInt(count));
|
|
2610
|
+
}
|
|
2611
|
+
case 'eth_blockNumber':
|
|
2612
|
+
{
|
|
2613
|
+
return await provider.getBlockNumber();
|
|
2614
|
+
}
|
|
2615
|
+
case 'eth_getBlockByNumber':
|
|
2616
|
+
{
|
|
2617
|
+
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2618
|
+
}
|
|
2619
|
+
case 'eth_getBlockByHash':
|
|
2620
|
+
{
|
|
2621
|
+
return await provider.getBlock(request.params[0] /* , jsonRpcRequest.params[1] */);
|
|
2622
|
+
}
|
|
2623
|
+
case 'eth_getTransactionByHash':
|
|
2624
|
+
{
|
|
2625
|
+
return await provider.getTransaction(request.params[0]);
|
|
2626
|
+
}
|
|
2627
|
+
case 'eth_call':
|
|
2628
|
+
{
|
|
2629
|
+
const [transactionObject, blockTag] = request.params;
|
|
2630
|
+
return await provider.call(_extends({}, transactionObject, {
|
|
2631
|
+
blockTag
|
|
2632
|
+
}));
|
|
2633
|
+
}
|
|
2634
|
+
case 'eth_getCode':
|
|
2635
|
+
{
|
|
2636
|
+
const [contractAddress, blockTag] = request.params;
|
|
2637
|
+
return await provider.getCode(contractAddress, blockTag);
|
|
2638
|
+
}
|
|
2639
|
+
case 'eth_estimateGas':
|
|
2640
|
+
{
|
|
2641
|
+
const [transactionObject] = request.params;
|
|
2642
|
+
return await provider.estimateGas(transactionObject);
|
|
2643
|
+
}
|
|
2644
|
+
case 'eth_gasPrice':
|
|
2645
|
+
{
|
|
2646
|
+
const feeData = await provider.getFeeData();
|
|
2647
|
+
return feeData.gasPrice === null ? null : toHexString(feeData.gasPrice);
|
|
2648
|
+
}
|
|
2649
|
+
case 'wallet_switchEthereumChain':
|
|
2650
|
+
{
|
|
2651
|
+
const [switchParams] = request.params;
|
|
2652
|
+
if (!switchParams.chainId || switchParams.chainId.length === 0) {
|
|
2653
|
+
throw new Error('invalid chainId');
|
|
2654
|
+
}
|
|
2655
|
+
const chainId = BigInt(switchParams.chainId);
|
|
2656
|
+
this.setDefaultChainId(Number(chainId));
|
|
2657
|
+
return null; // success
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// smart wallet method
|
|
2661
|
+
case 'sequence_getWalletContext':
|
|
2662
|
+
{
|
|
2663
|
+
return account.contexts;
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
// smart wallet method
|
|
2667
|
+
case 'sequence_getWalletConfig':
|
|
2668
|
+
{
|
|
2669
|
+
const [chainId] = request.params;
|
|
2670
|
+
if (chainId) {
|
|
2671
|
+
return [(await account.status(chainId)).onChain.config];
|
|
2672
|
+
} else {
|
|
2673
|
+
return await Promise.all(account.networks.map(async function (network) {
|
|
2674
|
+
const status = await account.status(network.chainId);
|
|
2675
|
+
return status.onChain.config;
|
|
2676
|
+
}));
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// smart wallet method
|
|
2681
|
+
case 'sequence_getWalletState':
|
|
2682
|
+
{
|
|
2683
|
+
const [chainId] = request.params;
|
|
2684
|
+
// TODO: Add getWalletState to the Signer interface
|
|
2685
|
+
if (chainId) {
|
|
2686
|
+
return [getLegacyWalletState(chainId, await account.status(chainId))];
|
|
2687
|
+
} else {
|
|
2688
|
+
return await Promise.all(account.networks.map(async function (network) {
|
|
2689
|
+
const status = await account.status(network.chainId);
|
|
2690
|
+
return getLegacyWalletState(network.chainId, status);
|
|
2691
|
+
}));
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
// smart wallet method
|
|
2696
|
+
case 'sequence_getNetworks':
|
|
2697
|
+
{
|
|
2698
|
+
// NOTE: must ensure that the response result below returns clean serialized data, which is to omit
|
|
2699
|
+
// the provider and relayer objects and only return the urls so can be reinstantiated on dapp side.
|
|
2700
|
+
// This is handled by this.getNetworks() but noted here for future readers.
|
|
2701
|
+
return await this.getNetworks(true);
|
|
2702
|
+
}
|
|
2703
|
+
case 'sequence_isSequence':
|
|
2704
|
+
{
|
|
2705
|
+
return true;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// smart wallet method
|
|
2709
|
+
case 'sequence_updateConfig':
|
|
2710
|
+
{
|
|
2711
|
+
throw new Error('sequence_updateConfig method is not allowed from a dapp');
|
|
2712
|
+
// NOTE: method is disabled as we don't need a dapp to request to update a config.
|
|
2713
|
+
// However, if we ever want this, we can enable it but must also use the prompter
|
|
2714
|
+
// for confirmation.
|
|
2715
|
+
//
|
|
2716
|
+
// const [newConfig] = request.params
|
|
2717
|
+
// return await signer.updateConfig(newConfig)
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
// smart wallet method
|
|
2721
|
+
case 'sequence_publishConfig':
|
|
2722
|
+
{
|
|
2723
|
+
throw new Error('sequence_publishConfig method is not allowed from a dapp');
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// relayer method
|
|
2727
|
+
case 'sequence_gasRefundOptions':
|
|
2728
|
+
{
|
|
2729
|
+
// TODO
|
|
2730
|
+
break;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// relayer method
|
|
2734
|
+
case 'sequence_getNonce':
|
|
2735
|
+
{
|
|
2736
|
+
// TODO
|
|
2737
|
+
break;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2740
|
+
// relayer method
|
|
2741
|
+
case 'sequence_relay':
|
|
2742
|
+
{
|
|
2743
|
+
// TODO
|
|
2744
|
+
break;
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
// set default network of wallet
|
|
2748
|
+
case 'sequence_setDefaultNetwork':
|
|
2749
|
+
{
|
|
2750
|
+
const [defaultChainId] = request.params;
|
|
2751
|
+
if (!defaultChainId) {
|
|
2752
|
+
throw new Error('invalid request, method argument defaultChainId cannot be empty');
|
|
2753
|
+
}
|
|
2754
|
+
this.setDefaultChainId(defaultChainId);
|
|
2755
|
+
return await this.getNetworks(true);
|
|
2756
|
+
}
|
|
2757
|
+
default:
|
|
2758
|
+
{
|
|
2759
|
+
if (!jsonRpcProvider) {
|
|
2760
|
+
throw new Error(`Account provider doesn't support send method`);
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
// NOTE: provider here will be chain-bound if chainId is provided
|
|
2764
|
+
return await jsonRpcProvider.send(request.method, request.params);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
} catch (err) {
|
|
2768
|
+
logger.error(err);
|
|
2769
|
+
throw {
|
|
2770
|
+
message: err == null ? void 0 : err.message,
|
|
2771
|
+
code: 4001
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2777
2774
|
}
|
|
2778
2775
|
on(event, fn) {
|
|
2779
2776
|
this.events.on(event, fn);
|
|
@@ -2861,7 +2858,7 @@ class WalletRequestHandler {
|
|
|
2861
2858
|
this.events.emit('disconnect', undefined, origin);
|
|
2862
2859
|
}
|
|
2863
2860
|
notifyChainChanged(chainId, origin) {
|
|
2864
|
-
this.events.emit('chainChanged', ethers.
|
|
2861
|
+
this.events.emit('chainChanged', ethers.toQuantity(chainId), origin);
|
|
2865
2862
|
}
|
|
2866
2863
|
async notifyNetworks(networks) {
|
|
2867
2864
|
const n = networks || (await this.getNetworks(true));
|
|
@@ -2869,7 +2866,7 @@ class WalletRequestHandler {
|
|
|
2869
2866
|
if (n.length > 0) {
|
|
2870
2867
|
const defaultNetwork = n.find(network => network.chainId === this.defaultChainId());
|
|
2871
2868
|
if (defaultNetwork) {
|
|
2872
|
-
this.events.emit('chainChanged', ethers.
|
|
2869
|
+
this.events.emit('chainChanged', ethers.toQuantity(defaultNetwork.chainId));
|
|
2873
2870
|
}
|
|
2874
2871
|
} else {
|
|
2875
2872
|
this.events.emit('chainChanged', '0x0');
|
|
@@ -2938,6 +2935,19 @@ function getLegacyWalletState(chainId, status) {
|
|
|
2938
2935
|
}
|
|
2939
2936
|
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
2937
|
|
|
2938
|
+
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
2939
|
+
if (source == null) return {};
|
|
2940
|
+
var target = {};
|
|
2941
|
+
var sourceKeys = Object.keys(source);
|
|
2942
|
+
var key, i;
|
|
2943
|
+
for (i = 0; i < sourceKeys.length; i++) {
|
|
2944
|
+
key = sourceKeys[i];
|
|
2945
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
2946
|
+
target[key] = source[key];
|
|
2947
|
+
}
|
|
2948
|
+
return target;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2941
2951
|
class SequenceSigner {
|
|
2942
2952
|
get utils() {
|
|
2943
2953
|
return this.provider.utils;
|
|
@@ -2946,7 +2956,6 @@ class SequenceSigner {
|
|
|
2946
2956
|
this.client = client;
|
|
2947
2957
|
this.provider = provider;
|
|
2948
2958
|
this.singleNetworkSigners = {};
|
|
2949
|
-
this._isSigner = true;
|
|
2950
2959
|
this._isSequenceSigner = true;
|
|
2951
2960
|
}
|
|
2952
2961
|
async getAddress() {
|
|
@@ -3016,12 +3025,17 @@ class SequenceSigner {
|
|
|
3016
3025
|
});
|
|
3017
3026
|
const provider = this.getProvider(chainId);
|
|
3018
3027
|
try {
|
|
3019
|
-
|
|
3020
|
-
const
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3028
|
+
const result = await new Promise(resolve => {
|
|
3029
|
+
const check = async function check() {
|
|
3030
|
+
const tx = await provider.getTransaction(txHash);
|
|
3031
|
+
if (tx !== null) {
|
|
3032
|
+
return resolve(tx);
|
|
3033
|
+
}
|
|
3034
|
+
await provider.once('block', check);
|
|
3035
|
+
};
|
|
3036
|
+
check();
|
|
3024
3037
|
});
|
|
3038
|
+
return result;
|
|
3025
3039
|
} catch (err) {
|
|
3026
3040
|
err.transactionHash = txHash;
|
|
3027
3041
|
throw err;
|
|
@@ -3043,15 +3057,12 @@ class SequenceSigner {
|
|
|
3043
3057
|
async estimateGas(transaction, optionals) {
|
|
3044
3058
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).estimateGas(transaction);
|
|
3045
3059
|
}
|
|
3046
|
-
async call(transaction,
|
|
3047
|
-
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction
|
|
3060
|
+
async call(transaction, optionals) {
|
|
3061
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction);
|
|
3048
3062
|
}
|
|
3049
3063
|
getChainId() {
|
|
3050
3064
|
return Promise.resolve(this.client.getChainId());
|
|
3051
3065
|
}
|
|
3052
|
-
async getGasPrice(optionals) {
|
|
3053
|
-
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getGasPrice();
|
|
3054
|
-
}
|
|
3055
3066
|
async getFeeData(optionals) {
|
|
3056
3067
|
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getFeeData();
|
|
3057
3068
|
}
|
|
@@ -3059,7 +3070,7 @@ class SequenceSigner {
|
|
|
3059
3070
|
const res = await this.provider.resolveName(name);
|
|
3060
3071
|
|
|
3061
3072
|
// For some reason ethers.Signer expects this to return `string`
|
|
3062
|
-
// but ethers.
|
|
3073
|
+
// but ethers.Provider expects this to return `string | null`.
|
|
3063
3074
|
// The signer doesn't have any other source of information, so we'll
|
|
3064
3075
|
// fail if the provider doesn't return a result.
|
|
3065
3076
|
if (res === null) {
|
|
@@ -3070,6 +3081,12 @@ class SequenceSigner {
|
|
|
3070
3081
|
_checkProvider(_operation) {
|
|
3071
3082
|
// We always have a provider, so this is a noop
|
|
3072
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
|
+
}
|
|
3073
3090
|
populateTransaction(_transaction) {
|
|
3074
3091
|
throw new Error('SequenceSigner does not support populateTransaction');
|
|
3075
3092
|
}
|
|
@@ -3207,31 +3224,43 @@ class WalletUtils {
|
|
|
3207
3224
|
// recoverAddress()
|
|
3208
3225
|
}
|
|
3209
3226
|
|
|
3210
|
-
|
|
3211
|
-
|
|
3227
|
+
const _excluded = ["method"];
|
|
3228
|
+
const EIP1193EventTypes = ['connect', 'disconnect', 'chainChanged', 'accountsChanged'];
|
|
3229
|
+
class SequenceProvider extends ethers.AbstractProvider {
|
|
3230
|
+
constructor(client, providerFor, networks = allNetworks, options) {
|
|
3212
3231
|
// We support a lot of networks
|
|
3213
3232
|
// but we start with the default one
|
|
3214
|
-
super(client.getChainId());
|
|
3233
|
+
super(client.getChainId(), options);
|
|
3215
3234
|
|
|
3216
3235
|
// Emit events as defined by EIP-1193
|
|
3217
3236
|
this.client = client;
|
|
3218
3237
|
this.providerFor = providerFor;
|
|
3219
3238
|
this.networks = networks;
|
|
3239
|
+
this.options = options;
|
|
3220
3240
|
this.singleNetworkProviders = {};
|
|
3221
3241
|
this._isSequenceProvider = true;
|
|
3222
3242
|
this.utils = void 0;
|
|
3223
3243
|
this.signer = void 0;
|
|
3244
|
+
this.eip1193EventListeners = new Map();
|
|
3224
3245
|
client.onConnect(details => {
|
|
3225
|
-
|
|
3246
|
+
var _this$eip1193EventLis;
|
|
3247
|
+
//this.emit('connect', details)
|
|
3248
|
+
(_this$eip1193EventLis = this.eip1193EventListeners.get('connect')) == null || _this$eip1193EventLis.forEach(listener => listener(details));
|
|
3226
3249
|
});
|
|
3227
3250
|
client.onDisconnect(error => {
|
|
3228
|
-
|
|
3251
|
+
var _this$eip1193EventLis2;
|
|
3252
|
+
//this.emit('disconnect', error)
|
|
3253
|
+
(_this$eip1193EventLis2 = this.eip1193EventListeners.get('disconnect')) == null || _this$eip1193EventLis2.forEach(listener => listener(error));
|
|
3229
3254
|
});
|
|
3230
3255
|
client.onDefaultChainIdChanged(chainId => {
|
|
3231
|
-
|
|
3256
|
+
var _this$eip1193EventLis3;
|
|
3257
|
+
//this.emit('chainChanged', chainId)
|
|
3258
|
+
(_this$eip1193EventLis3 = this.eip1193EventListeners.get('chainChanged')) == null || _this$eip1193EventLis3.forEach(listener => listener(chainId));
|
|
3232
3259
|
});
|
|
3233
3260
|
client.onAccountsChanged(accounts => {
|
|
3234
|
-
|
|
3261
|
+
var _this$eip1193EventLis4;
|
|
3262
|
+
//this.emit('accountsChanged', accounts)
|
|
3263
|
+
(_this$eip1193EventLis4 = this.eip1193EventListeners.get('accountsChanged')) == null || _this$eip1193EventLis4.forEach(listener => listener(accounts));
|
|
3235
3264
|
});
|
|
3236
3265
|
|
|
3237
3266
|
// NOTICE: We don't emit 'open' and 'close' events
|
|
@@ -3248,6 +3277,29 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3248
3277
|
// Create a utils instance
|
|
3249
3278
|
this.utils = new WalletUtils(this.signer);
|
|
3250
3279
|
}
|
|
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
|
+
}
|
|
3251
3303
|
getSigner(chainId) {
|
|
3252
3304
|
return this.signer.getSigner(chainId);
|
|
3253
3305
|
}
|
|
@@ -3340,7 +3392,7 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3340
3392
|
}
|
|
3341
3393
|
const useChainId = this.toChainId(chainId);
|
|
3342
3394
|
if (!this.singleNetworkProviders[useChainId]) {
|
|
3343
|
-
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId);
|
|
3395
|
+
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId, this.options);
|
|
3344
3396
|
}
|
|
3345
3397
|
return this.singleNetworkProviders[useChainId];
|
|
3346
3398
|
}
|
|
@@ -3360,11 +3412,26 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3360
3412
|
}
|
|
3361
3413
|
return provider;
|
|
3362
3414
|
}
|
|
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
|
+
}
|
|
3363
3431
|
async perform(method, params) {
|
|
3364
|
-
var _provider$prepareRequ;
|
|
3365
3432
|
// First we check if the method should be handled by the client
|
|
3366
3433
|
if (method === 'eth_chainId') {
|
|
3367
|
-
return ethers.
|
|
3434
|
+
return ethers.toQuantity(await this.useChainId());
|
|
3368
3435
|
}
|
|
3369
3436
|
if (method === 'eth_accounts') {
|
|
3370
3437
|
return [this.client.getAddress()];
|
|
@@ -3384,17 +3451,15 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3384
3451
|
method === 'sequence_sign' || method === 'sequence_signTypedData_v4') {
|
|
3385
3452
|
// We pass the chainId to the client, if we don't pass one
|
|
3386
3453
|
// the client will use its own default chainId
|
|
3387
|
-
return this.client.
|
|
3454
|
+
return this.client.request({
|
|
3388
3455
|
method,
|
|
3389
|
-
params
|
|
3390
|
-
|
|
3456
|
+
params,
|
|
3457
|
+
chainId: this.getChainId()
|
|
3458
|
+
});
|
|
3391
3459
|
}
|
|
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]);
|
|
3460
|
+
return this._perform(_extends({
|
|
3461
|
+
method
|
|
3462
|
+
}, params));
|
|
3398
3463
|
}
|
|
3399
3464
|
send(method, params) {
|
|
3400
3465
|
return this.perform(method, params);
|
|
@@ -3402,14 +3467,18 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3402
3467
|
request(request) {
|
|
3403
3468
|
return this.perform(request.method, request.params);
|
|
3404
3469
|
}
|
|
3405
|
-
async
|
|
3470
|
+
async _detectNetwork() {
|
|
3406
3471
|
const chainId = this.client.getChainId();
|
|
3407
|
-
const
|
|
3408
|
-
if (!
|
|
3472
|
+
const found = findNetworkConfig(this.networks, chainId);
|
|
3473
|
+
if (!found) {
|
|
3409
3474
|
throw new Error(`Unknown network ${chainId}`);
|
|
3410
3475
|
}
|
|
3476
|
+
const network = new ethers.Network(found.name, found.chainId);
|
|
3411
3477
|
return network;
|
|
3412
3478
|
}
|
|
3479
|
+
async detectNetwork() {
|
|
3480
|
+
return this._detectNetwork();
|
|
3481
|
+
}
|
|
3413
3482
|
|
|
3414
3483
|
// Override most of the methods, so we add support for an optional chainId
|
|
3415
3484
|
// argument, which is used to select the provider to use.
|
|
@@ -3426,9 +3495,9 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3426
3495
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3427
3496
|
return provider.getBlockNumber();
|
|
3428
3497
|
}
|
|
3429
|
-
async
|
|
3498
|
+
async getFeeData(optionals) {
|
|
3430
3499
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3431
|
-
return provider.
|
|
3500
|
+
return provider.getFeeData();
|
|
3432
3501
|
}
|
|
3433
3502
|
async getBalance(addressOrName, blockTag, optionals) {
|
|
3434
3503
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3442,21 +3511,21 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3442
3511
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3443
3512
|
return provider.getCode(addressOrName, blockTag);
|
|
3444
3513
|
}
|
|
3445
|
-
async
|
|
3514
|
+
async getStorage(addressOrName, position, blockTag, optionals) {
|
|
3446
3515
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3447
|
-
return provider.
|
|
3516
|
+
return provider.getStorage(addressOrName, position, blockTag);
|
|
3448
3517
|
}
|
|
3449
|
-
async call(transaction,
|
|
3518
|
+
async call(transaction, optionals) {
|
|
3450
3519
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3451
|
-
return provider.call(transaction
|
|
3520
|
+
return provider.call(transaction);
|
|
3452
3521
|
}
|
|
3453
3522
|
async estimateGas(transaction, optionals) {
|
|
3454
3523
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3455
3524
|
return provider.estimateGas(transaction);
|
|
3456
3525
|
}
|
|
3457
|
-
async getBlock(blockHashOrBlockTag, optionals) {
|
|
3526
|
+
async getBlock(blockHashOrBlockTag, prefetchTxs, optionals) {
|
|
3458
3527
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3459
|
-
return provider.getBlock(blockHashOrBlockTag);
|
|
3528
|
+
return provider.getBlock(blockHashOrBlockTag, prefetchTxs);
|
|
3460
3529
|
}
|
|
3461
3530
|
async getTransaction(transactionHash, optionals) {
|
|
3462
3531
|
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
@@ -3483,7 +3552,7 @@ class SequenceProvider extends ethers.providers.BaseProvider {
|
|
|
3483
3552
|
return provider.getResolver(name);
|
|
3484
3553
|
}
|
|
3485
3554
|
async resolveName(name) {
|
|
3486
|
-
if (ethers.
|
|
3555
|
+
if (ethers.isAddress(name)) {
|
|
3487
3556
|
return name;
|
|
3488
3557
|
}
|
|
3489
3558
|
if (!(await this.supportsENS())) {
|
|
@@ -3516,7 +3585,7 @@ SequenceProvider.is = provider => {
|
|
|
3516
3585
|
};
|
|
3517
3586
|
function normalizeChainId(chainId) {
|
|
3518
3587
|
if (typeof chainId === 'object') return normalizeChainId(chainId.chainId);
|
|
3519
|
-
return
|
|
3588
|
+
return Number(chainId);
|
|
3520
3589
|
}
|
|
3521
3590
|
|
|
3522
3591
|
/**
|
|
@@ -3529,8 +3598,8 @@ function normalizeChainId(chainId) {
|
|
|
3529
3598
|
* NOTICE: These networks won't support ENS unless they are the mainnet.
|
|
3530
3599
|
*/
|
|
3531
3600
|
class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
3532
|
-
constructor(client, providerFor, chainId) {
|
|
3533
|
-
super(client, providerFor);
|
|
3601
|
+
constructor(client, providerFor, chainId, options) {
|
|
3602
|
+
super(client, providerFor, undefined, options);
|
|
3534
3603
|
this.chainId = chainId;
|
|
3535
3604
|
this._isSingleNetworkSequenceProvider = true;
|
|
3536
3605
|
}
|
|
@@ -3549,11 +3618,11 @@ class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
|
3549
3618
|
}
|
|
3550
3619
|
async getNetwork() {
|
|
3551
3620
|
const networks = await this.client.getNetworks();
|
|
3552
|
-
const
|
|
3553
|
-
if (!
|
|
3621
|
+
const found = findNetworkConfig(networks, this.chainId);
|
|
3622
|
+
if (!found) {
|
|
3554
3623
|
throw new Error(`Unsupported network ${this.chainId}`);
|
|
3555
3624
|
}
|
|
3556
|
-
return
|
|
3625
|
+
return new ethers.Network(found.name, found.chainId);
|
|
3557
3626
|
}
|
|
3558
3627
|
|
|
3559
3628
|
/**
|
|
@@ -3616,55 +3685,6 @@ const setupAnalytics = (projectAccessKey, server) => {
|
|
|
3616
3685
|
});
|
|
3617
3686
|
};
|
|
3618
3687
|
|
|
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
3688
|
/**
|
|
3669
3689
|
* This session class is meant to persist the state of the wallet connection
|
|
3670
3690
|
* whitin the dapp. This enables the client to retain the wallet address (and some more)
|
|
@@ -3780,7 +3800,7 @@ class SequenceClient {
|
|
|
3780
3800
|
});
|
|
3781
3801
|
this.transport.on('connect', response => {
|
|
3782
3802
|
var _this$callbacks$conne;
|
|
3783
|
-
const chainIdHex = ethers.
|
|
3803
|
+
const chainIdHex = ethers.toQuantity(this.getChainId());
|
|
3784
3804
|
(_this$callbacks$conne = this.callbacks.connect) == null || _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
|
|
3785
3805
|
// Ignore the full connect response
|
|
3786
3806
|
// use the chainId defined locally
|
|
@@ -3816,7 +3836,7 @@ class SequenceClient {
|
|
|
3816
3836
|
// instead we handle it locally, so we listen for changes in the store
|
|
3817
3837
|
this.defaultChainId.onDefaultChainIdChanged(chainId => {
|
|
3818
3838
|
var _this$callbacks$chain2;
|
|
3819
|
-
const chainIdHex = ethers.
|
|
3839
|
+
const chainIdHex = ethers.toQuantity(chainId);
|
|
3820
3840
|
(_this$callbacks$chain2 = this.callbacks.chainChanged) == null || _this$callbacks$chain2.forEach(cb => cb(chainIdHex));
|
|
3821
3841
|
});
|
|
3822
3842
|
if (options != null && options.projectAccessKey) {
|
|
@@ -3929,7 +3949,7 @@ class SequenceClient {
|
|
|
3929
3949
|
type: 'connect',
|
|
3930
3950
|
options: _extends({}, options, {
|
|
3931
3951
|
networkId: this.getChainId(),
|
|
3932
|
-
clientVersion:
|
|
3952
|
+
clientVersion: VERSION
|
|
3933
3953
|
})
|
|
3934
3954
|
});
|
|
3935
3955
|
const connectDetails = await this.transport.waitUntilConnected().catch(error => {
|
|
@@ -3949,7 +3969,7 @@ class SequenceClient {
|
|
|
3949
3969
|
// Normalize chainId into a decimal string
|
|
3950
3970
|
// TODO: Remove this once wallet-webapp returns chainId as a string
|
|
3951
3971
|
if (connectDetails.chainId) {
|
|
3952
|
-
connectDetails.chainId =
|
|
3972
|
+
connectDetails.chainId = BigInt(connectDetails.chainId).toString();
|
|
3953
3973
|
}
|
|
3954
3974
|
if (connectDetails.connected) {
|
|
3955
3975
|
var _connectDetails$sessi;
|
|
@@ -3975,33 +3995,17 @@ class SequenceClient {
|
|
|
3975
3995
|
|
|
3976
3996
|
// Higher level API
|
|
3977
3997
|
|
|
3978
|
-
|
|
3979
|
-
// but transport uses it instead of send, so we wrap it
|
|
3980
|
-
send(request, chainId) {
|
|
3998
|
+
async request(request) {
|
|
3981
3999
|
// Internally when sending requests we use `legacy_sign`
|
|
3982
4000
|
// to avoid the default EIP6492 behavior overriding an explicit
|
|
3983
4001
|
// "legacy sign" request, so we map the method here.
|
|
3984
4002
|
request.method = this.mapSignMethod(request.method);
|
|
3985
|
-
return
|
|
3986
|
-
this.transport.sendAsync(request, (error, response) => {
|
|
3987
|
-
if (error) {
|
|
3988
|
-
reject(error);
|
|
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
|
-
});
|
|
4003
|
+
return this.transport.request(request);
|
|
4000
4004
|
}
|
|
4001
4005
|
async getNetworks(pull) {
|
|
4002
4006
|
const connectedSession = this.session.connectedSession();
|
|
4003
4007
|
if (pull) {
|
|
4004
|
-
connectedSession.networks = await this.
|
|
4008
|
+
connectedSession.networks = await this.request({
|
|
4005
4009
|
method: 'sequence_getNetworks'
|
|
4006
4010
|
});
|
|
4007
4011
|
this.session.setSession(connectedSession);
|
|
@@ -4057,15 +4061,14 @@ class SequenceClient {
|
|
|
4057
4061
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4058
4062
|
}
|
|
4059
4063
|
});
|
|
4060
|
-
|
|
4061
|
-
// Serialize a BytesLike or string message into a hex string before sending
|
|
4062
|
-
message = ethers.utils.hexlify(messageToBytes(message));
|
|
4064
|
+
message = ethers.hexlify(messageToBytes(message));
|
|
4063
4065
|
|
|
4064
4066
|
// Address is ignored by the wallet webapp
|
|
4065
|
-
return this.
|
|
4067
|
+
return this.request({
|
|
4066
4068
|
method,
|
|
4067
|
-
params: [message, this.getAddress()]
|
|
4068
|
-
|
|
4069
|
+
params: [message, this.getAddress()],
|
|
4070
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4071
|
+
});
|
|
4069
4072
|
}
|
|
4070
4073
|
async signTypedData(typedData, options) {
|
|
4071
4074
|
var _this$analytics5;
|
|
@@ -4073,7 +4076,7 @@ class SequenceClient {
|
|
|
4073
4076
|
|
|
4074
4077
|
// TODO: Stop using ethers for this, this is the only place where we use it
|
|
4075
4078
|
// and it makes the client depend on ethers.
|
|
4076
|
-
const encoded = ethers.
|
|
4079
|
+
const encoded = ethers.TypedDataEncoder.getPayload(typedData.domain, typedData.types, typedData.message);
|
|
4077
4080
|
|
|
4078
4081
|
// The sign typed data will use one of the following chainIds, in order:
|
|
4079
4082
|
// - The one provided in the options
|
|
@@ -4086,10 +4089,11 @@ class SequenceClient {
|
|
|
4086
4089
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4087
4090
|
}
|
|
4088
4091
|
});
|
|
4089
|
-
return this.
|
|
4092
|
+
return this.request({
|
|
4090
4093
|
method,
|
|
4091
|
-
params: [this.getAddress(), encoded]
|
|
4092
|
-
|
|
4094
|
+
params: [this.getAddress(), encoded],
|
|
4095
|
+
chainId: (options == null ? void 0 : options.chainId) || typedData.domain.chainId && Number(typedData.domain.chainId) || this.getChainId()
|
|
4096
|
+
});
|
|
4093
4097
|
}
|
|
4094
4098
|
async sendTransaction(tx, options) {
|
|
4095
4099
|
var _this$analytics6;
|
|
@@ -4101,22 +4105,24 @@ class SequenceClient {
|
|
|
4101
4105
|
chainId: `${(options == null ? void 0 : options.chainId) || this.getChainId()}`
|
|
4102
4106
|
}
|
|
4103
4107
|
});
|
|
4104
|
-
return this.
|
|
4108
|
+
return this.request({
|
|
4105
4109
|
method: 'eth_sendTransaction',
|
|
4106
|
-
params: [extendedTxs]
|
|
4107
|
-
|
|
4110
|
+
params: [extendedTxs],
|
|
4111
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4112
|
+
});
|
|
4108
4113
|
}
|
|
4109
4114
|
async getWalletContext() {
|
|
4110
|
-
return this.
|
|
4115
|
+
return this.request({
|
|
4111
4116
|
method: 'sequence_getWalletContext'
|
|
4112
4117
|
});
|
|
4113
4118
|
}
|
|
4114
4119
|
async getOnchainWalletConfig(options) {
|
|
4115
4120
|
// NOTICE: sequence_getWalletConfig sends the chainId as a param
|
|
4116
|
-
const res = await this.
|
|
4121
|
+
const res = await this.request({
|
|
4117
4122
|
method: 'sequence_getWalletConfig',
|
|
4118
|
-
params: [(options == null ? void 0 : options.chainId) || this.getChainId()]
|
|
4119
|
-
|
|
4123
|
+
params: [(options == null ? void 0 : options.chainId) || this.getChainId()],
|
|
4124
|
+
chainId: options == null ? void 0 : options.chainId
|
|
4125
|
+
});
|
|
4120
4126
|
return Array.isArray(res) ? res[0] : res;
|
|
4121
4127
|
}
|
|
4122
4128
|
|
|
@@ -4195,9 +4201,11 @@ const initWallet = (projectAccessKey, partialConfig) => {
|
|
|
4195
4201
|
if (!rpcUrl) {
|
|
4196
4202
|
throw new Error(`no rpcUrl found for chainId: ${chainId}`);
|
|
4197
4203
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4204
|
+
rpcProviders[chainId] = new JsonRpcProvider(rpcUrl, {
|
|
4205
|
+
middlewares: [loggingProviderMiddleware, exceptionProviderMiddleware, new CachedProvider()]
|
|
4206
|
+
}, {
|
|
4207
|
+
cacheTimeout: -1
|
|
4208
|
+
});
|
|
4201
4209
|
}
|
|
4202
4210
|
return rpcProviders[chainId];
|
|
4203
4211
|
};
|