@toruslabs/ethereum-controllers 8.17.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/lib.cjs/Account/AccountTrackerController.js +15 -7
  2. package/dist/lib.cjs/AccountAbstraction/AccountAbstractionController.js +4 -6
  3. package/dist/lib.cjs/Eip5792/walletGetCallsStatus.js +2 -2
  4. package/dist/lib.cjs/Eip5792/walletSendCalls.js +8 -9
  5. package/dist/lib.cjs/Eip7702/eip7702Utils.js +3 -3
  6. package/dist/lib.cjs/Gas/GasFeeController.js +3 -2
  7. package/dist/lib.cjs/Keyring/KeyringController.js +69 -40
  8. package/dist/lib.cjs/Message/utils.js +15 -14
  9. package/dist/lib.cjs/Nfts/NftHandler.js +54 -12
  10. package/dist/lib.cjs/Nfts/NftsController.js +1 -4
  11. package/dist/lib.cjs/Preferences/PreferencesController.js +2 -2
  12. package/dist/lib.cjs/Tokens/TokenHandler.js +39 -7
  13. package/dist/lib.cjs/Tokens/TokensController.js +15 -7
  14. package/dist/lib.cjs/Transaction/TransactionController.js +17 -20
  15. package/dist/lib.cjs/Transaction/TransactionGasUtil.js +11 -12
  16. package/dist/lib.cjs/Transaction/TransactionUtils.js +44 -39
  17. package/dist/lib.cjs/index.js +0 -1
  18. package/dist/lib.cjs/types/Account/AccountTrackerController.d.ts +1 -1
  19. package/dist/lib.cjs/types/AccountAbstraction/AccountAbstractionController.d.ts +1 -3
  20. package/dist/lib.cjs/types/Keyring/KeyringController.d.ts +4 -4
  21. package/dist/lib.cjs/types/Nfts/NftHandler.d.ts +4 -3
  22. package/dist/lib.cjs/types/Nfts/NftsController.d.ts +0 -1
  23. package/dist/lib.cjs/types/Tokens/TokenHandler.d.ts +4 -3
  24. package/dist/lib.cjs/types/Tokens/TokensController.d.ts +1 -1
  25. package/dist/lib.cjs/types/Transaction/TransactionUtils.d.ts +11 -3
  26. package/dist/lib.cjs/types/utils/abis.d.ts +544 -99
  27. package/dist/lib.cjs/types/utils/eip5792Types.d.ts +0 -1
  28. package/dist/lib.cjs/types/utils/hex.d.ts +9 -0
  29. package/dist/lib.cjs/types/utils/interfaces.d.ts +205 -2
  30. package/dist/lib.cjs/types/utils/transaction.d.ts +1 -1
  31. package/dist/lib.cjs/types/utils/viem.d.ts +8 -0
  32. package/dist/lib.cjs/utils/abis.js +12 -0
  33. package/dist/lib.cjs/utils/conversionUtils.js +3 -4
  34. package/dist/lib.cjs/utils/eip5792Types.js +0 -2
  35. package/dist/lib.cjs/utils/helpers.js +9 -8
  36. package/dist/lib.cjs/utils/hex.js +23 -0
  37. package/dist/lib.cjs/utils/transaction.js +7 -11
  38. package/dist/lib.cjs/utils/viem.js +214 -0
  39. package/dist/lib.esm/Account/AccountTrackerController.js +15 -7
  40. package/dist/lib.esm/AccountAbstraction/AccountAbstractionController.js +5 -7
  41. package/dist/lib.esm/Eip5792/walletGetCallsStatus.js +1 -1
  42. package/dist/lib.esm/Eip5792/walletSendCalls.js +9 -10
  43. package/dist/lib.esm/Eip7702/eip7702Utils.js +1 -1
  44. package/dist/lib.esm/Gas/GasFeeController.js +3 -2
  45. package/dist/lib.esm/Keyring/KeyringController.js +68 -40
  46. package/dist/lib.esm/Message/utils.js +13 -12
  47. package/dist/lib.esm/Network/createEthereumMiddleware.js +2 -2
  48. package/dist/lib.esm/Nfts/NftHandler.js +54 -12
  49. package/dist/lib.esm/Nfts/NftsController.js +1 -4
  50. package/dist/lib.esm/Preferences/PreferencesController.js +1 -1
  51. package/dist/lib.esm/Tokens/TokenHandler.js +39 -7
  52. package/dist/lib.esm/Tokens/TokensController.js +15 -7
  53. package/dist/lib.esm/Transaction/TransactionController.js +6 -9
  54. package/dist/lib.esm/Transaction/TransactionGasUtil.js +11 -12
  55. package/dist/lib.esm/Transaction/TransactionUtils.js +30 -26
  56. package/dist/lib.esm/index.js +2 -2
  57. package/dist/lib.esm/utils/abis.js +12 -0
  58. package/dist/lib.esm/utils/conversionUtils.js +2 -3
  59. package/dist/lib.esm/utils/eip5792Types.js +1 -2
  60. package/dist/lib.esm/utils/helpers.js +8 -7
  61. package/dist/lib.esm/utils/hex.js +21 -0
  62. package/dist/lib.esm/utils/interfaces.js +64 -0
  63. package/dist/lib.esm/utils/transaction.js +7 -11
  64. package/dist/lib.esm/utils/viem.js +214 -0
  65. package/package.json +13 -18
  66. package/dist/ethereumControllers.umd.min.js +0 -2
  67. package/dist/ethereumControllers.umd.min.js.LICENSE.txt +0 -50
