viem 2.54.2 → 2.54.4

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 (76) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/_cjs/actions/index.js +5 -3
  3. package/_cjs/actions/index.js.map +1 -1
  4. package/_cjs/actions/public/getRawTransaction.js +14 -0
  5. package/_cjs/actions/public/getRawTransaction.js.map +1 -0
  6. package/_cjs/clients/decorators/public.js +2 -0
  7. package/_cjs/clients/decorators/public.js.map +1 -1
  8. package/_cjs/errors/version.js +1 -1
  9. package/_cjs/index.js.map +1 -1
  10. package/_cjs/tempo/Formatters.js +5 -1
  11. package/_cjs/tempo/Formatters.js.map +1 -1
  12. package/_cjs/tempo/Transaction.js.map +1 -1
  13. package/_cjs/tempo/chainConfig.js +11 -2
  14. package/_cjs/tempo/chainConfig.js.map +1 -1
  15. package/_cjs/utils/abi/decodeAbiParameters.js +11 -2
  16. package/_cjs/utils/abi/decodeAbiParameters.js.map +1 -1
  17. package/_cjs/utils/abi/encodeAbiParameters.js +26 -11
  18. package/_cjs/utils/abi/encodeAbiParameters.js.map +1 -1
  19. package/_esm/actions/index.js +1 -0
  20. package/_esm/actions/index.js.map +1 -1
  21. package/_esm/actions/public/getRawTransaction.js +34 -0
  22. package/_esm/actions/public/getRawTransaction.js.map +1 -0
  23. package/_esm/clients/decorators/public.js +2 -0
  24. package/_esm/clients/decorators/public.js.map +1 -1
  25. package/_esm/errors/version.js +1 -1
  26. package/_esm/index.js.map +1 -1
  27. package/_esm/tempo/Formatters.js +7 -1
  28. package/_esm/tempo/Formatters.js.map +1 -1
  29. package/_esm/tempo/Transaction.js.map +1 -1
  30. package/_esm/tempo/chainConfig.js +11 -2
  31. package/_esm/tempo/chainConfig.js.map +1 -1
  32. package/_esm/utils/abi/decodeAbiParameters.js +18 -2
  33. package/_esm/utils/abi/decodeAbiParameters.js.map +1 -1
  34. package/_esm/utils/abi/encodeAbiParameters.js +30 -12
  35. package/_esm/utils/abi/encodeAbiParameters.js.map +1 -1
  36. package/_types/actions/index.d.ts +1 -0
  37. package/_types/actions/index.d.ts.map +1 -1
  38. package/_types/actions/public/getRawTransaction.d.ts +38 -0
  39. package/_types/actions/public/getRawTransaction.d.ts.map +1 -0
  40. package/_types/chains/definitions/tempo.d.ts +42 -0
  41. package/_types/chains/definitions/tempo.d.ts.map +1 -1
  42. package/_types/chains/definitions/tempoDevnet.d.ts +42 -0
  43. package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
  44. package/_types/chains/definitions/tempoLocalnet.d.ts +42 -0
  45. package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
  46. package/_types/chains/definitions/tempoModerato.d.ts +42 -0
  47. package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
  48. package/_types/clients/decorators/public.d.ts +23 -0
  49. package/_types/clients/decorators/public.d.ts.map +1 -1
  50. package/_types/errors/version.d.ts +1 -1
  51. package/_types/index.d.ts +1 -0
  52. package/_types/index.d.ts.map +1 -1
  53. package/_types/tempo/Formatters.d.ts.map +1 -1
  54. package/_types/tempo/Transaction.d.ts +11 -0
  55. package/_types/tempo/Transaction.d.ts.map +1 -1
  56. package/_types/tempo/chainConfig.d.ts +22 -0
  57. package/_types/tempo/chainConfig.d.ts.map +1 -1
  58. package/_types/tempo/zones/zone.d.ts +126 -0
  59. package/_types/tempo/zones/zone.d.ts.map +1 -1
  60. package/_types/types/eip1193.d.ts +11 -0
  61. package/_types/types/eip1193.d.ts.map +1 -1
  62. package/_types/utils/abi/decodeAbiParameters.d.ts.map +1 -1
  63. package/_types/utils/abi/encodeAbiParameters.d.ts +5 -5
  64. package/_types/utils/abi/encodeAbiParameters.d.ts.map +1 -1
  65. package/actions/index.ts +6 -0
  66. package/actions/public/getRawTransaction.ts +60 -0
  67. package/clients/decorators/public.ts +30 -0
  68. package/errors/version.ts +1 -1
  69. package/index.ts +5 -0
  70. package/package.json +2 -2
  71. package/tempo/Formatters.ts +8 -0
  72. package/tempo/Transaction.ts +10 -0
  73. package/tempo/chainConfig.ts +11 -2
  74. package/types/eip1193.ts +11 -0
  75. package/utils/abi/decodeAbiParameters.ts +17 -2
  76. package/utils/abi/encodeAbiParameters.ts +32 -15
