ox 1.8.1 → 1.8.3

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 (134) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/core/Frame.d.ts +23 -20
  3. package/dist/core/Frame.d.ts.map +1 -1
  4. package/dist/core/Frame.js +28 -23
  5. package/dist/core/Frame.js.map +1 -1
  6. package/dist/core/FrameReceipt.d.ts +23 -14
  7. package/dist/core/FrameReceipt.d.ts.map +1 -1
  8. package/dist/core/FrameReceipt.js +15 -11
  9. package/dist/core/FrameReceipt.js.map +1 -1
  10. package/dist/core/FrameRequest.d.ts +50 -0
  11. package/dist/core/FrameRequest.d.ts.map +1 -0
  12. package/dist/core/FrameRequest.js +59 -0
  13. package/dist/core/FrameRequest.js.map +1 -0
  14. package/dist/core/FrameSignature.d.ts +17 -16
  15. package/dist/core/FrameSignature.d.ts.map +1 -1
  16. package/dist/core/FrameSignature.js +38 -21
  17. package/dist/core/FrameSignature.js.map +1 -1
  18. package/dist/core/Siwe.d.ts.map +1 -1
  19. package/dist/core/Siwe.js +3 -3
  20. package/dist/core/Siwe.js.map +1 -1
  21. package/dist/core/Transaction.d.ts +2 -2
  22. package/dist/core/Transaction.d.ts.map +1 -1
  23. package/dist/core/Transaction.js.map +1 -1
  24. package/dist/core/TransactionRequest.d.ts +5 -5
  25. package/dist/core/TransactionRequest.d.ts.map +1 -1
  26. package/dist/core/TransactionRequest.js +3 -3
  27. package/dist/core/TransactionRequest.js.map +1 -1
  28. package/dist/core/TxEnvelope.d.ts +3 -1
  29. package/dist/core/TxEnvelope.d.ts.map +1 -1
  30. package/dist/core/TxEnvelope.js +9 -1
  31. package/dist/core/TxEnvelope.js.map +1 -1
  32. package/dist/core/TxEnvelopeEip8141.d.ts +4 -4
  33. package/dist/core/TxEnvelopeEip8141.js +8 -8
  34. package/dist/core/TxEnvelopeEip8141.js.map +1 -1
  35. package/dist/core/internal/rpcSchemas/eth.d.ts +16 -4
  36. package/dist/core/internal/rpcSchemas/eth.d.ts.map +1 -1
  37. package/dist/index.d.ts +21 -5
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +21 -5
  40. package/dist/index.js.map +1 -1
  41. package/dist/zod/Block.d.ts +49 -37
  42. package/dist/zod/Block.d.ts.map +1 -1
  43. package/dist/zod/Frame.d.ts +14 -14
  44. package/dist/zod/Frame.js +5 -5
  45. package/dist/zod/Frame.js.map +1 -1
  46. package/dist/zod/FrameReceipt.d.ts +42 -2
  47. package/dist/zod/FrameReceipt.d.ts.map +1 -1
  48. package/dist/zod/FrameReceipt.js +11 -1
  49. package/dist/zod/FrameReceipt.js.map +1 -1
  50. package/dist/zod/FrameRequest.d.ts +40 -0
  51. package/dist/zod/FrameRequest.d.ts.map +1 -0
  52. package/dist/zod/FrameRequest.js +37 -0
  53. package/dist/zod/FrameRequest.js.map +1 -0
  54. package/dist/zod/FrameSignature.d.ts +21 -13
  55. package/dist/zod/FrameSignature.d.ts.map +1 -1
  56. package/dist/zod/FrameSignature.js +10 -7
  57. package/dist/zod/FrameSignature.js.map +1 -1
  58. package/dist/zod/RpcSchema.d.ts +447 -265
  59. package/dist/zod/RpcSchema.d.ts.map +1 -1
  60. package/dist/zod/Transaction.d.ts +98 -74
  61. package/dist/zod/Transaction.d.ts.map +1 -1
  62. package/dist/zod/Transaction.js +4 -4
  63. package/dist/zod/Transaction.js.map +1 -1
  64. package/dist/zod/TransactionEnvelope.d.ts +50 -34
  65. package/dist/zod/TransactionEnvelope.d.ts.map +1 -1
  66. package/dist/zod/TransactionReceipt.d.ts +42 -2
  67. package/dist/zod/TransactionReceipt.d.ts.map +1 -1
  68. package/dist/zod/TransactionRequest.d.ts +29 -21
  69. package/dist/zod/TransactionRequest.d.ts.map +1 -1
  70. package/dist/zod/TransactionRequest.js +3 -3
  71. package/dist/zod/TransactionRequest.js.map +1 -1
  72. package/dist/zod/TxEnvelopeEip8141.d.ts +37 -25
  73. package/dist/zod/TxEnvelopeEip8141.d.ts.map +1 -1
  74. package/dist/zod/internal/rpcSchemas/Eth.d.ts +449 -267
  75. package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
  76. package/dist/zod/internal/rpcSchemas/Eth.js +9 -0
  77. package/dist/zod/internal/rpcSchemas/Eth.js.map +1 -1
  78. package/dist/zod/internal/rpcSchemas/Wallet.d.ts +49 -21
  79. package/dist/zod/internal/rpcSchemas/Wallet.d.ts.map +1 -1
  80. package/dist/zod/tempo/RpcSchemaTempo.d.ts +64 -48
  81. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  82. package/dist/zod/tempo/Transaction.d.ts +49 -37
  83. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  84. package/dist/zod/z.d.ts +1 -0
  85. package/dist/zod/z.d.ts.map +1 -1
  86. package/dist/zod/z.js +1 -0
  87. package/dist/zod/z.js.map +1 -1
  88. package/package.json +11 -1
  89. package/src/core/Frame.ts +41 -33
  90. package/src/core/FrameReceipt.ts +30 -16
  91. package/src/core/FrameRequest.ts +78 -0
  92. package/src/core/FrameSignature.ts +64 -34
  93. package/src/core/Siwe.ts +21 -13
  94. package/src/core/Transaction.ts +35 -24
  95. package/src/core/TransactionRequest.ts +9 -7
  96. package/src/core/TxEnvelope.ts +9 -1
  97. package/src/core/TxEnvelopeEip8141.ts +8 -8
  98. package/src/core/_test/AbiConstructor.test.ts +2 -0
  99. package/src/core/_test/Frame.test-d.ts +16 -7
  100. package/src/core/_test/Frame.test.ts +52 -24
  101. package/src/core/_test/FrameReceipt.test.ts +15 -9
  102. package/src/core/_test/FrameRequest.test-d.ts +16 -0
  103. package/src/core/_test/FrameRequest.test.ts +41 -0
  104. package/src/core/_test/FrameRpc.test.ts +131 -0
  105. package/src/core/_test/FrameSignature.test-d.ts +20 -0
  106. package/src/core/_test/FrameSignature.test.ts +132 -11
  107. package/src/core/_test/RpcSchema.test-d.ts +45 -0
  108. package/src/core/_test/Siwe.test.ts +147 -0
  109. package/src/core/_test/TransactionEnvelope.test.ts +1 -1
  110. package/src/core/_test/TransactionReceipt.test.ts +32 -6
  111. package/src/core/_test/TransactionRequest.test-d.ts +10 -1
  112. package/src/core/_test/TransactionRequest.test.ts +3 -2
  113. package/src/core/_test/TxEnvelopeEip8141.test-d.ts +2 -2
  114. package/src/core/_test/TxEnvelopeEip8141.test.ts +92 -53
  115. package/src/core/_test/index.test.ts +1 -0
  116. package/src/core/internal/rpcSchemas/eth.ts +13 -4
  117. package/src/index.ts +22 -5
  118. package/src/version.ts +1 -1
  119. package/src/zod/Frame.ts +5 -5
  120. package/src/zod/FrameReceipt.ts +11 -1
  121. package/src/zod/FrameRequest.ts +46 -0
  122. package/src/zod/FrameSignature.ts +10 -7
  123. package/src/zod/Transaction.ts +4 -4
  124. package/src/zod/TransactionRequest.ts +3 -3
  125. package/src/zod/_test/Frame.test.ts +13 -11
  126. package/src/zod/_test/FrameReceipt.test.ts +11 -4
  127. package/src/zod/_test/FrameRequest.test-d.ts +15 -0
  128. package/src/zod/_test/FrameRequest.test.ts +44 -0
  129. package/src/zod/_test/FrameSignature.test.ts +73 -9
  130. package/src/zod/_test/RpcSchema.test.ts +106 -0
  131. package/src/zod/_test/TransactionRequest.test.ts +61 -0
  132. package/src/zod/_test/TxEnvelopeEip8141.test.ts +3 -3
  133. package/src/zod/internal/rpcSchemas/Eth.ts +20 -0
  134. package/src/zod/z.ts +1 -0