@@ -0,0 +1,214 @@
1
+ 'use strict';
2
+
3
+ var viem = require('viem');
4
+
5
+ // viem's serializeTransaction infers tx type via `if (transaction.type)` which is
6
+ // falsy for type 0 (legacy). Map numeric types to string names so the check passes,
7
+ // and strip undefined/null fields that also break viem's type inference.
8
+ const VIEM_TX_TYPE_NAMES = {
9
+ 0: "legacy",
10
+ 1: "eip2930",
11
+ 2: "eip1559",
12
+ 3: "eip4844",
13
+ 4: "eip7702"
14
+ };
15
+ const VIEM_QUANTITY_FIELDS = ["gasPrice", "maxFeePerGas", "maxPriorityFeePerGas", "maxFeePerBlobGas", "value"];
16
+ function toViemQuantity(value) {
17
+ if (typeof value === "bigint") return value;
18
+ if (typeof value === "number") return BigInt(value);
19
+ if (typeof value === "string" && viem.isHex(value)) return BigInt(value);
20
+ return undefined;
21
+ }
22
+ function toViemNumber(value) {
23
+ if (typeof value === "number") return value;
24
+ if (typeof value === "bigint") return Number(value);
25
+ if (typeof value === "string" && viem.isHex(value)) return Number(value);
26
+ return undefined;
27
+ }
28
+ function toViemHex(value) {
29
+ if (typeof value === "string" && viem.isHex(value)) return value;
30
+ if (value instanceof Uint8Array) return viem.toHex(value);
31
+ return undefined;
32
+ }
33
+ function toViemAddress(value) {
34
+ if (typeof value === "string" && viem.isAddress(value)) return value;
35
+ return undefined;
36
+ }
37
+ function toViemHexArray(value) {
38
+ if (!Array.isArray(value)) return undefined;
39
+ const normalized = [];
40
+ for (const item of value) {
41
+ const hex = toViemHex(item);
42
+ if (!hex) return undefined;
43
+ normalized.push(hex);
44
+ }
45
+ return normalized;
46
+ }
47
+ function toViemAccessList(value) {
48
+ if (!value) return undefined;
49
+ const accessList = [];
50
+ if (Array.isArray(value)) {
51
+ for (const entry of value) {
52
+ if (Array.isArray(entry)) {
53
+ const [addressLike, storageKeysLike] = entry;
54
+ const address = toViemAddress(addressLike);
55
+ const storageKeys = toViemHexArray(storageKeysLike);
56
+ if (!address || !storageKeys) return undefined;
57
+ accessList.push({
58
+ address,
59
+ storageKeys
60
+ });
61
+ continue;
62
+ }
63
+ if (typeof entry === "object" && entry !== null) {
64
+ const address = toViemAddress(entry.address);
65
+ const storageKeys = toViemHexArray(entry.storageKeys);
66
+ if (!address || !storageKeys) return undefined;
67
+ accessList.push({
68
+ address,
69
+ storageKeys
70
+ });
71
+ continue;
72
+ }
73
+ return undefined;
74
+ }
75
+ return accessList;
76
+ }
77
+ if (typeof value === "object") {
78
+ for (const [addressLike, storageKeysLike] of Object.entries(value)) {
79
+ const address = toViemAddress(addressLike);
80
+ const storageKeys = toViemHexArray(storageKeysLike);
81
+ if (!address || !storageKeys) return undefined;
82
+ accessList.push({
83
+ address,
84
+ storageKeys
85
+ });
86
+ }
87
+ return accessList;
88
+ }
89
+ return undefined;
90
+ }
91
+ function toViemAuthorizationList(value) {
92
+ if (!value) return undefined;
93
+ const authorizationList = [];
94
+ for (const authorization of value) {
95
+ const address = toViemAddress(authorization.address);
96
+ const chainId = toViemNumber(authorization.chainId);
97
+ const nonce = toViemNumber(authorization.nonce);
98
+ if (!address || typeof chainId === "undefined" || typeof nonce === "undefined") {
99
+ return undefined;
100
+ }
101
+ const normalizedAuthorization = {
102
+ address,
103
+ chainId,
104
+ nonce
105
+ };
106
+ const signature = authorization.signature;
107
+ if (typeof signature === "string" && viem.isHex(signature)) {
108
+ const parsed = viem.parseSignature(signature);
109
+ normalizedAuthorization.r = parsed.r;
110
+ normalizedAuthorization.s = parsed.s;
111
+ normalizedAuthorization.yParity = parsed.yParity;
112
+ } else if (typeof signature === "object" && signature !== null) {
113
+ const r = toViemHex(signature.r);
114
+ const s = toViemHex(signature.s);
115
+ const yParity = toViemNumber(signature.yParity);
116
+ const vRaw = signature.v;
117
+ const v = typeof vRaw === "bigint" ? vRaw : typeof vRaw === "number" ? BigInt(vRaw) : typeof vRaw === "string" && viem.isHex(vRaw) ? BigInt(vRaw) : undefined;
118
+ if (r && s) {
119
+ normalizedAuthorization.r = r;
120
+ normalizedAuthorization.s = s;
121
+ }
122
+ if (typeof yParity !== "undefined") {
123
+ normalizedAuthorization.yParity = yParity;
124
+ }
125
+ if (typeof v !== "undefined") {
126
+ normalizedAuthorization.v = v;
127
+ }
128
+ }
129
+ authorizationList.push(normalizedAuthorization);
130
+ }
131
+ return authorizationList;
132
+ }
133
+ function toViemBlobs(value) {
134
+ if (!value) return undefined;
135
+ const blobs = [];
136
+ for (const blob of value) {
137
+ if (typeof blob === "string" || blob instanceof Uint8Array) {
138
+ const normalizedBlob = toViemHex(blob);
139
+ if (!normalizedBlob) return undefined;
140
+ blobs.push(normalizedBlob);
141
+ continue;
142
+ }
143
+ if (typeof blob === "object" && blob !== null) {
144
+ const normalizedBlob = toViemHex(blob.data);
145
+ if (!normalizedBlob) return undefined;
146
+ blobs.push(normalizedBlob);
147
+ continue;
148
+ }
149
+ return undefined;
150
+ }
151
+ return blobs;
152
+ }
153
+ /**
154
+ * Prepare transaction params for signing.
155
+ * @param tx - The transaction to prepare.
156
+ * @returns The prepared transaction.
157
+ */
158
+ function prepareViemTx(tx) {
159
+ var _input$gas;
160
+ const input = tx;
161
+ const prepared = {};
162
+ const txType = typeof input.type === "number" ? VIEM_TX_TYPE_NAMES[input.type] : input.type;
163
+ if (typeof txType === "string") {
164
+ prepared.type = txType;
165
+ }
166
+ // For EIP-4844 Transactions, we want to sign the transaction payload body (tx_payload_body) without the sidecars (ie. without the network wrapper).
167
+ // ref: https://github.com/wevm/viem/blob/b3af510a6e2e45526e2bb10298b7fc1f178a73a3/src/accounts/utils/signTransaction.ts#L56
168
+ if (prepared.type === "eip4844") {
169
+ prepared.sidecars = false;
170
+ }
171
+ const chainId = toViemNumber(input.chainId);
172
+ if (typeof chainId !== "undefined") {
173
+ prepared.chainId = chainId;
174
+ }
175
+ const nonce = toViemNumber(input.nonce);
176
+ if (typeof nonce !== "undefined") {
177
+ prepared.nonce = nonce;
178
+ }
179
+ const gas = toViemQuantity((_input$gas = input.gas) !== null && _input$gas !== void 0 ? _input$gas : input.gasLimit);
180
+ if (typeof gas !== "undefined") {
181
+ prepared.gas = gas;
182
+ }
183
+ for (const field of VIEM_QUANTITY_FIELDS) {
184
+ const value = toViemQuantity(input[field]);
185
+ if (typeof value !== "undefined") {
186
+ prepared[field] = value;
187
+ }
188
+ }
189
+ if (typeof input.to === "string") {
190
+ prepared.to = input.to;
191
+ }
192
+ if (typeof input.data === "string") {
193
+ prepared.data = input.data;
194
+ }
195
+ const accessList = toViemAccessList(input.accessList);
196
+ if (accessList) {
197
+ prepared.accessList = accessList;
198
+ }
199
+ const authorizationList = toViemAuthorizationList(input.authorizationList);
200
+ if (authorizationList) {
201
+ prepared.authorizationList = authorizationList;
202
+ }
203
+ const blobVersionedHashes = toViemHexArray(input.blobVersionedHashes);
204
+ if (blobVersionedHashes) {
205
+ prepared.blobVersionedHashes = blobVersionedHashes;
206
+ }
207
+ const blobs = toViemBlobs(input.blobs);
208
+ if (blobs) {
209
+ prepared.blobs = blobs;
210
+ }
211
+ return prepared;
212
+ }
213
+
214
+ exports.prepareViemTx = prepareViemTx;
@@ -2,8 +2,8 @@ import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
2
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
3
  import { BaseController } from '@toruslabs/base-controllers';
