viem 2.54.3 → 2.54.5

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 (53) hide show
  1. package/CHANGELOG.md +14 -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/actions/wallet/prepareTransactionRequest.js +8 -6
  7. package/_cjs/actions/wallet/prepareTransactionRequest.js.map +1 -1
  8. package/_cjs/clients/decorators/public.js +2 -0
  9. package/_cjs/clients/decorators/public.js.map +1 -1
  10. package/_cjs/errors/version.js +1 -1
  11. package/_cjs/index.js.map +1 -1
  12. package/_cjs/tempo/Transaction.js +24 -30
  13. package/_cjs/tempo/Transaction.js.map +1 -1
  14. package/_cjs/tempo/chainConfig.js +16 -0
  15. package/_cjs/tempo/chainConfig.js.map +1 -1
  16. package/_esm/actions/index.js +1 -0
  17. package/_esm/actions/index.js.map +1 -1
  18. package/_esm/actions/public/getRawTransaction.js +34 -0
  19. package/_esm/actions/public/getRawTransaction.js.map +1 -0
  20. package/_esm/actions/wallet/prepareTransactionRequest.js +8 -6
  21. package/_esm/actions/wallet/prepareTransactionRequest.js.map +1 -1
  22. package/_esm/clients/decorators/public.js +2 -0
  23. package/_esm/clients/decorators/public.js.map +1 -1
  24. package/_esm/errors/version.js +1 -1
  25. package/_esm/index.js.map +1 -1
  26. package/_esm/tempo/Transaction.js +31 -42
  27. package/_esm/tempo/Transaction.js.map +1 -1
  28. package/_esm/tempo/chainConfig.js +16 -0
  29. package/_esm/tempo/chainConfig.js.map +1 -1
  30. package/_types/actions/index.d.ts +1 -0
  31. package/_types/actions/index.d.ts.map +1 -1
  32. package/_types/actions/public/getRawTransaction.d.ts +38 -0
  33. package/_types/actions/public/getRawTransaction.d.ts.map +1 -0
  34. package/_types/actions/wallet/prepareTransactionRequest.d.ts.map +1 -1
  35. package/_types/clients/decorators/public.d.ts +23 -0
  36. package/_types/clients/decorators/public.d.ts.map +1 -1
  37. package/_types/errors/version.d.ts +1 -1
  38. package/_types/index.d.ts +1 -0
  39. package/_types/index.d.ts.map +1 -1
  40. package/_types/tempo/Transaction.d.ts.map +1 -1
  41. package/_types/tempo/chainConfig.d.ts.map +1 -1
  42. package/_types/types/eip1193.d.ts +11 -0
  43. package/_types/types/eip1193.d.ts.map +1 -1
  44. package/actions/index.ts +6 -0
  45. package/actions/public/getRawTransaction.ts +60 -0
  46. package/actions/wallet/prepareTransactionRequest.ts +10 -6
  47. package/clients/decorators/public.ts +30 -0
  48. package/errors/version.ts +1 -1
  49. package/index.ts +5 -0
  50. package/package.json +1 -1
  51. package/tempo/Transaction.ts +31 -42
  52. package/tempo/chainConfig.ts +15 -0
  53. package/types/eip1193.ts +11 -0
@@ -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.3'
1
+ export const version = '2.54.5'
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.3",
4
+ "version": "2.54.5",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -2,7 +2,6 @@
2
2
 
3
3
  import type { Address } from 'abitype'
4
4
  import * as Hex from 'ox/Hex'
5
- import * as Secp256k1 from 'ox/Secp256k1'
6
5
  import * as Signature from 'ox/Signature'