@@ -0,0 +1,78 @@
1
+ import * as Frame from './Frame.js'
2
+ import type { Compute, PartialBy } from './internal/types.js'
3
+
4
+ /** A frame request whose omitted gas limits are estimated by the node. */
5
+ export type FrameRequest<bigintType = bigint> = Frame.Frame<bigintType>
6
+
7
+ /** JSON-RPC frame request. Only the execution mode is required. */
8
+ export type Rpc = Compute<
9
+ PartialBy<Frame.Rpc, Exclude<keyof Frame.Rpc, 'mode'>>
10
+ >
11
+
12
+ /**
13
+ * Converts an RPC frame request, preserving omitted gas limits for node estimation.
14
+ *
15
+ * @example
16
+ * ```ts twoslash
17
+ * import { FrameRequest } from 'ox'
18
+ *
19
+ * const frame = FrameRequest.fromRpc({
20
+ * mode: '0x2',
21
+ * stateGas: '0x0'
22
+ * })
23
+ * ```
24
+ *
25
+ * @param frame - The RPC frame request.
26
+ * @returns The decoded request with omitted gas limits preserved.
27
+ */
28
+ export function fromRpc(frame: Rpc): FrameRequest {
29
+ const { executionGas, stateGas, ...rest } = Frame.fromRpc({
30
+ ...frame,
31
+ data: frame.data ?? '0x',
32
+ executionGas: frame.executionGas ?? '0x0',
33
+ flags: frame.flags ?? '0x0',
34
+ stateGas: frame.stateGas ?? '0x0',
35
+ value: frame.value ?? '0x0',
36
+ })
37
+ return {
38
+ ...rest,
39
+ ...(frame.executionGas === undefined ? {} : { executionGas }),
40
+ ...(frame.stateGas === undefined ? {} : { stateGas }),
41
+ }
42
+ }
43
+
44
+ export declare namespace fromRpc {
45
+ type ErrorType = Frame.fromRpc.ErrorType
46
+ }
47
+
48
+ /**
49
+ * Converts a frame request to RPC fields without filling omitted gas limits.
50
+ *
51
+ * Explicit zero limits remain zero. Omitted mode, flags, value, and data use frame defaults.
52
+ *
53
+ * @example
54
+ * ```ts twoslash
55
+ * import { FrameRequest } from 'ox'
56
+ *
57
+ * const frame = FrameRequest.toRpc({
58
+ * mode: 'sender',
59
+ * stateGas: 0n
60
+ * })
61
+ * ```
62
+ *
63
+ * @param frame - The frame request. Gas and value accept hex, bigint, or number values.
64
+ * @returns The RPC request with omitted gas limits preserved.
65
+ */
66
+ export function toRpc(frame: toRpc.Input): Rpc {
67
+ const { executionGas, stateGas, ...rest } = Frame.toRpc(frame)
68
+ return {
69
+ ...rest,
70
+ ...(frame.executionGas === undefined ? {} : { executionGas }),
71
+ ...(frame.stateGas === undefined ? {} : { stateGas }),
72
+ }
73
+ }
74
+
75
+ export declare namespace toRpc {
76
+ type Input = Frame.toRpc.Input
77
+ type ErrorType = Frame.toRpc.ErrorType
78
+ }
@@ -26,19 +26,19 @@ export type Arbitrary = {
26
26
  signer?: undefined
27
27
  }