4
4
  import { Mutex } from 'async-mutex';
5
- import { BrowserProvider, toQuantity, Contract } from 'ethers';
6
5
  import log from 'loglevel';
6
+ import { createPublicClient, custom, toHex } from 'viem';
7
7
  import { singleBalanceCheckerAbi } from '../utils/abis.js';
8
8
  import { SINGLE_CALL_BALANCES_ADDRESSES } from '../utils/contractAddresses.js';
9
9
 
@@ -32,7 +32,7 @@ class AccountTrackerController extends BaseController {
32
32
  _defineProperty(this, "provider", void 0);
33
33
  _defineProperty(this, "blockTracker", void 0);
34
34
  _defineProperty(this, "mutex", new Mutex());
35
- _defineProperty(this, "ethersProvider", void 0);
35
+ _defineProperty(this, "publicClient", void 0);
36
36
  _defineProperty(this, "getIdentities", void 0);
37
37
  _defineProperty(this, "getCurrentChainId", void 0);
38
38
  this.defaultState = {
@@ -41,7 +41,9 @@ class AccountTrackerController extends BaseController {
41
41
  this.initialize();
42
42
  this.provider = provider;
43
43
  this.blockTracker = blockTracker;
44
- this.ethersProvider = new BrowserProvider(this.provider, "any");
44
+ this.publicClient = createPublicClient({
45
+ transport: custom(this.provider)
46
+ });
45
47
  this.getIdentities = getIdentities;
46
48
  this.getCurrentChainId = getCurrentChainId;
47
49
  onPreferencesStateChange(() => {
@@ -127,21 +129,27 @@ class AccountTrackerController extends BaseController {
127
129
  } = this.state;
128
130
  if (!accounts[address]) return;
129
131
  accounts[address] = {
130
- balance: toQuantity(balance)
132
+ balance: toHex(BigInt(balance))
131
133
  };
132
134
  this.update({
133
135
  accounts
134
136
  });
135
137
  }
136
138
  async _updateAccountsViaBalanceChecker(addresses, deployedContractAddress) {
137
- const ethContract = new Contract(deployedContractAddress, singleBalanceCheckerAbi, this.ethersProvider);
138
139
  try {
139
- const result = await ethContract.balances(addresses, [ZERO_ADDRESS]);
140
+ const result = await this.publicClient.readContract({
141
+ address: deployedContractAddress,
142
+ abi: singleBalanceCheckerAbi,
143
+ functionName: "balances",
144
+ args: [addresses, [ZERO_ADDRESS]],
145
+ authorizationList: undefined // required when public client has no chain specified
146
+ });
140
147
  const {
141
148
  accounts
142
149
  } = this.state;
143
150
  addresses.forEach((address, index) => {
144
- const balance = toQuantity(result[index]);
151
+ var _result$index;
152
+ const balance = toHex((_result$index = result[index]) !== null && _result$index !== void 0 ? _result$index : 0n);
145
153
  if (!accounts[address]) return;
146
154
  accounts[address] = {
147
155
  balance
@@ -1,11 +1,9 @@
1
1
  import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
2
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
- import { addHexPrefix } from '@ethereumjs/util';
4
3
  import { BaseController, TransactionStatus } from '@toruslabs/base-controllers';
5
4
  import { JRPCEngine, providerFromEngine } from '@web3auth/auth';
6
- import { isHexString } from 'ethers';
7
5
  import log from 'loglevel';
8
- import { defineChain, createPublicClient, http, createWalletClient, custom, parseEther, toHex } from 'viem';
6
+ import { defineChain, createPublicClient, http, createWalletClient, custom, toHex, parseEther, isHex } from 'viem';
9
7
  import { createPaymasterClient, createBundlerClient } from 'viem/account-abstraction';
10
8
 
11
9
  const eoaInterceptorMiddleware = eoaAddress => (req, res, next, end) => {
@@ -124,7 +122,7 @@ class AccountAbstractionController extends BaseController {
124
122
  });
125
123
  }
126
124
  async sendTransaction(id, tx, address) {
127
- var _txParams$chainId, _txReceipt$receipt, _txReceipt$nonce, _txReceipt$receipt2, _txReceipt$receipt3, _txReceipt$receipt4;
125
+ var _txParams$chainId, _txReceipt$receipt, _txReceipt$nonce, _txReceipt$receipt$ga, _txReceipt$receipt2, _txReceipt$receipt$ef, _txReceipt$receipt3, _txReceipt$receipt4;
128
126
  if (address.toLowerCase() !== this.smartAccount.address.toLowerCase()) {
129
127
  throw new Error("Invalid address");
130
128
  }
@@ -164,8 +162,8 @@ class AccountAbstractionController extends BaseController {
164
162
  receipt: {
165
163
  transactionHash: (_txReceipt$receipt = txReceipt.receipt) === null || _txReceipt$receipt === void 0 ? void 0 : _txReceipt$receipt.transactionHash,
166
164
  nonce: (_txReceipt$nonce = txReceipt.nonce) === null || _txReceipt$nonce === void 0 ? void 0 : _txReceipt$nonce.toString(),
167
- gasUsed: addHexPrefix((_txReceipt$receipt2 = txReceipt.receipt) === null || _txReceipt$receipt2 === void 0 || (_txReceipt$receipt2 = _txReceipt$receipt2.gasUsed) === null || _txReceipt$receipt2 === void 0 ? void 0 : _txReceipt$receipt2.toString(16)),
168
- effectiveGasPrice: addHexPrefix((_txReceipt$receipt3 = txReceipt.receipt) === null || _txReceipt$receipt3 === void 0 || (_txReceipt$receipt3 = _txReceipt$receipt3.effectiveGasPrice) === null || _txReceipt$receipt3 === void 0 ? void 0 : _txReceipt$receipt3.toString(16)),
165
+ gasUsed: toHex((_txReceipt$receipt$ga = (_txReceipt$receipt2 = txReceipt.receipt) === null || _txReceipt$receipt2 === void 0 ? void 0 : _txReceipt$receipt2.gasUsed) !== null && _txReceipt$receipt$ga !== void 0 ? _txReceipt$receipt$ga : 0n),
166
+ effectiveGasPrice: toHex((_txReceipt$receipt$ef = (_txReceipt$receipt3 = txReceipt.receipt) === null || _txReceipt$receipt3 === void 0 ? void 0 : _txReceipt$receipt3.effectiveGasPrice) !== null && _txReceipt$receipt$ef !== void 0 ? _txReceipt$receipt$ef : 0n),
169
167
  type: (_txReceipt$receipt4 = txReceipt.receipt) === null || _txReceipt$receipt4 === void 0 ? void 0 : _txReceipt$receipt4.type,
170
168
  reason: txReceipt.reason
171
169
  },
@@ -278,7 +276,7 @@ class AccountAbstractionController extends BaseController {
278
276
  throw new Error("Invalid address");
279
277
  }
280
278
  return (_this$smartAccount = this.smartAccount) === null || _this$smartAccount === void 0 ? void 0 : _this$smartAccount.signMessage({
281
- message: isHexString(message) ? {
279
+ message: isHex(message) ? {
282
280
  raw: message
283
281
  } : message
284
282
  });
@@ -1,7 +1,7 @@
1
- import { addHexPrefix } from '@ethereumjs/util';
2
1
  import { TransactionStatus } from '@toruslabs/base-controllers';
3
2
  import { rpcErrors, JsonRpcError } from '@web3auth/auth';
4
3
  import { GetCallsStatusCode, EIP_5792_METHODS, EIP5792ErrorCode } from '../utils/eip5792Types.js';
4
+ import { addHexPrefix } from '../utils/hex.js';
5
5
 
6
6
  /**
7
7
  * Maps a TransactionStatus to an EIP-5792 GetCallsStatusCode.
@@ -1,9 +1,8 @@
1
- import { isValidAddress } from '@ethereumjs/util';
2
1
  import { rpcErrors } from '@web3auth/auth';
3
- import { isHexString } from 'ethers';
4
2
  import { v4, parse } from 'uuid';
3
+ import { isHex, isAddress } from 'viem';
5
4
  import { getIsEip7702UpgradeSupported } from '../Eip7702/eip7702Utils.js';
6
- import { SUPPORTED_EIP_5792_VERSIONS, EIP_5792_METHODS } from '../utils/eip5792Types.js';
5
+ import { EIP_5792_METHODS } from '../utils/eip5792Types.js';
7
6
 
8
7
  /**
9
8
  * Generates a unique batch ID for EIP-5792 calls.
@@ -23,20 +22,20 @@ function generateBatchId() {
23
22
  */
24
23
  function validateCall(call, index) {
25
24
  // Validate 'to' address
26
- if (!call.to || !isHexString(call.to) || !isValidAddress(call.to)) {
25
+ if (!call.to || !isHex(call.to) || !isAddress(call.to)) {
27
26
  throw rpcErrors.invalidParams(`Invalid 'to' address in call at index ${index}`);
28
27
  }
29
28
 
30
29
  // Validate 'value' if present
31
30
  if (call.value !== undefined) {
32
- if (!isHexString(call.value)) {
31
+ if (!isHex(call.value)) {
33
32
  throw rpcErrors.invalidParams(`Invalid 'value' in call at index ${index}: must be a valid non-negative hex string`);
34
33
  }
35
34
  }
36
35
 
37
36
  // Validate 'data' if present
38
37
  if (call.data !== undefined) {
39
- if (!isHexString(call.data)) {
38
+ if (!isHex(call.data)) {
40
39
  throw rpcErrors.invalidParams(`Invalid 'data' in call at index ${index}: must be a valid hex string`);
41
40
  }
42
41
  }
@@ -53,12 +52,12 @@ function validateSendCallsParams(sendCallsParams) {
53
52
  }
54
53
 
55
54
  // Validate version format
56
- if (!sendCallsParams.version || !SUPPORTED_EIP_5792_VERSIONS.includes(sendCallsParams.version)) {
57
- throw rpcErrors.invalidParams(`Invalid version: expected one of ${SUPPORTED_EIP_5792_VERSIONS.join(", ")}, got "${sendCallsParams.version || "undefined"}"`);
55
+ if (!sendCallsParams.version || typeof sendCallsParams.version !== "string") {
56
+ throw rpcErrors.invalidParams(`Invalid version: expected a string, got "${sendCallsParams.version || "undefined"}"`);
58
57
  }
59
58
 
60
59
  // Validate chainId format
61
- if (!sendCallsParams.chainId || !isHexString(sendCallsParams.chainId)) {
60
+ if (!sendCallsParams.chainId || !isHex(sendCallsParams.chainId)) {
62
61
  throw rpcErrors.invalidParams("Invalid chainId: must be a valid hex string");
63
62
  }
64
63
 
@@ -66,7 +65,7 @@ function validateSendCallsParams(sendCallsParams) {
66
65
  if (!sendCallsParams.from) {
67
66
  throw rpcErrors.invalidParams("Missing 'from' address");
68
67
  }
69
- if (!isHexString(sendCallsParams.from) || !isValidAddress(sendCallsParams.from)) {
68
+ if (!isHex(sendCallsParams.from) || !isAddress(sendCallsParams.from)) {
70
69
  throw rpcErrors.invalidParams("Invalid 'from' address: must be a valid hex address");
71
70
  }
72
71
 
@@ -1,8 +1,8 @@
1
- import { addHexPrefix } from '@ethereumjs/util';
2
1
  import { zeroAddress, encodeAbiParameters, parseAbiParameters, encodeFunctionData } from 'viem';
3
2
  import { erc7821Abi } from '../utils/abis.js';
4
3
  import { SUPPORTED_NETWORKS } from '../utils/constants.js';
5
4
  import { EIP_7702_PREFIX } from '../utils/eip7702Types.js';
5
+ import { addHexPrefix } from '../utils/hex.js';
6
6
 
7
7
  /**
8
8
  * The MetaMask EIP-7702 Stateless Delegator contract address.
@@ -1,8 +1,9 @@
1
1
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
- import { isHexString, addHexPrefix } from '@ethereumjs/util';
3
2
  import { BaseController, PollingManager, cloneDeep } from '@toruslabs/base-controllers';
4
3
  import log from 'loglevel';
4
+ import { isHex } from 'viem';
5
5
  import { GAS_ESTIMATE_TYPES } from '../utils/constants.js';
6
+ import { addHexPrefix } from '../utils/hex.js';
6
7
  import { fetchGasEstimates, fetchEthGasPriceEstimate, fetchLegacyGasPriceEstimates, fetchGasEstimatesViaEthFeeHistory, calculateTimeEstimate } from './gasUtil.js';
7
8
 
8
9
  const GAS_FEE_API = "https://mock-gas-server.herokuapp.com/";
@@ -119,7 +120,7 @@ class GasFeeController extends BaseController {
119
120
  const chainId = this.getNetworkIdentifier();
120
121
  if (chainId === "loading") return;
121
122
  let chainIdInt;
122
- if (typeof chainId === "string" && isHexString(addHexPrefix(chainId))) {
123
+ if (typeof chainId === "string" && isHex(addHexPrefix(chainId))) {
123
124
  chainIdInt = Number.parseInt(chainId, 16);
124
125
  }
125
126
  try {
@@ -1,8 +1,10 @@
1
- import { encode } from '@ethereumjs/rlp';
2
- import { addHexPrefix, bytesToHex, privateToPublic, toChecksumAddress, privateToAddress, stripHexPrefix, bigIntToBytes, isHexString } from '@ethereumjs/util';
1
+ import _objectSpread from '@babel/runtime/helpers/objectSpread2';
3
2
  import { BaseKeyringController, ecsignature, concatSig } from '@toruslabs/base-controllers';
4
- import { SigningKey, concat, keccak256, hashMessage, TypedDataEncoder } from 'ethers';
5
- import { toHex } from 'viem';
3
+ import { hexToBytes } from '@toruslabs/metadata-helpers';
4
+ import { serializeTransaction, keccak256, parseSignature, toHex, isHex } from 'viem';
5
+ import { privateKeyToAccount } from 'viem/accounts';
6
+ import { addHexPrefix, stripHexPrefix } from '../utils/hex.js';
7
+ import { prepareViemTx } from '../utils/viem.js';
6
8
 
7
9
  class KeyringController extends BaseKeyringController {
8
10
  constructor({
@@ -20,49 +22,55 @@ class KeyringController extends BaseKeyringController {
20
22
  }
21
23
  async signTransaction(tx, address) {
22
24
  const wallet = this._getWalletForAccount(address);
23
- const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
25
+ const account = privateKeyToAccount(addHexPrefix(wallet.privateKey));
24
26
  const localTx = tx;
25
- localTx.signature = privKey.sign(localTx.unsignedHash);
26
- return localTx;
27
+ const txToSign = prepareViemTx(localTx);
28
+ // NOTE: don't use account.signTransaction directly because it only return signed serialized transaction
29
+ // we don't want to compute unsigned hash and signature again
30
+ const serializedUnsigned = serializeTransaction(txToSign);
31
+ const unsignedHash = keccak256(serializedUnsigned);
32
+ const rawSig = await account.sign({
33
+ hash: unsignedHash
34
+ });
35
+ const signature = parseSignature(rawSig);
36
+ const serialized = serializeTransaction(txToSign, signature);
37
+ return _objectSpread(_objectSpread({}, txToSign), {}, {
38
+ unsignedHash,
39
+ serialized,
40
+ signature
41
+ });
27
42
  }
28
43
  async signEip7702Authorization(authorization, address) {
29
44
  const wallet = this._getWalletForAccount(address);
30
- const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
45
+ const account = privateKeyToAccount(addHexPrefix(wallet.privateKey));
31
46
 
32
47
  // Convert hex strings to proper types for RLP encoding
33
48
  // EIP-7702 authorization tuple: [chain_id_decimal, address, nonce_decimal]
34
49
  const chainIdDecimal = parseInt(authorization.chainId, 16);
35
50
  const nonceDecimal = parseInt(authorization.nonce, 16);
36
-
37
- // RLP encode the eip7702 authorization
38
- const encodedAuthorization = encode([chainIdDecimal, authorization.address, nonceDecimal]);
39
- // Prefixed with EIP7702 Domain Separator (0x05)
40
- const prefixedAuthorization = concat(["0x05", encodedAuthorization]);
41
- const authorizationHash = keccak256(prefixedAuthorization);
42
- const {
43
- r,
44
- s,
45
- v
46
- } = privKey.sign(authorizationHash);
47
- const signedAuthorization = {
51
+ const signedAuthorization = await account.signAuthorization({
52
+ contractAddress: authorization.address,
53
+ chainId: chainIdDecimal,
54
+ nonce: nonceDecimal
55
+ });
56
+ return {
48
57
  address: authorization.address,
49
58
  chainId: authorization.chainId,
50
59
  nonce: authorization.nonce,
51
- r: addHexPrefix(r),
52
- s: addHexPrefix(s),
53
- yParity: toHex(v - 27 === 0 ? 0 : 1)
60
+ r: signedAuthorization.r,
61
+ s: signedAuthorization.s,
62
+ yParity: toHex(signedAuthorization.yParity)
54
63
  };
55
- return signedAuthorization;
56
64
  }
57
65
  getAccounts() {
58
66
  return this.state.wallets.map(w => w.publicKey);
59
67
  }
60
- importAccount(accountPrivateKey) {
68
+ async importAccount(accountPrivateKey) {
61
69
  try {
62
70
  const hexPrivateKey = accountPrivateKey.padStart(64, "0");
63
- const bufferPrivKey = Buffer.from(hexPrivateKey, "hex");
64
- const publicKey = bytesToHex(privateToPublic(bufferPrivKey));
65
- const address = toChecksumAddress(bytesToHex(privateToAddress(bufferPrivKey)));
71
+ const account = privateKeyToAccount(addHexPrefix(hexPrivateKey));
72
+ const publicKey = account.publicKey;
73
+ const address = account.address;
66
74
  const existingWallet = this.state.wallets.find(w => w.address === address);
67
75
  if (existingWallet) return existingWallet.address;
68
76
  this.update({
@@ -90,37 +98,57 @@ class KeyringController extends BaseKeyringController {
90
98
  });
91
99
  }
92
100
  }
93
- getBufferPrivateKey(privateKey) {
101
+ getPrivateKeyBytes(privateKey) {
94
102
  const stripped = stripHexPrefix(privateKey);
95
- return Buffer.from(stripped, "hex");
103
+ return hexToBytes(stripped);
96
104
  }
97
105
 
98
106
  // For eth_sign, we need to sign arbitrary data:
99
107
  async signMessage(data, address) {
108
+ if (typeof data !== "string") {
109
+ throw new Error("Torus Keyring - signMessage data must be type 'string'");
110
+ }
100
111
  const wallet = this._getWalletForAccount(address);
101
- const privKey = this.getBufferPrivateKey(wallet.privateKey);
102
- const messageSig = ecsignature(Buffer.from(stripHexPrefix(data), "hex"), privKey);
103
- const sig = concatSig(Buffer.from(bigIntToBytes(messageSig.v)), Buffer.from(messageSig.r), Buffer.from(messageSig.s));
112
+ const privKey = this.getPrivateKeyBytes(wallet.privateKey);
113
+ const payload = hexToBytes(stripHexPrefix(data));
114
+ const messageSig = ecsignature(payload, privKey);
115
+ const sig = concatSig(messageSig.v, messageSig.r, messageSig.s);
104
116
  return sig;
105
117
  }
106
118
  async signPersonalMessage(data, address) {
107
119
  const wallet = this._getWalletForAccount(address);
108
- const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
120
+ const account = privateKeyToAccount(addHexPrefix(wallet.privateKey));
109
121
  // we need to check if the data is hex or not
110
122
  // For historical reasons, you must submit the message to sign in hex-encoded UTF-8.
111
123
  // https://docs.metamask.io/wallet/how-to/sign-data/#use-personal_sign
112
- const message = isHexString(data) ? Buffer.from(stripHexPrefix(data), "hex") : Buffer.from(data);
113
- const signature = privKey.sign(hashMessage(message)).serialized;
114
- return signature;
124
+ const message = isHex(data) ? {
125
+ raw: data
126
+ } : data;
127
+ return account.signMessage({
128
+ message
129
+ });
115
130
  }
116
131
 
117
132
  // personal_signTypedData, signs data along with the schema
118
133
  async signTypedData(typedData, address) {
119
134
  const wallet = this._getWalletForAccount(address);
120
- const privKey = new SigningKey(addHexPrefix(wallet.privateKey));
135
+ const account = privateKeyToAccount(addHexPrefix(wallet.privateKey));
121
136
  delete typedData.types.EIP712Domain;
122
- const signature = privKey.sign(TypedDataEncoder.hash(typedData.domain, typedData.types, typedData.message)).serialized;
123
- return signature;
137
+ const primaryType = typedData.primaryType;
138
+ if (!primaryType) {
139
+ throw new Error("Torus Keyring - primaryType is required");
140
+ }
141
+ const rawSig = await account.signTypedData({
142
+ domain: _objectSpread(_objectSpread({}, typedData.domain), {}, {
143
+ chainId: typeof typedData.domain.chainId === "string" ? parseInt(typedData.domain.chainId, 16) : typedData.domain.chainId,
144
+ salt: typedData.domain.salt,
145
+ verifyingContract: typedData.domain.verifyingContract
146
+ }),
147
+ types: typedData.types,
148
+ primaryType,
149
+ message: typedData.message
150
+ });
151
+ return rawSig;
124
152
  }
125
153
  _getWalletForAccount(account) {
126
154
  const address = account.toLowerCase();
@@ -1,10 +1,11 @@
1
- import { isValidAddress, stripHexPrefix, addHexPrefix, bytesToHex } from '@ethereumjs/util';
2
1
  import { CHAIN_NAMESPACES } from '@toruslabs/base-controllers';
3
- import { isHexString, JsonRpcProvider, toQuantity } from 'ethers';
2
+ import { bytesToHex, utf8ToBytes } from '@toruslabs/metadata-helpers';
3
+ import { isHex, createPublicClient, http, toHex, isAddress } from 'viem';
4
+ import { stripHexPrefix, addHexPrefix } from '../utils/hex.js';
4
5
 
5
6
  const hexRe = /^[0-9A-Fa-f]+$/gu;
6
7
  function validateAddress(address, propertyName) {
7
- if (!address || typeof address !== "string" || !isValidAddress(address)) {
8
+ if (!address || typeof address !== "string" || !isAddress(address)) {
8
9
  throw new Error(`Invalid "${propertyName}" address: ${address} must be a valid string.`);
9
10
  }
10
11
  }
@@ -27,7 +28,7 @@ function normalizeMessageData(data) {
27
28
  } catch {
28
29
  // do nothing
29
30
  }
30
- return bytesToHex(Buffer.from(data, "utf8"));
31
+ return addHexPrefix(bytesToHex(utf8ToBytes(data)));
31
32
  }
32
33
  async function validateTypedSignMessageDataV4(messageData, currentChainId) {
33
34
  validateAddress(messageData.from, "from");
@@ -72,7 +73,7 @@ async function validateAddChainData(data) {
72
73
  if (!chainId) {
73
74
  throw new Error("Invalid add chain params: please pass chainId in params");
74
75
  }
75
- if (!isHexString(chainId)) {
76
+ if (!isHex(chainId)) {
76
77
  throw new Error("Invalid add chain params: please pass a valid hex chainId in params, for: ex: 0x1");
77
78
  }
78
79
  if (!rpcUrls || rpcUrls.length === 0) throw new Error("params.rpcUrls not provided");
@@ -85,12 +86,12 @@ async function validateAddChainData(data) {
85
86
  if (!name) throw new Error("params.nativeCurrency.name not provided");
86
87
  if (!symbol) throw new Error("params.nativeCurrency.symbol not provided");
87
88
  if (decimals === undefined) throw new Error("params.nativeCurrency.decimals not provided");
88
- const _web3 = new JsonRpcProvider(rpcUrls[0], "any");
89
- const {
90
- chainId: networkChainID
91
- } = await _web3.getNetwork();
92
- if (Number.parseInt(networkChainID.toString()) !== Number.parseInt(chainId, 16)) {
93
- throw new Error(`Provided rpc url's chainId version is not matching with provided chainId, expected: ${toQuantity(networkChainID)}, received: ${chainId}`);
89
+ const client = createPublicClient({
90
+ transport: http(rpcUrls[0])
91
+ });
92
+ const networkChainID = await client.getChainId();
93
+ if (networkChainID !== Number.parseInt(chainId, 16)) {
94
+ throw new Error(`Provided rpc url's chainId version is not matching with provided chainId, expected: ${toHex(networkChainID)}, received: ${chainId}`);
94
95
  }
95
96
  }
96
97
  function validateSwitchChainData(data) {
@@ -100,7 +101,7 @@ function validateSwitchChainData(data) {
100
101
  if (!fullChainId) {
101
102
  throw new Error("Invalid switch chain params: please pass chainId in params");
102
103
  }
103
- if (!isHexString(fullChainId)) {
104
+ if (!isHex(fullChainId)) {
104
105
  const [namespace, chainId] = fullChainId.split(":");
105
106
  if (namespace !== CHAIN_NAMESPACES.SOLANA && namespace !== CHAIN_NAMESPACES.EIP155) {
106
107
  throw new Error("Invalid switch chain params: invalid namespace");
@@ -1,5 +1,5 @@
1
- import { PROVIDER_JRPC_METHODS, createFetchMiddleware, createGenericJRPCMiddleware } from '@toruslabs/base-controllers';
2
- import { createAsyncMiddleware, mergeMiddleware, createScaffoldMiddleware } from '@web3auth/auth';
1
+ import { createFetchMiddleware, PROVIDER_JRPC_METHODS, createGenericJRPCMiddleware } from '@toruslabs/base-controllers';
2
+ import { mergeMiddleware, createScaffoldMiddleware, createAsyncMiddleware } from '@web3auth/auth';
3
3
  import { walletGetUpgradeStatus } from '../Eip7702/walletGetUpgradeStatus.js';
4
4
  import { walletUpgradeAccount } from '../Eip7702/walletUpgradeAccount.js';
5
5
  import { METHOD_TYPES, TRANSACTION_ENVELOPE_TYPES, BUNDLER_METHOD_TYPES, PAYMASTER_METHOD_TYPES } from '../utils/constants.js';