7
6
  import {
8
7
  type AuthorizationTempo,
@@ -297,7 +296,8 @@ async function serializeTempo(
297
296
  },
298
297
  sig?: OneOf<SignatureEnvelope.SignatureEnvelope | viem_Signature> | undefined,
299
298
  ) {
300
- const signature = (() => {
299
+ // Track caller signatures separately from synthesized multisig approvals.
300
+ const signature_provided = (() => {
301
301
  if (transaction.signature) return transaction.signature
302
302
  if (sig && 'type' in sig) return sig as SignatureEnvelope.SignatureEnvelope
303
303
  if (sig)
@@ -325,9 +325,14 @@ async function serializeTempo(
325
325
  const hasPrefilledFeePayerSignature =
326
326
  typeof transaction.feePayerSignature !== 'undefined' &&
327
327
  transaction.feePayerSignature !== null
328
+ // Sponsorship sender signatures omit `feeToken`.
328
329
  const shouldStripFeeTokenForSponsorship =
329
- (feePayer === true && (!signature || !feePayerSignature)) ||
330
- (!signature && hasPrefilledFeePayerSignature)
330
+ // Relay fills a partial sender envelope first.
331
+ (feePayer === true && (!signature_provided || !feePayerSignature)) ||
332
+ // Local fee-payer accounts sign after sender serialization.
333
+ (typeof feePayer === 'object' && !signature_provided) ||
334
+ // Filled transactions can already include fee-payer approval.
335
+ (!signature_provided && hasPrefilledFeePayerSignature)
331
336
 
332
337
  const transaction_ox = {
333
338
  ...rest,
@@ -354,22 +359,15 @@ async function serializeTempo(
354
359
  // for the sender sign payload and the partial sponsorship handoff envelope.
355
360
  // Keep it only on the final broadcast envelope so the chain can verify
356
361
  // the fee payer.
357
- if (shouldStripFeeTokenForSponsorship) delete transaction_ox.feeToken
358
-
359
- // Native multisig (TIP-1061): combine the collected owner approvals into the
360
- // multisig signature envelope and serialize the broadcast transaction. The
361
- // approvals are recovered against the multisig owner digest and ordered into
362
- // the strictly-ascending owner address order the node requires.
363
- //
364
- // Bootstrap (`init`) is auto-detected from the nonce: the protocol requires
365
- // (and consumes) nonce `0` for the first transaction from a derived account,
366
- // so `nonce == 0` uniquely identifies a bootstrap. This matches the serialized
367
- // nonce above (a falsy `nonce` serializes as `0`). The owner approval digest
368
- // doesn't commit to `init`, so attaching it here (rather than at owner-signing)
369
- // is safe.
370
- // NOTE: fee-payer + multisig is handled in a later phase.
371
- if (transaction.multisig && transaction.signatures && !feePayer) {
372
- const payload = TxTempo.getSignPayload(TxTempo.from(transaction_ox))
362
+ const transaction_sender_ox = { ...transaction_ox }
363
+ if (shouldStripFeeTokenForSponsorship) delete transaction_sender_ox.feeToken
364
+
365
+ // Combine owner approvals before fee-payer handling.
366
+ const signature = (() => {
367
+ if (signature_provided) return signature_provided
368
+ if (!transaction.multisig || !transaction.signatures) return undefined
369
+
370
+ const payload = TxTempo.getSignPayload(TxTempo.from(transaction_sender_ox))
373
371
  const signatures = transaction.signatures.map((approval) =>
374
372
  SignatureEnvelope.from(approval),
375
373
  )
@@ -378,31 +376,25 @@ async function serializeTempo(
378
376
  signatures,
379
377
  genesisConfig: transaction.multisig,
380
378
  })
381
- const signature = SignatureEnvelope.from({
379
+ return SignatureEnvelope.from({
382
380
  genesisConfig: transaction.multisig,
383
381
  signatures: sorted,
384
382
  ...(nonce ? {} : { init: true }),
385
383
  })
386
- return TxTempo.serialize(transaction_ox, {
387
- feePayerSignature: undefined,
388
- signature,
389
- })
390
- }
384
+ })()
391
385
 
392
386
  if (signature && typeof transaction.feePayer === 'object') {
393
387
  const tx = TxTempo.from(transaction_ox, {
394
388
  signature,
395
389
  })
396
390
 
397
- const sender = (() => {
398
- if (transaction.from) return transaction.from
399
- if (signature.type === 'secp256k1')
400
- return Secp256k1.recoverAddress({
401
- payload: TxTempo.getSignPayload(tx),
402
- signature: signature.signature,
403
- })
404
- throw new Error('Unable to extract sender from transaction or signature.')
405
- })()
391
+ const sender =
392
+ transaction.from ??
393
+ SignatureEnvelope.extractAddress({
394
+ payload: TxTempo.getSignPayload(tx),
395
+ root: true,
396
+ signature,
397
+ })
406
398
 
407
399
  const hash = TxTempo.getFeePayerSignPayload(tx, {
408
400
  sender,
@@ -421,16 +413,16 @@ async function serializeTempo(
421
413
  // Fee payer signature was prefilled during `eth_fillTransaction` -- emit
422
414
  // a full envelope with both signatures to skip `eth_signRawTransaction`.
423
415
  if (signature && feePayerSignature)
424
- return TxTempo.serialize(transaction_ox, {
416
+ return TxTempo.serialize(transaction_sender_ox, {
425
417
  signature,
426
418
  })
427
419
  if (signature)
428
- return TxTempo.serialize(transaction_ox, {
420
+ return TxTempo.serialize(transaction_sender_ox, {
429
421
  format: 'feePayer',
430
422
  sender: transaction.from,
431
423
  signature,
432
424
  })
433
- return TxTempo.serialize(transaction_ox, {
425
+ return TxTempo.serialize(transaction_sender_ox, {
434
426
  feePayerSignature: null,
435
427
  })
436
428
  }
@@ -439,10 +431,7 @@ async function serializeTempo(
439
431
  // If we have specified a fee payer, the user will not be signing over the fee token.
440
432
  // Defer the fee token signing to the fee payer. Once the fee payer has signed,
441
433
  // keep `feeToken` so the broadcast envelope carries the token the chain must charge.
442
- {
443
- ...transaction_ox,
444
- ...(feePayer && !feePayerSignature ? { feeToken: undefined } : {}),
445
- },
434
+ transaction_sender_ox,
446
435
  {
447
436
  feePayerSignature: undefined,
448
437
  signature,
@@ -94,6 +94,7 @@ export const chainConfig = {
94
94
  weight: Number(owner.weight),
95
95
  })),
96
96
  }
97
+ request.multisigSignatureCount ??= inferMultisigSignatureCount(config)
97
98
  // A non-multisig `account` (e.g. the client's default) isn't the sender,
98
99
  // so drop it: core then fills nonce/gas/fees for the multisig sender via
99
100
  // `request.from`. A multisig account *is* the sender — keep it so the
@@ -147,6 +148,7 @@ export const chainConfig = {
147
148
  // validBefore timestamp.
148
149
  const useExpiringNonce = await (async () => {
149
150
  if (request.nonceKey === 'expiring') return true
151
+ if (multisig) return false
150
152
  if (request.feePayer && typeof request.nonceKey === 'undefined')
151
153
  return true
152
154
  const address = request.account?.address
@@ -261,3 +263,16 @@ export const chainConfig = {
261
263
  } as const satisfies viem_ChainConfig & { blockTime: number }
262
264
 
263
265
  export type ChainConfig = typeof chainConfig
266
+
267
+ function inferMultisigSignatureCount(config: MultisigConfig.Config) {
268
+ const threshold = Number(config.threshold)
269
+ const weights = config.owners
270
+ .map((owner) => Number(owner.weight))
271
+ .sort((a, b) => b - a)
272
+ let total = 0
273
+ for (const [index, weight] of weights.entries()) {
274
+ total += weight
275
+ if (total >= threshold) return index + 1
276
+ }
277
+ return weights.length
278
+ }
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