@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.
Files changed (34) hide show
  1. package/dist/0xsequence-provider.cjs.dev.js +685 -692
  2. package/dist/0xsequence-provider.cjs.prod.js +685 -692
  3. package/dist/0xsequence-provider.esm.js +687 -695
  4. package/dist/declarations/src/client.d.ts +3 -7
  5. package/dist/declarations/src/index.d.ts +1 -0
  6. package/dist/declarations/src/provider.d.ts +22 -31
  7. package/dist/declarations/src/signer.d.ts +14 -15
  8. package/dist/declarations/src/transactions.d.ts +2 -0
  9. package/dist/declarations/src/transports/base-provider-transport.d.ts +2 -6
  10. package/dist/declarations/src/transports/base-wallet-transport.d.ts +2 -6
  11. package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +2 -5
  12. package/dist/declarations/src/transports/wallet-request-handler.d.ts +6 -7
  13. package/dist/declarations/src/types.d.ts +11 -6
  14. package/dist/declarations/src/utils/index.d.ts +3 -3
  15. package/dist/declarations/src/utils.d.ts +7 -7
  16. package/package.json +12 -12
  17. package/src/client.ts +53 -32
  18. package/src/eip191exceptions.ts +2 -2
  19. package/src/extended.ts +5 -5
  20. package/src/index.ts +1 -0
  21. package/src/init.ts +10 -9
  22. package/src/provider.ts +66 -114
  23. package/src/signer.ts +43 -46
  24. package/src/transactions.ts +25 -2
  25. package/src/transports/base-provider-transport.ts +23 -19
  26. package/src/transports/base-wallet-transport.ts +13 -22
  27. package/src/transports/mux-transport/mux-message-provider.ts +6 -5
  28. package/src/transports/proxy-transport/proxy-message-provider.ts +2 -5
  29. package/src/transports/wallet-request-handler.ts +131 -91
  30. package/src/transports/window-transport/window-message-handler.ts +3 -17
  31. package/src/transports/window-transport/window-message-provider.ts +1 -1
  32. package/src/types.ts +11 -8
  33. package/src/utils/index.ts +4 -4
  34. 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.getBytes(message);
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.getBytes(ethers.ethers.concat([eip191prefix, ethers.ethers.toUtf8Bytes(String(messageBytes.length)), messageBytes]));
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.toQuantity(networks.find(network => network.isDefaultChain).chainId));
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, (key, value) => {
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(account, prompter, networks) {
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 = 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.toQuantity(chainId)
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
- async sendMessageRequest(message) {
2360
- var _message$clientVersio;
2361
- // Older versions of the client require the response to be jsonrpc wrapped
2362
- const majorVersion = Number(((_message$clientVersio = message.clientVersion) == null ? void 0 : _message$clientVersio.split('.')[0]) || '0');
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
- // set default network of wallet
2742
- case 'sequence_setDefaultNetwork':
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
- // NOTE: provider here will be chain-bound if chainId is provided
2758
- return await jsonRpcProvider.send(request.method, request.params);
2759
- }
2760
- }
2761
- } catch (err) {
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.toQuantity(chainId), origin);
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.toQuantity(defaultNetwork.chainId));
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
- const result = await new Promise(resolve => {
3022
- let attempts = 0;
3023
- const check = async function check() {
3024
- attempts++;
3025
- const tx = await provider.getTransaction(txHash);
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
- const _excluded = ["method"];
3228
- const EIP1193EventTypes = ['connect', 'disconnect', 'chainChanged', 'accountsChanged'];
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(), options);
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
- var _this$eip1193EventLis;
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
- var _this$eip1193EventLis2;
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
- var _this$eip1193EventLis3;
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
- var _this$eip1193EventLis4;
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, this.options);
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.toQuantity(await this.useChainId());
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.request({
3391
+ return this.client.send({
3455
3392
  method,
3456
- params,
3457
- chainId: this.getChainId()
3458
- });
3393
+ params
3394
+ }, this.getChainId());
3459
3395
  }
3460
- return this._perform(_extends({
3461
- method
3462
- }, params));
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 _detectNetwork() {
3409
+ async detectNetwork() {
3471
3410
  const chainId = this.client.getChainId();
3472
- const found = network.findNetworkConfig(this.networks, chainId);
3473
- if (!found) {
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 getFeeData(optionals) {
3433
+ async getGasPrice(optionals) {
3499
3434
  const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
3500
- return await provider.getFeeData();
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 getStorage(addressOrName, position, blockTag, optionals) {
3449
+ async getStorageAt(addressOrName, position, blockTag, optionals) {
3515
3450
  const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
3516
- return provider.getStorage(addressOrName, position, blockTag);
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, prefetchTxs, optionals) {
3461
+ async getBlock(blockHashOrBlockTag, optionals) {
3527
3462
  const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
3528
- return provider.getBlock(blockHashOrBlockTag, prefetchTxs);
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 Number(BigInt(chainId));
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, options) {
3602
- super(client, providerFor, undefined, options);
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 found = network.findNetworkConfig(networks, this.chainId);
3622
- if (!found) {
3556
+ const res = network.findNetworkConfig(networks, this.chainId);
3557
+ if (!res) {
3623
3558
  throw new Error(`Unsupported network ${this.chainId}`);
3624
3559
  }
3625
- const network$1 = new ethers.ethers.Network(found.name, found.chainId);
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.toQuantity(this.getChainId());
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.toQuantity(chainId);
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: core.VERSION
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 = BigInt(connectDetails.chainId).toString();
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
- async request(request) {
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 this.transport.request(request);
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.request({
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
- // If the message is a string, even if it looks like a BytesLike string we need to represent it as utf8 bytes.
4067
- // ie. '0x1234' is a string, '0x1234' is a bytesLike string which is 2 bytes but we must sign the full '0x1234' as 6 utf8 bytes
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.request({
4069
+ return this.send({
4072
4070
  method,
4073
- params: [message, this.getAddress()],
4074
- chainId: options == null ? void 0 : options.chainId
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.TypedDataEncoder.getPayload(typedData.domain, typedData.types, typedData.message);
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.request({
4093
+ return this.send({
4097
4094
  method,
4098
- params: [this.getAddress(), encoded],
4099
- chainId: (options == null ? void 0 : options.chainId) || typedData.domain.chainId && Number(BigInt(typedData.domain.chainId)) || this.getChainId()
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.request({
4108
+ return this.send({
4113
4109
  method: 'eth_sendTransaction',
4114
- params: [extendedTxs],
4115
- chainId: options == null ? void 0 : options.chainId
4116
- });
4110
+ params: [extendedTxs]
4111
+ }, options == null ? void 0 : options.chainId);
4117
4112
  }
4118
4113
  async getWalletContext() {
4119
- return this.request({
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.request({
4120
+ const res = await this.send({
4126
4121
  method: 'sequence_getWalletConfig',
4127
- params: [(options == null ? void 0 : options.chainId) || this.getChainId()],
4128
- chainId: options == null ? void 0 : options.chainId
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
- rpcProviders[chainId] = new network.JsonRpcProvider(rpcUrl, {
4209
- middlewares: [network.loggingProviderMiddleware, network.exceptionProviderMiddleware, new network.CachedProvider()]
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;