28
28
 
29
- /** A structured secp256k1 signature entry. */
29
+ /** A secp256k1 signature entry. */
30
30
  export type Secp256k1 = {
31
31
  /** Explicit nonzero digest. Omit or use empty bytes for the transaction signing hash. */
32
32
  payload?: Hex.Hex | undefined
33
33
  /** secp256k1 verification scheme. */
34
34
  scheme: 1 | 'secp256k1'
35
- /** Recovered signature. Omit for an unsigned entry. */
36
- signature?: Signature.Signature | undefined
35
+ /** Recovered signature or `Signature.toHex` bytes. Omit or use `0x` for an unsigned entry. */
36
+ signature?: Hex.Hex | Signature.Signature | undefined
37
37
  /** Signer address. Omit to use the transaction sender. */
38
38
  signer?: Address.Address | undefined
39
39
  }
40
40
 
41
- /** A structured P-256 signature entry. */
41
+ /** A P-256 signature entry. */
42
42
  export type P256 = {
43
43
  /** Explicit nonzero digest. Omit or use empty bytes for the transaction signing hash. */
44
44
  payload?: Hex.Hex | undefined
@@ -50,14 +50,14 @@ export type P256 = {
50
50
  | {
51
51
  /** Uncompressed P-256 public key. */
52
52
  publicKey: PublicKey.PublicKey
53
- /** P-256 signature. */
54
- signature: Signature.Signature<false>
53
+ /** P-256 signature or `Signature.toHex` bytes. */
54
+ signature: Hex.Hex | Signature.Signature<false>
55
55
  }
56
56
  | {
57
57
  /** Public key, if already known. Empty wire signatures do not retain it. */
58
58
  publicKey?: PublicKey.PublicKey | undefined
59
- /** Omit for an unsigned entry. */
60
- signature?: undefined
59
+ /** Omit or use `0x` for an unsigned entry. */
60
+ signature?: '0x' | undefined
61
61
  }
62
62
  )
63
63
 
@@ -67,13 +67,13 @@ export type FrameSignature = Arbitrary | Secp256k1 | P256
67
67
  /** JSON-RPC representation of a frame signature. */
68
68
  export type Rpc = {
69
69
  /** Explicit digest, or empty bytes for the transaction signing hash. */
70
- msg: Hex.Hex
70
+ msg?: Hex.Hex | undefined
71
71
  /** Signature verification scheme. */
72
- scheme: 0 | 1 | 2
72
+ scheme: '0x0' | '0x1' | '0x2'
73
73
  /** Encoded signature bytes. */
74
- signature: Hex.Hex
74
+ signature?: Hex.Hex | undefined
75
75
  /** Signer address; absent for the transaction sender. */
76
- signer?: Address.Address | null | undefined
76
+ signer?: Address.Address | '0x' | undefined
77
77
  }
78
78
 
79
79
  /** RLP-ready signature entry. The payload occupies the specification's `msg` field. */
@@ -164,24 +164,34 @@ export function assert(
164
164
  throw new InvalidError('Public key coordinates must fit in 32 bytes.')
165
165
  }
166
166
  }
