@0xsequence/provider 1.10.15 → 2.0.1

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