package/actions/index.ts CHANGED
@@ -200,6 +200,12 @@ export {
200
200
  type GetProofReturnType,
201
201
  getProof,
202
202
  } from './public/getProof.js'
203
+ export {
204
+ type GetRawTransactionErrorType,
205
+ type GetRawTransactionParameters,
206
+ type GetRawTransactionReturnType,
207
+ getRawTransaction,
208
+ } from './public/getRawTransaction.js'
203
209
  export {
204
210
  type GetStorageAtErrorType,
205
211
  type GetStorageAtParameters,
@@ -0,0 +1,60 @@
1
+ import type { Client } from '../../clients/createClient.js'
2
+ import type { Transport } from '../../clients/transports/createTransport.js'
3
+ import {
4
+ TransactionNotFoundError,
5
+ type TransactionNotFoundErrorType,
6
+ } from '../../errors/transaction.js'
7
+ import type { ErrorType } from '../../errors/utils.js'
8
+ import type { Chain } from '../../types/chain.js'
9
+ import type { Hash, Hex } from '../../types/misc.js'
10
+ import type { RequestErrorType } from '../../utils/buildRequest.js'
11
+
12
+ export type GetRawTransactionParameters = {
13
+ /** The hash of the transaction. */
14
+ hash: Hash
15
+ }
16
+
17
+ export type GetRawTransactionReturnType = Hex
18
+
19
+ export type GetRawTransactionErrorType =
20
+ | TransactionNotFoundErrorType
21
+ | RequestErrorType
22
+ | ErrorType
23
+
24
+ /**
25
+ * Returns the raw, serialized [Transaction](https://viem.sh/docs/glossary/terms#transaction) given a hash.
26
+ *
27
+ * - Docs: https://viem.sh/docs/actions/public/getRawTransaction
28
+ * - JSON-RPC Methods: `eth_getRawTransactionByHash`
29
+ *
30
+ * @param client - Client to use
31
+ * @param parameters - {@link GetRawTransactionParameters}
32
+ * @returns The raw, serialized transaction. {@link GetRawTransactionReturnType}
33
+ *
34
+ * @example
35
+ * import { createPublicClient, http } from 'viem'
36
+ * import { mainnet } from 'viem/chains'
37
+ * import { getRawTransaction } from 'viem/public'
38
+ *
39
+ * const client = createPublicClient({
40
+ * chain: mainnet,
41
+ * transport: http(),
42
+ * })
43
+ * const rawTransaction = await getRawTransaction(client, {
44
+ * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
45
+ * })
46
+ */
47
+ export async function getRawTransaction<chain extends Chain | undefined>(
48
+ client: Client<Transport, chain>,
49
+ { hash }: GetRawTransactionParameters,
50
+ ): Promise<GetRawTransactionReturnType> {
51
+ const rawTransaction = await client.request(
52
+ {
53
+ method: 'eth_getRawTransactionByHash',
54
+ params: [hash],
55
+ },
56
+ { dedupe: true },
57
+ )
58
+ if (!rawTransaction) throw new TransactionNotFoundError({ hash })
59
+ return rawTransaction
60
+ }
@@ -160,6 +160,11 @@ import {
160
160
  type GetProofReturnType,
161
161
  getProof,
162
162
  } from '../../actions/public/getProof.js'
163
+ import {
164
+ type GetRawTransactionParameters,
165
+ type GetRawTransactionReturnType,
166
+ getRawTransaction,
167
+ } from '../../actions/public/getRawTransaction.js'
163
168
  import {
164
169
  type GetStorageAtParameters,
165
170
  type GetStorageAtReturnType,
@@ -1352,6 +1357,30 @@ export type PublicActions<
1352
1357
  | EstimateMaxPriorityFeePerGasParameters<chain, chainOverride>
1353
1358
  | undefined,
1354
1359
  ) => Promise<EstimateMaxPriorityFeePerGasReturnType>
1360
+ /**
1361
+ * Returns the raw, serialized [Transaction](https://viem.sh/docs/glossary/terms#transaction) given a hash.
1362
+ *
1363
+ * - Docs: https://viem.sh/docs/actions/public/getRawTransaction
1364
+ * - JSON-RPC Methods: `eth_getRawTransactionByHash`
1365
+ *
1366
+ * @param args - {@link GetRawTransactionParameters}
1367
+ * @returns The raw, serialized transaction. {@link GetRawTransactionReturnType}
1368
+ *
1369
+ * @example
1370
+ * import { createPublicClient, http } from 'viem'
1371
+ * import { mainnet } from 'viem/chains'
1372
+ *
1373
+ * const client = createPublicClient({
1374
+ * chain: mainnet,
1375
+ * transport: http(),
1376
+ * })
1377
+ * const rawTransaction = await client.getRawTransaction({
1378
+ * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
1379
+ * })
1380
+ */
1381
+ getRawTransaction: (
1382
+ args: GetRawTransactionParameters,
1383
+ ) => Promise<GetRawTransactionReturnType>
1355
1384
  /**
1356
1385
  * Returns the value from a storage slot at a given address.
1357
1386
  *
@@ -2284,6 +2313,7 @@ export function publicActions<
2284
2313
  estimateMaxPriorityFeePerGas: (args) =>
2285
2314
  estimateMaxPriorityFeePerGas(client, args),
2286
2315
  fillTransaction: (args) => fillTransaction(client, args),
2316
+ getRawTransaction: (args) => getRawTransaction(client, args),
2287
2317
  getStorageAt: (args) => getStorageAt(client, args),
2288
2318
  getTransaction: (args) => getTransaction(client, args),
2289
2319
  getTransactionConfirmations: (args) =>
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '2.54.2'
1
+ export const version = '2.54.4'
package/index.ts CHANGED
@@ -237,6 +237,11 @@ export type {
237
237
  GetProofParameters,
238
238
  GetProofReturnType,
239
239
  } from './actions/public/getProof.js'
240
+ export type {
241
+ GetRawTransactionErrorType,
242
+ GetRawTransactionParameters,
243
+ GetRawTransactionReturnType,
244
+ } from './actions/public/getRawTransaction.js'
240
245
  export type {
241
246
  GetStorageAtErrorType,
242
247
  GetStorageAtParameters,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "viem",
3
3
  "description": "TypeScript Interface for Ethereum",
4
- "version": "2.54.2",
4
+ "version": "2.54.4",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -234,7 +234,7 @@
234
234
  "@scure/bip39": "1.6.0",
235
235
  "abitype": "1.2.3",
236
236
  "isows": "1.0.7",
237
- "ox": "0.14.29",
237
+ "ox": "0.14.30",
238
238
  "ws": "8.21.0"
239
239
  },
240
240
  "license": "MIT",
@@ -121,8 +121,12 @@ export function formatTransactionRequest(
121
121
  // `multisig` / `signatures` are client-side only (TIP-1061). They drive
122
122
  // sender derivation, owner signing, and final envelope assembly, but are
123
123
  // never sent as raw RPC fields — the wire payload is the serialized tx.
124
+ // `multisigInit` / `multisigSignatureCount` are wire fields: the node
125
+ // prices multisig gas from them during simulation.
124
126
  const {
125
127
  multisig: _multisig,
128
+ multisigInit,
129
+ multisigSignatureCount,
126
130
  signatures: _signatures,
127
131
  ...rpcRequest
128
132
  } = request
@@ -164,6 +168,10 @@ export function formatTransactionRequest(
164
168
 
165
169
  return {
166
170
  ...rpc,
171
+ ...(multisigInit ? { multisigInit } : {}),
172
+ ...(typeof multisigSignatureCount !== 'undefined'
173
+ ? { multisigSignatureCount }
174
+ : {}),
167
175
  ...(request.capabilities ? { capabilities: request.capabilities } : {}),
168
176
  ...(keyData ? { keyData } : {}),
169
177
  ...(keyId ? { keyId } : {}),
@@ -126,6 +126,16 @@ export type TransactionRequestTempo<
126
126
  feeToken?: TempoAddress.Address | bigint | undefined
127
127
  keyAuthorization?: KeyAuthorization.Signed<quantity, index> | undefined
128
128
  multisig?: MultisigConfig.Config<index> | undefined
129
+ /** Bootstrap multisig config hint for node-side gas modeling (TIP-1061). Attached automatically when `multisig` is present; the node ignores it for registered senders. */
130
+ multisigInit?:
131
+ | {
132
+ salt: Hex.Hex
133
+ threshold: number
134
+ owners: readonly { owner: Address; weight: number }[]
135
+ }
136
+ | undefined
137
+ /** Modeled owner approval count for node-side gas modeling (TIP-1061). */
138
+ multisigSignatureCount?: number | undefined
129
139
  nonceKey?: 'expiring' | quantity | undefined
130
140
  signatures?: readonly SignatureEnvelope.Serialized[] | undefined
131
141
  validBefore?: index | undefined
@@ -83,8 +83,17 @@ export const chainConfig = {
83
83
  ? (request.account as MultisigAccount).config
84
84
  : undefined)
85
85
  if (multisig) {
86
- request.multisig = multisig
87
- request.from = MultisigConfig.getAddress(multisig)
86
+ const config = MultisigConfig.from(multisig)
87
+ request.multisig = config
88
+ request.from = MultisigConfig.getAddress(config)
89
+ request.multisigInit = {
90
+ salt: config.salt ?? MultisigConfig.zeroSalt,
91
+ threshold: Number(config.threshold),
92
+ owners: config.owners.map((owner) => ({
93
+ owner: owner.owner,
94
+ weight: Number(owner.weight),
95
+ })),
96
+ }
88
97
  // A non-multisig `account` (e.g. the client's default) isn't the sender,
89
98
  // so drop it: core then fills nonce/gas/fees for the multisig sender via
90
99
  // `request.from`. A multisig account *is* the sender — keep it so the
package/types/eip1193.ts CHANGED
@@ -991,6 +991,17 @@ export type PublicRpcSchema = [
991
991
  ]
992
992
  ReturnType: Proof
993
993
  },
994
+ /**
995
+ * @description Returns the raw, serialized transaction specified by hash
996
+ * @example
997
+ * provider.request({ method: 'eth_getRawTransactionByHash', params: ['0x...'] })
998
+ * // => '0x...'
999
+ */
1000
+ {
1001
+ Method: 'eth_getRawTransactionByHash'
1002
+ Parameters: [hash: Hash]
1003
+ ReturnType: Hex | null
1004
+ },
994
1005
  /**
995
1006
  * @description Returns the value from a storage position at an address
996
1007
  * @link https://eips.ethereum.org/EIPS/eip-1474
@@ -75,7 +75,9 @@ export function decodeAbiParameters<
75
75
  const values = []
76
76
  for (let i = 0; i < params.length; ++i) {
77
77
  const param = params[i]
78
- cursor.setPosition(consumed)
78
+ // Zero-width types (e.g. `uint256[0]`, empty tuples) at the end of the
79
+ // data consume no bytes, so the cursor may already be exhausted.
80
+ if (consumed < bytes.length) cursor.setPosition(consumed)
79
81
  const [data, consumed_] = decodeParameter(cursor, param, {
80
82
  staticPosition: 0,
81
83
  })
@@ -146,7 +148,8 @@ function decodeArray(
146
148
  ) {
147
149
  // If the length of the array is not known in advance (dynamic array),
148
150
  // this means we will need to wonder off to the pointer and decode.
149
- if (!length) {
151
+ // Note: zero-length fixed arrays (`T[0]`) are not dynamic.
152
+ if (length === null) {
150
153
  // Dealing with a dynamic type, so get the offset of the array data.
151
154
  const offset = bytesToNumber(cursor.readBytes(sizeOfOffset))
152
155
 
@@ -172,6 +175,12 @@ function decodeArray(
172
175
  })
173
176
  consumed += consumed_
174
177
  value.push(data)
178
+ // Charge zero-width elements against the read limit to bound work
179
+ // on huge lengths of zero-width types (e.g. `uint256[0][]`).
180
+ if (consumed_ === 0) {
181
+ cursor.assertReadLimit()
182
+ cursor._touch()
183
+ }
175
184
  }
176
185
 
177
186
  // As we have gone wondering, restore to the original position + next slot.
@@ -214,6 +223,12 @@ function decodeArray(
214
223
  })
215
224
  consumed += consumed_
216
225
  value.push(data)
226
+ // Charge zero-width elements against the read limit to bound work
227
+ // on huge lengths of zero-width types (e.g. `uint256[0][4294967295]`).
228
+ if (consumed_ === 0) {
229
+ cursor.assertReadLimit()
230
+ cursor._touch()
231
+ }
217
232
  }
218
233
  return [value, consumed]
219
234
  }
@@ -26,7 +26,7 @@ import { IntegerOutOfRangeError } from '../../errors/encoding.js'
26
26
  import type { ErrorType } from '../../errors/utils.js'
27
27
  import type { Hex } from '../../types/misc.js'
28
28
  import { type IsAddressErrorType, isAddress } from '../address/isAddress.js'
29
- import { type ConcatErrorType, concat } from '../data/concat.js'
29
+ import { type ConcatHexErrorType, concatHex } from '../data/concat.js'
30
30
  import { type PadHexErrorType, padHex } from '../data/pad.js'
31
31
  import { type SizeErrorType, size } from '../data/size.js'
32
32
  import { type SliceErrorType, slice } from '../data/slice.js'
@@ -101,9 +101,7 @@ export function encodeAbiParameters<
101
101
  params: params as readonly AbiParameter[],
102
102
  values: values as any,
103
103
  })
104
- const data = encodeParams(preparedParams)
105
- if (data.length === 0) return '0x'
106
- return data
104
+ return encodeParams(preparedParams)
107
105
  }
108
106
 
109
107
  /////////////////////////////////////////////////////////////////
@@ -212,7 +210,8 @@ function encodeParams(preparedParams: PreparedParam[]): Hex {
212
210
  }
213
211
 
214
212
  // 3. Concatenate static and dynamic parts.
215
- return concat([...staticParams, ...dynamicParams])
213
+ // `concatHex` returns `'0x'` for empty input (zero-width parameters).
214
+ return concatHex([...staticParams, ...dynamicParams])
216
215
  }
217
216
 
218
217
  /////////////////////////////////////////////////////////////////
@@ -229,7 +228,7 @@ function encodeAddress(value: Hex): PreparedParam {
229
228
 
230
229
  type EncodeArrayErrorType =
231
230
  | AbiEncodingArrayLengthMismatchErrorType
232
- | ConcatErrorType
231
+ | ConcatHexErrorType
233
232
  | EncodeParamsErrorType
234
233
  | InvalidArrayErrorType
235
234
  | NumberToHexErrorType
@@ -257,7 +256,9 @@ function encodeArray<const param extends AbiParameter>(
257
256
  type: `${param.type}[${length}]`,
258
257
  })
259
258
 
260
- let dynamicChild = false
259
+ // Zero-length fixed arrays of dynamic types (e.g. `string[0]`) are dynamic
260
+ // per the ABI spec, even though they have no elements to inspect.
261
+ let dynamicChild = value.length === 0 && isDynamicType(param)
261
262
  const preparedParams: PreparedParam[] = []
262
263
  for (let i = 0; i < value.length; i++) {
263
264
  const preparedParam = prepareParam({ param, value: value[i] })
@@ -271,20 +272,20 @@ function encodeArray<const param extends AbiParameter>(
271
272
  const length = numberToHex(preparedParams.length, { size: 32 })
272
273
  return {
273
274
  dynamic: true,
274
- encoded: preparedParams.length > 0 ? concat([length, data]) : length,
275
+ encoded: concatHex([length, data]),
275
276
  }
276
277
  }
277
278
  if (dynamicChild) return { dynamic: true, encoded: data }
278
279
  }
279
280
  return {
280
281
  dynamic: false,
281
- encoded: concat(preparedParams.map(({ encoded }) => encoded)),
282
+ encoded: concatHex(preparedParams.map(({ encoded }) => encoded)),
282
283
  }
283
284
  }
284
285
 
285
286
  type EncodeBytesErrorType =
286
287
  | AbiEncodingBytesSizeMismatchErrorType
287
- | ConcatErrorType
288
+ | ConcatHexErrorType
288
289
  | PadHexErrorType
289
290
  | NumberToHexErrorType
290
291
  | SizeErrorType
@@ -307,7 +308,10 @@ function encodeBytes<const param extends AbiParameter>(
307
308
  })
308
309
  return {
309
310
  dynamic: true,
310
- encoded: concat([padHex(numberToHex(bytesSize, { size: 32 })), value_]),
311
+ encoded: concatHex([
312
+ padHex(numberToHex(bytesSize, { size: 32 })),
313
+ value_,
314
+ ]),
311
315
  }
312
316
  }
313
317
  if (bytesSize !== Number.parseInt(paramSize, 10))
@@ -356,7 +360,7 @@ function encodeNumber(
356
360
  }
357
361
 
358
362
  type EncodeStringErrorType =
359
- | ConcatErrorType
363
+ | ConcatHexErrorType
360
364
  | NumberToHexErrorType
361
365
  | PadHexErrorType
362
366
  | SizeErrorType
@@ -377,7 +381,7 @@ function encodeString(value: string): PreparedParam {
377
381
  }
378
382
  return {
379
383
  dynamic: true,
380
- encoded: concat([
384
+ encoded: concatHex([
381
385
  padHex(numberToHex(size(hexValue), { size: 32 })),
382
386
  ...parts,
383
387
  ]),
@@ -385,7 +389,7 @@ function encodeString(value: string): PreparedParam {
385
389
  }
386
390
 
387
391
  type EncodeTupleErrorType =
388
- | ConcatErrorType
392
+ | ConcatHexErrorType
389
393
  | EncodeParamsErrorType
390
394
  // TODO: Add back once circular type reference is resolved
391
395
  // | PrepareParamErrorType
@@ -413,7 +417,7 @@ function encodeTuple<
413
417
  dynamic,
414
418
  encoded: dynamic
415
419
  ? encodeParams(preparedParams)
416
- : concat(preparedParams.map(({ encoded }) => encoded)),
420
+ : concatHex(preparedParams.map(({ encoded }) => encoded)),
417
421
  }
418
422
  }
419
423
 
@@ -428,3 +432,16 @@ export function getArrayComponents(
428
432
  [matches[2] ? Number(matches[2]) : null, matches[1]]
429
433
  : undefined
430
434
  }
435
+
436
+ function isDynamicType(param: AbiParameter): boolean {
437
+ const { type } = param
438
+ if (type === 'string') return true
439
+ if (type === 'bytes') return true
440
+ if (type.endsWith('[]')) return true
441
+ if (type === 'tuple')
442
+ return (param as TupleAbiParameter).components.some(isDynamicType)
443
+ const arrayComponents = getArrayComponents(type)
444
+ if (arrayComponents)
445
+ return isDynamicType({ ...param, type: arrayComponents[1] })
446
+ return false
447
+ }