167
- if (entry.signature !== undefined && entry.publicKey === undefined)
167
+ if (
168
+ entry.signature !== undefined &&
169
+ entry.signature !== '0x' &&
170
+ entry.publicKey === undefined
171
+ )
168
172
  throw new InvalidError('P-256 signatures require a public key.')
169
173
  }
170
- if (entry.signature === undefined) {
174
+ if (entry.signature === undefined || entry.signature === '0x') {
171
175
  if (options.signed) throw new InvalidError('Signature is required.')
172
176
  return
173
177
  }
174
- Hex.assert(entry.signature.r, { strict: true })
175
- Hex.assert(entry.signature.s, { strict: true })
178
+ if (typeof entry.signature === 'string')
179
+ Hex.assert(entry.signature, { strict: true })
180
+ const signature =
181
+ typeof entry.signature === 'string'
182
+ ? Signature.fromHex(entry.signature)
183
+ : entry.signature
184
+ Hex.assert(signature.r, { strict: true })
185
+ Hex.assert(signature.s, { strict: true })
176
186
  if (
177
- (scheme === 1 || entry.signature.yParity !== undefined) &&
178
- entry.signature.yParity !== 0 &&
179
- entry.signature.yParity !== 1
187
+ (scheme === 1 || signature.yParity !== undefined) &&
188
+ signature.yParity !== 0 &&
189
+ signature.yParity !== 1
180
190
  )
181
191
  throw new InvalidError('Signature parity must be 0 or 1.')
182
- Signature.assert(entry.signature, { recovered: scheme === 1 })
183
- const r = Hex.toBigInt(entry.signature.r)
184
- const s = Hex.toBigInt(entry.signature.s)
192
+ Signature.assert(signature, { recovered: scheme === 1 })
193
+ const r = Hex.toBigInt(signature.r)
194
+ const s = Hex.toBigInt(signature.s)
185
195
  const order = scheme === 1 ? secp256k1N : p256N
186
196
  if (
187
197
  r === 0n ||
@@ -210,13 +220,15 @@ export declare namespace assert {
210
220
  | Hex.toBigInt.ErrorType
211
221
  | PublicKey.assert.ErrorType
212
222
  | Signature.assert.ErrorType
223
+ | Signature.fromHex.ErrorType
213
224
  | Errors.GlobalErrorType
214
225
  }
215
226
 
216
227
  /**
217
228
  * Coerces a value into a {@link ox#FrameSignature.FrameSignature}.
218
229
  *
219
- * Accepts arbitrary signature bytes or a structured signature entry. Omitted
230
+ * Accepts arbitrary signature bytes or a signature entry. Protocol signatures accept
231
+ * structured objects or `Signature.toHex` bytes. P-256 entries still require a public key. Omitted
220
232
  * `scheme` and `payload` default to `'arbitrary'` and `'0x'`, respectively.
221
233
  * An empty payload selects the canonical transaction signing hash; an explicit
222
234
  * payload must be a nonzero 32-byte digest.
@@ -340,7 +352,7 @@ export declare namespace from {
340
352
  *
341
353
  * const entry = FrameSignature.fromRpc({
342
354
  * msg: '0x',
343
- * scheme: 0,
355
+ * scheme: '0x0',
344
356
  * signature: '0xdeadbeef'
345
357
  * })
346
358
  * ```
@@ -350,15 +362,20 @@ export declare namespace from {
350
362
  */
351
363
  export function fromRpc(entry: Rpc): FrameSignature {
352
364
  return fromTuple([
353
- entry.scheme === 0 ? '0x' : Hex.fromNumber(entry.scheme, { size: 1 }),
365
+ entry.scheme === '0x0'
366
+ ? '0x'
367
+ : Hex.fromNumber(Hex.toNumber(entry.scheme), { size: 1 }),
354
368
  entry.signer ?? '0x',
355
- entry.msg,
356
- entry.signature,
369
+ entry.msg ?? '0x',
370
+ entry.signature ?? '0x',
357
371
  ])
358
372
  }
359
373
 
360
374
  export declare namespace fromRpc {
361
- type ErrorType = fromTuple.ErrorType | Hex.fromNumber.ErrorType
375
+ type ErrorType =
376
+ | fromTuple.ErrorType
377
+ | Hex.fromNumber.ErrorType
378
+ | Hex.toNumber.ErrorType
362
379
  }
363
380
 
364
381
  /**
@@ -381,8 +398,10 @@ export function toRpc(entry: FrameSignature): Rpc {
381
398
  const [scheme, signer, msg, signature] = toTuple(entry)
382
399
  return {
383
400
  msg,
384
- scheme: (scheme === '0x' ? 0 : Hex.toNumber(scheme)) as Rpc['scheme'],
385
- signature,
401
+ scheme: (scheme === '0x'
402
+ ? '0x0'
403
+ : Hex.fromNumber(Hex.toNumber(scheme))) as Rpc['scheme'],
404
+ ...(signature === '0x' && scheme !== '0x' ? {} : { signature }),
386
405
  ...(signer === '0x' ? {} : { signer }),
387
406
  }
388
407
  }
@@ -509,13 +528,24 @@ export function toTuple(entry: FrameSignature): Tuple {
509
528
  return entry.signature
510
529
  case 1:
511
530
  case 'secp256k1':
512
- return entry.signature === undefined
531
+ return entry.signature === undefined || entry.signature === '0x'
513
532
  ? '0x'
514
- : Hex.fromBytes(Signature.toRecoveredBytes(entry.signature))
533
+ : Hex.fromBytes(
534
+ Signature.toRecoveredBytes(
535
+ typeof entry.signature === 'string'
536
+ ? Signature.fromHex(entry.signature)
537
+ : entry.signature,
538
+ ),
539
+ )
515
540
  case 2:
516
541
  case 'p256': {
517
- if (entry.signature === undefined) return '0x'
518
- const { publicKey, signature } = entry
542
+ if (entry.signature === undefined || entry.signature === '0x')
543
+ return '0x'
544
+ const publicKey = entry.publicKey!
545
+ const signature =
546
+ typeof entry.signature === 'string'
547
+ ? Signature.fromHex(entry.signature)
548
+ : entry.signature
519
549
  const s = Hex.toBigInt(signature.s)
520
550
  return Hex.concat(
521
551
  Hex.fromNumber(Hex.toBigInt(signature.r), { size: 32 }),
package/src/core/Siwe.ts CHANGED
@@ -21,7 +21,7 @@ export const prefixRegex =
21
21
 
22
22
  // https://regexr.com/80gf9
23
23
  export const suffixRegex =
24
- /(?:URI: (?<uri>.+))\n(?:Version: (?<version>.+))\n(?:Chain ID: (?<chainId>\d+))\n(?:Nonce: (?<nonce>[a-zA-Z0-9]+))\n(?:Issued At: (?<issuedAt>.+))(?:\nExpiration Time: (?<expirationTime>.+))?(?:\nNot Before: (?<notBefore>.+))?(?:\nRequest ID: (?<requestId>.+))?/
24
+ /(?:URI: (?<uri>.+))\n(?:Version: (?<version>.+))\n(?:Chain ID: (?<chainId>\d+))\n(?:Nonce: (?<nonce>[a-zA-Z0-9]+))\n(?:Issued At: (?<issuedAt>.+))(?:\nExpiration Time: (?<expirationTime>.+))?(?:\nNot Before: (?<notBefore>.+))?(?:\nRequest ID: (?<requestId>.*))?(?:\nResources:(?<resources>(?:\n- .+)*))?/
25
25
 
26
26
  const siweDateTimeRegex =
27
27
  /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])[Tt]([01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:[Zz]|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/
@@ -421,18 +421,26 @@ export function parseMessage(message: string): ExactPartial<Message> {
421
421
  scheme?: string
422
422
  statement?: string
423
423
  }
424
- const { chainId, expirationTime, issuedAt, notBefore, requestId, ...suffix } =
425
- (message.match(suffixRegex)?.groups ?? {}) as {
426
- chainId: string
427
- expirationTime?: string
428
- issuedAt?: string
429
- nonce: string
430
- notBefore?: string
431
- requestId?: string
432
- uri: string
433
- version: '1'
434
- }
435
- const resources = message.split('Resources:')[1]?.split('\n- ').slice(1)
424
+ const {
425
+ chainId,
426
+ expirationTime,
427
+ issuedAt,
428
+ notBefore,
429
+ requestId,
430
+ resources: resources_,
431
+ ...suffix
432
+ } = (message.match(suffixRegex)?.groups ?? {}) as {
433
+ chainId: string
434
+ expirationTime?: string
435
+ issuedAt?: string
436
+ nonce: string
437
+ notBefore?: string
438
+ requestId?: string
439
+ resources?: string
440
+ uri: string
441
+ version: '1'
442
+ }
443
+ const resources = resources_?.split('\n- ').slice(1)
436
444
  return {
437
445
  ...prefix,
438
446
  ...suffix,
@@ -6,7 +6,12 @@ import * as Frame from './Frame.js'
6
6
  import * as FrameSignature from './FrameSignature.js'
7
7
  import * as Hex from './Hex.js'
8
8
  import * as Quantity from './internal/quantity.js'
9
- import type { Compute, OneOf, UnionCompute } from './internal/types.js'
9
+ import type {
10
+ Compute,
11
+ ExactPartial,
12
+ OneOf,
13
+ UnionCompute,
14
+ } from './internal/types.js'
10
15
  import * as Signature from './Signature.js'
11
16
 
12
17
  /**
@@ -197,29 +202,35 @@ export type Eip8141<
197
202
  > = Compute<
198
203
  Omit<
199
204
  Base<type, pending, bigintType, numberType>,
200
- 'chainId' | 'r' | 's' | 'v' | 'yParity'
201
- > & {
202
- /** Versioned blob hashes. */
203
- blobVersionedHashes: readonly Hex.Hex[]
204
- /** Chain ID, retaining bigint precision when needed. */
205
- chainId: numberType | bigintType
206
- /** Frames in execution order. */
207
- frames: readonly ([bigintType] extends [Hex.Hex]
208
- ? Frame.Rpc
209
- : Frame.Frame<bigintType>)[]
210
- /** Effective gas price. */
211
- gasPrice?: bigintType | undefined
212
- /** Maximum fee per blob gas. */
213
- maxFeePerBlobGas: bigintType
214
- /** Maximum fee per gas. */
215
- maxFeePerGas: bigintType
216
- /** Maximum priority fee per gas. */
217
- maxPriorityFeePerGas: bigintType
218
- /** Frame signature entries. */
219
- signatures: readonly ([bigintType] extends [Hex.Hex]
220
- ? FrameSignature.Rpc
221
- : FrameSignature.FrameSignature)[]
222
- }
205
+ 'chainId' | 'gas' | 'input' | 'to' | 'value' | 'r' | 's' | 'v' | 'yParity'
206
+ > &
207
+ ExactPartial<
208
+ Pick<
209
+ Base<type, pending, bigintType, numberType>,
210
+ 'gas' | 'input' | 'to' | 'value'
211
+ >
212
+ > & {
213
+ /** Versioned blob hashes. */
214
+ blobVersionedHashes: readonly Hex.Hex[]
215
+ /** Chain ID, retaining bigint precision when needed. */
216
+ chainId: numberType | bigintType
217
+ /** Frames in execution order. */
218
+ frames: readonly ([bigintType] extends [Hex.Hex]
219
+ ? Frame.Rpc
220
+ : Frame.Frame<bigintType>)[]
221
+ /** Effective gas price. */
222
+ gasPrice?: bigintType | undefined
223
+ /** Maximum fee per blob gas. */
224
+ maxFeePerBlobGas: bigintType
225
+ /** Maximum fee per gas. */
226
+ maxFeePerGas: bigintType
227
+ /** Maximum priority fee per gas. */
228
+ maxPriorityFeePerGas: bigintType
229
+ /** Frame signature entries. */
230
+ signatures: readonly ([bigintType] extends [Hex.Hex]
231
+ ? FrameSignature.Rpc
232
+ : FrameSignature.FrameSignature)[]
233
+ }
223
234
  >
224
235
 
225
236
  /** An EIP-8141 RPC transaction. */
@@ -3,7 +3,7 @@ import type * as Address from './Address.js'
3
3
  import * as Authorization from './Authorization.js'
4
4
  import * as Blobs from './Blobs.js'
5
5
  import * as Errors from './Errors.js'
6
- import * as Frame from './Frame.js'
6
+ import * as FrameRequest from './FrameRequest.js'
7
7
  import * as FrameSignature from './FrameSignature.js'
8
8
  import * as Hex from './Hex.js'
9
9
  import * as Quantity from './internal/quantity.js'
@@ -19,7 +19,9 @@ export type TransactionRequest<
19
19
  bigintType = bigint,
20
20
  numberType = number,
21
21
  type extends string = string,
22
- frame = [bigintType] extends [Hex.Hex] ? Frame.Rpc : Frame.Frame<bigintType>,
22
+ frame = [bigintType] extends [Hex.Hex]
23
+ ? FrameRequest.Rpc
24
+ : FrameRequest.FrameRequest<bigintType>,
23
25
  signature = [bigintType] extends [Hex.Hex]
24
26
  ? FrameSignature.Rpc
25
27
  : FrameSignature.FrameSignature,
@@ -79,7 +81,7 @@ export type Rpc = TransactionRequest<
79
81
  Hex.Hex,
80
82
  Hex.Hex,
81
83
  string,
82
- Frame.Rpc,
84
+ FrameRequest.Rpc,
83
85
  FrameSignature.Rpc
84
86
  >
85
87
 
@@ -109,7 +111,7 @@ export function fromRpc(request: Rpc): TransactionRequest {
109
111
  if (typeof request.chainId !== 'undefined')
110
112
  request_.chainId = Hex.toNumber(request.chainId)
111
113
  if (request.frames !== undefined)
112
- request_.frames = request.frames.map(Frame.fromRpc)
114
+ request_.frames = request.frames.map(FrameRequest.fromRpc)
113
115
  if (request.signatures !== undefined)
114
116
  request_.signatures = request.signatures.map(FrameSignature.fromRpc)
115
117
  if (typeof request.gas !== 'undefined')
@@ -141,7 +143,7 @@ export function fromRpc(request: Rpc): TransactionRequest {
141
143
  export declare namespace fromRpc {
142
144
  export type ErrorType =
143
145
  | Authorization.fromRpcList.ErrorType
144
- | Frame.fromRpc.ErrorType
146
+ | FrameRequest.fromRpc.ErrorType
145
147
  | FrameSignature.fromRpc.ErrorType
146
148
  | Hex.toNumber.ErrorType
147
149
  | Hex.toBigInt.ErrorType
@@ -210,7 +212,7 @@ export function toRpc(request: toRpc.Input): Rpc {
210
212
  request_rpc.input = request.input
211
213
  }
212
214
  if (request.frames !== undefined)
213
- request_rpc.frames = request.frames.map(Frame.toRpc)
215
+ request_rpc.frames = request.frames.map(FrameRequest.toRpc)
214
216
  if (request.signatures !== undefined)
215
217
  request_rpc.signatures = request.signatures.map(FrameSignature.toRpc)
216
218
  if (typeof request.from !== 'undefined') request_rpc.from = request.from
@@ -258,7 +260,7 @@ export declare namespace toRpc {
258
260
 
259
261
  export type ErrorType =
260
262
  | Authorization.toRpcList.ErrorType
261
- | Frame.toRpc.ErrorType
263
+ | FrameRequest.toRpc.ErrorType
262
264
  | FrameSignature.toRpc.ErrorType
263
265
  | Hex.fromNumber.ErrorType
264
266
  | Errors.GlobalErrorType
@@ -242,7 +242,9 @@ export declare namespace deserialize {
242
242
  *
243
243
  * const envelope = TransactionEnvelope.from({
244
244
  * chainId: 1,
245
- * frames: [Frame.from({ gas: 50_000n, mode: 'sender' })],
245
+ * frames: [
246
+ * Frame.from({ executionGas: 50_000n, mode: 'sender' })
247
+ * ],
246
248
  * sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
247
249
  * })
248
250
  * ```
@@ -779,6 +781,12 @@ export function toTransactionRequest(
779
781
  ...rest,
780
782
  ...(sidecars ? { blobs: sidecars.blobs } : {}),
781
783
  chainId: Hex.toNumber(Hex.fromNumber(rest.chainId)),
784
+ // Envelopes commit to zero defaults; request omission would trigger estimation.
785
+ frames: rest.frames.map((frame) => ({
786
+ ...frame,
787
+ executionGas: frame.executionGas ?? 0n,
788
+ stateGas: frame.stateGas ?? 0n,
789
+ })),
782
790
  from: sender,
783
791
  }
784
792
  }
@@ -90,7 +90,7 @@ export type Type = typeof type
90
90
  *
91
91
  * TxEnvelopeEip8141.assert({
92
92
  * chainId: 1,
93
- * frames: [{ gas: 50_000n, mode: 'verify' }],
93
+ * frames: [{ executionGas: 50_000n, mode: 'verify' }],
94
94
  * sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
95
95
  * })
96
96
  * ```
@@ -146,7 +146,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
146
146
  }
147
147
  if (blobVersionedHashes.length === 0 && maxFeePerBlobGas !== 0n)
148
148
  throw new InvalidError('maxFeePerBlobGas must be zero without blobs.')
149
- let gas = 0n
149
+ let executionGas = 0n
150
150
  let stateGas = 0n
151
151
  let previousBatch = false
152
152
  let expiry = false
@@ -193,7 +193,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
193
193
  throw new InvalidError('Invalid or duplicate expiry verifier frame.')
194
194
  expiry = true
195
195
  }
196
- gas += frame.gas ?? 0n
196
+ executionGas += frame.executionGas ?? 0n
197
197
  stateGas += frame.stateGas ?? 0n
198
198
  count(frame.data ?? '0x')
199
199
  if (
@@ -210,10 +210,10 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
210
210
  count(payload)
211
211
  count(signature)
212
212
  }
213
- if (gas + stateGas >= 2n ** 64n)
213
+ if (executionGas + stateGas >= 2n ** 64n)
214
214
  throw new InvalidError('Combined frame gas must be less than 2^64.')
215
215
  if (
216
- intrinsic + tokens * 4n + gas > 16_777_216n ||
216
+ intrinsic + tokens * 4n + executionGas > 16_777_216n ||
217
217
  intrinsic + size * 64n > 16_777_216n
218
218
  )
219
219
  throw new InvalidError('Transaction execution gas exceeds 16777216.')
@@ -337,8 +337,8 @@ export declare namespace deserialize {
337
337
  * chainId: 1,
338
338
  * frames: [
339
339
  * {
340
+ * executionGas: 50_000n,
340
341
  * flags: 'approveExecutionAndPayment',
341
- * gas: 50_000n,
342
342
  * mode: 'verify'
343
343
  * }
344
344
  * ],
@@ -503,8 +503,8 @@ export declare namespace toRpc {
503
503
  * chainId: 1,
504
504
  * frames: [
505
505
  * {
506
+ * executionGas: 50_000n,
506
507
  * flags: 'approveExecutionAndPayment',
507
- * gas: 50_000n,
508
508
  * mode: 'verify'
509
509
  * }
510
510
  * ],
@@ -589,7 +589,7 @@ export declare namespace hash {
589
589
  *
590
590
  * const envelope = TxEnvelopeEip8141.from({
591
591
  * chainId: 1,
592
- * frames: [{ gas: 50_000n, mode: 'sender' }],
592
+ * frames: [{ executionGas: 50_000n, mode: 'sender' }],
593
593
  * sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
594
594
  * })
595
595
  * const serialized = TxEnvelopeEip8141.serialize(envelope)
@@ -136,6 +136,8 @@ describe('decode', () => {
136
136
  params: [hash],
137
137
  }))!
138
138
 
139
+ if (input === undefined) throw new Error('Missing transaction input')
140
+
139
141
  expect(
140
142
  AbiConstructor.decode(abiConstructor, {
141
143
  bytecode: Constructor.bytecode.object,
@@ -4,14 +4,15 @@ import { expectTypeOf, test } from 'vite-plus/test'
4
4
  test('from preserves literals', () => {
5
5
  const frame = Frame.from({
6
6
  data: '0x',
7
+ executionGas: 50_000n,
7
8
  flags: 3,
8
- gas: 50_000n,
9
9
  mode: 1,
10
10
  stateGas: 0n,
11
11
  value: 0n,
12
12
  })
13
13
  expectTypeOf(frame.mode).toEqualTypeOf<1>()
14
- expectTypeOf(frame.gas).toEqualTypeOf<50_000n>()
14
+ expectTypeOf(frame.executionGas).toEqualTypeOf<50_000n>()
15
+ expectTypeOf(frame.stateGas).toEqualTypeOf<0n>()
15
16
  expectTypeOf(Frame.toTuple(frame)).toEqualTypeOf<Frame.Tuple>()
16
17
  })
17
18
 
@@ -31,8 +32,8 @@ test('tuple accepts readonly input', () => {
31
32
  test('rejects unsupported modes and unsafe numeric budgets', () => {
32
33
  Frame.from({
33
34
  data: '0x',
35
+ executionGas: 0n,
34
36
  flags: 0,
35
- gas: 0n,
36
37
  // @ts-expect-error Unknown mode names are not supported.
37
38
  mode: 'unknown',
38
39
  stateGas: 0n,
@@ -40,9 +41,9 @@ test('rejects unsupported modes and unsafe numeric budgets', () => {
40
41
  })
41
42
  Frame.from({
42
43
  data: '0x',
43
- flags: 0,
44
44
  // @ts-expect-error Gas budgets use bigint.
45
- gas: 1,
45
+ executionGas: 1,
46
+ flags: 0,
46
47
  mode: 1,
47
48
  stateGas: 0n,
48
49
  value: 0n,
@@ -52,8 +53,8 @@ test('rejects unsupported modes and unsafe numeric budgets', () => {
52
53
  test('flags accept numbers and a strict named union', () => {
53
54
  const input = {
54
55
  data: '0x',
56
+ executionGas: 0n,
55
57
  flags: 'approvePayment',
56
- gas: 0n,
57
58
  mode: 1,
58
59
  stateGas: 0n,
59
60
  value: 0n,
@@ -74,8 +75,8 @@ test('flags accept numbers and a strict named union', () => {
74
75
  test('mode accepts numbers and a strict named union', () => {
75
76
  const frame = Frame.from({
76
77
  data: '0x',
78
+ executionGas: 0n,
77
79
  flags: 0,
78
- gas: 0n,
79
80
  mode: 'sender',
80
81
  stateGas: 0n,
81
82
  value: 1n,
@@ -95,6 +96,14 @@ test('allows omitted zero fields without widening supplied literals', () => {
95
96
  ).toEqualTypeOf<Frame.Tuple>()
96
97
  })
97
98
 
99
+ test('execution gas is named explicitly', () => {
100
+ const invalid: Frame.Frame = {
101
+ // @ts-expect-error The execution budget is named executionGas.
102
+ gas: 50_000n,
103
+ }
104
+ void invalid
105
+ })
106
+
98
107
  test('destination is named to', () => {
99
108
  const frame = Frame.from({ to: '0x1111111111111111111111111111111111111111' })
100
109
  expectTypeOf(